sark-gen 0.11.0

Sark proc-macro generators
Documentation
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()),
        })
    }
}