use std::marker::PhantomData;
use super::{Expansion, Reader, Shape};
use crate::binary::{Decoder, Writer};
use crate::frame::{Packer, Unpacker};
use crate::model::borrowed::ValueRef;
use crate::model::value::{Ref, Value};
use crate::with::With;
#[derive(Debug)]
pub struct Expand<W>(PhantomData<W>);
fn reference_of(v: &ValueRef<'_>) -> Option<Ref> {
match v {
ValueRef::Str(s) if s.starts_with(crate::names::TYPED) => match crate::typed::classify(s) {
Ok(crate::typed::Spelled::Ref(r)) => Some(r),
_ => None,
},
other => other.to_ref(),
}
}
impl<F, W: With<F>> With<F> for Expand<W> {
fn shape() -> Shape {
W::shape()
}
fn read(v: &ValueRef<'_>, cx: &mut Reader<'_>) -> Option<F> {
let reference = reference_of(v).filter(|_| cx.resolves());
let Some(r) = reference else {
return W::read(v, cx);
};
match cx.expand_ref(&r) {
Expansion::Kept => W::read(v, cx),
Expansion::Failed => {
cx.note_ref(r);
None
}
Expansion::Value(value) => {
cx.note_ref(r);
cx.expanded(|cx| {
let arena = bumpalo::Bump::new();
W::read(&value.borrow(&arena), cx)
})
}
}
}
fn write(f: &F) -> Value {
W::write(f)
}
fn absent() -> Option<F> {
W::absent()
}
fn skip(f: &F) -> bool {
W::skip(f)
}
fn write_text(f: &F, w: &mut crate::text::Writer) {
W::write_text(f, w);
}
fn encode(f: &F, w: &mut Writer) {
W::encode(f, w);
}
fn decode(d: &mut Decoder<'_>) -> Option<F> {
W::decode(d)
}
fn pack(f: &F, p: &mut Packer) {
W::pack(f, p);
}
fn unpack(u: &mut Unpacker<'_>) -> Option<F> {
W::unpack(u)
}
}