use anyhow::Result;
use crate::fst_properties::mutable_properties::concat_properties;
use crate::fst_properties::FstProperties;
use crate::fst_traits::{AllocableFst, ExpandedFst, MutableFst};
use crate::semirings::Semiring;
use crate::{StateId, Tr, Trs, EPS_LABEL};
pub fn concat<W, F1, F2>(fst_1: &mut F1, fst_2: &F2) -> Result<()>
where
W: Semiring,
F1: ExpandedFst<W> + MutableFst<W> + AllocableFst<W>,
F2: ExpandedFst<W>,
{
let props1 = fst_1.properties();
let props2 = fst_2.properties();
let start1 = fst_1.start();
if start1.is_none() {
return Ok(());
}
let numstates1 = fst_1.num_states();
fst_1.reserve_states(fst_2.num_states());
for s2 in fst_2.states_iter() {
let s1 = fst_1.add_state();
if let Some(final_weight) = unsafe { fst_2.final_weight_unchecked(s2) } {
unsafe { fst_1.set_final_unchecked(s1, final_weight) };
}
unsafe { fst_1.reserve_trs_unchecked(s1, fst_2.num_trs_unchecked(s2)) };
for tr in unsafe { fst_2.get_trs_unchecked(s2).trs() } {
let mut new_tr = tr.clone();
new_tr.nextstate += numstates1 as StateId;
unsafe { fst_1.add_tr_unchecked(s1, new_tr) };
}
}
let start2 = fst_2.start();
for s1 in 0..(numstates1 as StateId) {
if let Some(weight) = unsafe { fst_1.final_weight_unchecked(s1) } {
if let Some(_start2) = start2 {
unsafe {
fst_1.add_tr_unchecked(
s1,
Tr::new(
EPS_LABEL,
EPS_LABEL,
weight,
_start2 + (numstates1 as StateId),
),
)
};
}
unsafe { fst_1.delete_final_weight_unchecked(s1) };
}
}
if start2.is_some() {
fst_1.set_properties_with_mask(
concat_properties(props1, props2, false),
FstProperties::all_properties(),
);
}
Ok(())
}