use proc_macro2::TokenStream;
use quote::quote;
use syn::{Result, Type};
use super::field::FieldMode;
use super::scalar::{Classified, Scalar};
use crate::util::TypeExt;
pub(super) struct Decoder<'a> {
ty: &'a Type,
mode: FieldMode,
}
impl<'a> Decoder<'a> {
pub(super) fn new(ty: &'a Type, mode: FieldMode) -> Self {
Self { ty, mode }
}
pub(super) fn expr(&self) -> Result<TokenStream> {
if self.mode.seq {
let elem = self.ty.vec_inner().ok_or_else(|| {
syn::Error::new_spanned(self.ty, "#[field(seq)] requires a Vec<T> field")
})?;
let push = if self.mode.nested {
quote!(__v.push(
<#elem as sark::json::JsonDecode>::decode_json_borrowed(&__raw[__vs..__idx])?
);)
} else {
quote!(__v.push(sark::json::Parse::frame(&__bytes, &mut __idx)?);)
};
let capture = if self.mode.nested {
quote! {
let __vs = __idx;
sark::json::Scan::skip_value(__raw, &mut __idx)?;
}
} else {
quote!()
};
return Ok(quote! {{
sark::json::Scan::ws(__raw, &mut __idx);
sark::json::Scan::expect_byte(__raw, &mut __idx, b'[')?;
let mut __v = Vec::new();
sark::json::Scan::ws(__raw, &mut __idx);
if !sark::json::Scan::eat_byte(__raw, &mut __idx, b']') {
loop {
sark::json::Scan::ws(__raw, &mut __idx);
#capture
#push
sark::json::Scan::ws(__raw, &mut __idx);
if sark::json::Scan::eat_byte(__raw, &mut __idx, b',') {
continue;
}
sark::json::Scan::expect_byte(__raw, &mut __idx, b']')?;
break;
}
}
__v
}});
}
if self.mode.nested {
let ty = self.ty;
return Ok(quote! {{
sark::json::Scan::ws(__raw, &mut __idx);
let __vs = __idx;
sark::json::Scan::skip_value(__raw, &mut __idx)?;
<#ty as sark::json::JsonDecode>::decode_json_borrowed(&__raw[__vs..__idx])?
}});
}
let class = Classified::of(self.ty)?;
let decode = match class.scalar {
Scalar::U64 => quote!(sark::json::Parse::u64(__raw, &mut __idx)?),
Scalar::I64 | Scalar::F64 | Scalar::String | Scalar::Shared => {
return Err(syn::Error::new_spanned(
self.ty,
"this JSON field type requires `#[sark_gen::json(encode)]`",
));
}
Scalar::Bool => quote!(sark::json::Parse::bool(__raw, &mut __idx)?),
Scalar::Retained => {
if self.mode.raw {
quote!(sark::json::Parse::frame_raw(&__bytes, &mut __idx)?)
} else if self.mode.plain {
quote!(sark::json::Parse::frame_plain(&__bytes, &mut __idx)?)
} else {
quote!(sark::json::Parse::frame(&__bytes, &mut __idx)?)
}
}
Scalar::InlineToken => {
if self.mode.plain && !self.mode.raw {
quote!(sark::json::Parse::inline_plain(__raw, &mut __idx)?)
} else {
quote!(sark::json::Parse::inline_raw(__raw, &mut __idx)?)
}
}
};
Ok(if class.optional {
quote!({
if sark::json::Scan::eat_null(__raw, &mut __idx) {
None
} else {
Some(#decode)
}
})
} else {
decode
})
}
pub(super) fn empty(&self) -> Result<TokenStream> {
let class = Classified::of(self.ty)?;
if class.optional {
return Ok(quote!(None));
}
Ok(match class.scalar {
Scalar::U64 => quote!(0u64),
Scalar::I64 | Scalar::F64 | Scalar::String | Scalar::Shared => {
return Err(syn::Error::new_spanned(
self.ty,
"this JSON field type requires `#[sark_gen::json(encode)]`",
));
}
Scalar::Bool => quote!(false),
Scalar::Retained => quote!(sark::json::Parse::empty_frame()),
Scalar::InlineToken => quote!(sark::json::InlineToken::new()),
})
}
}