use super::Data;
pub fn assign(from: &Data, target: &Data) {
if let Some(r) = target
.get()
.as_any()
.downcast_ref::<crate::data::reference::Reference>()
{
*r.write() = from.clone();
} else if let (Some((from, from_ref)), Some(target)) = (
from.get()
.as_any()
.downcast_ref::<crate::data::tuple::Tuple>()
.map(|v| (v.clone(), false))
.or_else(|| {
from.get()
.as_any()
.downcast_ref::<crate::data::reference::Reference>()
.and_then(|r| {
r.write()
.get_mut()
.as_any()
.downcast_ref::<crate::data::tuple::Tuple>()
.map(|v| (v.clone_refs(), true))
})
}),
target
.get()
.as_any()
.downcast_ref::<crate::data::tuple::Tuple>(),
) {
for (from, target) in from.0.into_iter().zip(target.0.iter()) {
if from_ref {
assign(&Data::new(from), &*target.read());
} else {
assign(&*from.read(), &*target.read());
}
}
} else if let (Some((from, from_ref)), Some(target)) = (
from.get()
.as_any()
.downcast_ref::<crate::data::object::Object>()
.map(|v| (v.clone(), false))
.or_else(|| {
from.get()
.as_any()
.downcast_ref::<crate::data::reference::Reference>()
.and_then(|r| {
r.write()
.get_mut()
.as_any()
.downcast_ref::<crate::data::object::Object>()
.map(|v| (v.clone_refs(), true))
})
}),
target
.get()
.as_any()
.downcast_ref::<crate::data::object::Object>(),
) {
for (field, target) in target.iter() {
if from_ref {
let from = from
.get_mut(*field)
.expect("type-checks should guarantee that from has every field of target");
assign(&Data::new(from.clone_ref()), &*target.read());
} else {
let from = from
.get(*field)
.expect("type-checks should guarantee that from has every field of target");
assign(&from, &*target.read());
}
}
} else {
unreachable!("invalid assignment")
}
}