Preserves value merge in Rust

This commit is contained in:
Tony Garnock-Jones 2021-09-11 02:49:17 +02:00
parent eda9979041
commit 5f2a3e3eb8
2 changed files with 64 additions and 0 deletions

View File

@ -0,0 +1,62 @@
use super::Embeddable;
use super::Map;
use super::NestedValue;
use super::Record;
use super::Value;
pub fn merge_seqs<N: NestedValue<D>, D: Embeddable>(mut a: Vec<N>, mut b: Vec<N>) -> Option<Vec<N>> {
if a.len() > b.len() {
std::mem::swap(&mut a, &mut b);
}
let mut r = vec![];
let mut bi = b.into_iter();
for av in a.into_iter() {
r.push(merge2(av, bi.next().unwrap())?);
}
r.extend(bi);
Some(r)
}
pub fn merge2<N: NestedValue<D>, D: Embeddable>(v: N, w: N) -> Option<N> {
let (mut v_anns, v_val) = v.pieces();
let (w_anns, w_val) = w.pieces();
v_anns.modify(|anns| anns.extend(w_anns.to_vec().into_iter()));
if v_val == w_val {
Some(N::wrap(v_anns, v_val))
} else {
let maybe_merged = match v_val {
Value::Record(rv) =>
Some(Value::Record(Record(merge_seqs(rv.0, w_val.into_record()?.0)?))),
Value::Sequence(vs) =>
Some(Value::Sequence(merge_seqs(vs, w_val.into_sequence()?)?)),
Value::Set(_vs) =>
None, // unsure how to merge sets
Value::Dictionary(vs) => {
let mut ws = w_val.into_dictionary()?;
let mut rs = Map::new();
for (k, vv) in vs.into_iter() {
match ws.remove(&k) {
Some(wv) => { rs.insert(k, merge2(vv, wv)?); }
None => { rs.insert(k, vv); }
}
}
rs.extend(ws.into_iter());
Some(Value::Dictionary(rs))
}
_ => None,
};
maybe_merged.map(|vw| N::wrap(v_anns, vw))
}
}
pub fn merge<N: NestedValue<D>, D: Embeddable, I: IntoIterator<Item = N>>(vs: I) -> Option<N> {
let mut vs = vs.into_iter();
let mut v = vs.next().expect("at least one value in merge()");
for w in vs {
match merge2(v, w) {
Some(merged) => v = merged,
None => return None,
}
}
Some(v)
}

View File

@ -10,6 +10,7 @@ pub mod signed_integer;
pub mod suspendable;
pub mod text;
pub mod writer;
pub mod merge;
pub use de::Deserializer;
pub use de::from_value;
@ -19,6 +20,7 @@ pub use domain::DomainParse;
pub use domain::IOValueDomainCodec;
pub use domain::NoEmbeddedDomainCodec;
pub use domain::ViaCodec;
pub use merge::merge;
pub use packed::PackedReader;
pub use packed::PackedWriter;
pub use reader::BinarySource;