///|
fn append_segment(out : Array[MessageSegment], item : MessageSegment) -> Unit {
if !out.is_empty() {
let i = out.length() - 1
match (out[i], item) {
(Text(a, e), Text(b, f)) if e == f => {
out[i] = Text(a + b, e)
return
}
(Data(a), Data(b)) => {
out[i] = Data(a + b)
return
}
_ => ()
}
}
out.push(item)
}
///|
/// Split a segmented message, preserving text character boundaries and ECI state.
pub fn encode_append_message(
segments : Array[MessageSegment],
file_id1 : Int,
file_id2 : Int,
options? : MessageOptions = MessageOptions::new(),
) -> Array[Symbol] raise EncodeError {
if options.append is Some(_) ||
!valid_append({ index: 1, count: 2, file_id1, file_id2, }) {
raise InvalidOption("invalid automatic append header")
}
let single = Some(encode_message(segments, options~)) catch {
CapacityExceeded => None
e => raise e
}
if single is Some(s) {
return [s]
}
if options.macro_kind != 0 || options.reader_programming {
raise InvalidOption("control message must fit one symbol")
}
let atoms : Array[(MessageSegment, Int)] = []
let mut active = 3
for s in segments {
match s {
Text(t, e) =>
for c in t {
atoms.push((Text(c.to_string(), e), active))
active = e
}
Data(b) =>
for v in b {
atoms.push((Data(Bytes::from_array([v])), active))
}
Eci(e) => {
atoms.push((s, active))
active = e
}
Fnc1 => atoms.push((s, active))
}
}
let parts : Array[Array[MessageSegment]] = []
let mut offset = 0
while offset < atoms.length() {
if parts.length() >= 16 {
raise CapacityExceeded
}
let mut lo = 1
let mut hi = atoms.length() - offset
let mut best : Array[MessageSegment] = []
let mut count = 0
while lo <= hi {
let n = (lo + hi) / 2
let candidate : Array[MessageSegment] = []
if !options.gs1 && offset > 0 {
candidate.push(Eci(atoms[offset].1))
}
for j in offset..<(offset + n) {
append_segment(candidate, atoms[j].0)
}
let fits = try {
ignore(
encode_message(
candidate,
options=MessageOptions::new(
symbol=options.symbol,
gs1=options.gs1,
append=Some({ index: 1, count: 16, file_id1, file_id2, }),
),
),
)
true
} catch {
CapacityExceeded => false
e => raise e
}
if fits {
best = candidate
count = n
lo = n + 1
} else {
hi = n - 1
}
}
if count == 0 {
raise CapacityExceeded
}
parts.push(best)
offset += count
}
let result = []
for i in 0..