ferment-sys 0.2.14

Syntax tree morphing of FFI-compatible stuff
Documentation
use std::fmt::Formatter;
use quote::{quote, ToTokens};
use syn::__private::TokenStream2;
use syn::Pat;
use crate::ast::{CommaPunctuated, Depunctuated};
use crate::presentation::{ArgPresentation, DictionaryName, FFIConversionFromMethod, InterfacesMethodExpr};

#[allow(unused)]
#[derive(Clone, Debug)]
pub enum DictionaryExpr {
    Simple(TokenStream2),
    DictionaryName(DictionaryName),
    Depunctuated(Depunctuated<TokenStream2>),
    TypeDestructuring(TokenStream2, TokenStream2),
    BoxedSelfDestructuring(TokenStream2),
    ObjIntoIter,
    FfiDeref,
    FfiDerefAsRef,
    LetFfiRef,
    LetExpr(TokenStream2, TokenStream2),
    Deref(TokenStream2),
    DerefRef(TokenStream2),
    DerefMutRef(TokenStream2),
    AsRef(TokenStream2),
    AsMutRef(TokenStream2),
    Mapper(TokenStream2, TokenStream2),
    SelfProp(TokenStream2),
    FfiRefProp(TokenStream2),
    AsMut_(TokenStream2),
    IfNotNull(TokenStream2, TokenStream2),
    IfThen(TokenStream2, TokenStream2),
    MapOr(TokenStream2, TokenStream2, TokenStream2),
    Some(TokenStream2),
    NullMut,
    CChar,
    Arc,
    Rc,
    Box,
    Mutex,
    OnceLock,
    RwLock,
    Cell,
    RefCell,
    UnsafeCell,
    AsSlice(TokenStream2),
    ToVec(TokenStream2),
    MapCollect(TokenStream2, TokenStream2),
    Match(TokenStream2),
    MatchFields(TokenStream2, CommaPunctuated<ArgPresentation>),
    #[cfg(feature = "objc")]
    SwitchFields(TokenStream2, Depunctuated<crate::lang::objc::presentable::ArgPresentation>),
    #[cfg(feature = "objc")]
    Case(TokenStream2, TokenStream2),
    MatchResult(TokenStream2, TokenStream2),
    FromRoot(TokenStream2),
    CountRange,
    NewSmth(TokenStream2, TokenStream2),
    LeakBox(TokenStream2),
    MapIntoBox(TokenStream2),
    FromRawBox(TokenStream2),
    TryIntoUnwrap(TokenStream2),
    CallbackCaller(TokenStream2, TokenStream2),
    CallbackDestructor(TokenStream2, TokenStream2),
    CastedFFIConversion(DictionaryName, TokenStream2, TokenStream2, TokenStream2, TokenStream2),
    Clone(TokenStream2),
    FromPtrRead(TokenStream2),
    FromArc(TokenStream2),
    FromRc(TokenStream2),
    SelfAsTrait(TokenStream2, TokenStream2),
    IfElse(TokenStream2, TokenStream2, TokenStream2)
}

impl DictionaryExpr {
    pub fn simple<T: ToTokens>(name: T) -> Self {
        Self::Simple(name.to_token_stream())
    }
    pub fn self_prop<T: ToTokens>(name: T) -> Self {
        Self::SelfProp(name.to_token_stream())
    }
    pub fn self_as_trait<T: ToTokens, U: ToTokens>(ty: T, acc: U) -> Self {
        Self::SelfAsTrait(ty.to_token_stream(), acc.to_token_stream())
    }
    pub fn ffi_ref_prop<T: ToTokens>(name: T) -> Self {
        Self::FfiRefProp(name.to_token_stream())
    }
    pub fn deref<T: ToTokens>(name: T) -> Self {
        Self::Deref(name.to_token_stream())
    }
    pub fn deref_ref<T: ToTokens>(name: T) -> Self {
        Self::DerefRef(name.to_token_stream())
    }
    pub fn self_destruct<T: ToTokens>(name: T) -> Self {
        Self::TypeDestructuring(quote!(Self), name.to_token_stream())
    }
    pub fn type_destruct<T: ToTokens, U: ToTokens>(ty: T, name: U) -> Self {
        Self::TypeDestructuring(ty.to_token_stream(), name.to_token_stream())
    }
    pub fn callback_caller<T: ToTokens, U: ToTokens>(conversion: T, result: U) -> Self {
        Self::CallbackCaller(conversion.to_token_stream(), result.to_token_stream())
    }
    pub fn callback_dtor<T: ToTokens, U: ToTokens>(conversion: T, result: U) -> Self {
        Self::CallbackDestructor(conversion.to_token_stream(), result.to_token_stream())
    }
    
    pub fn casted_ffi_conversion<M: ToTokens, T: ToTokens, U: ToTokens, V: ToTokens>(interface: DictionaryName, method: M, ffi_ty: T, ty: U, field_expr: V) -> Self {
        Self::CastedFFIConversion(interface, method.to_token_stream(), ffi_ty.to_token_stream(), ty.to_token_stream(), field_expr.to_token_stream())
    }
    pub fn casted_ffi_conversion_from<T: ToTokens, U: ToTokens, V: ToTokens>(ffi_ty: T, ty: U, field_expr: V) -> Self {
        Self::CastedFFIConversion(DictionaryName::InterfaceFrom, FFIConversionFromMethod::Mut.to_token_stream(), ffi_ty.to_token_stream(), ty.to_token_stream(), field_expr.to_token_stream())
    }
    pub fn casted_ffi_conversion_from_opt<T: ToTokens, U: ToTokens, V: ToTokens>(ffi_ty: T, ty: U, field_expr: V) -> Self {
        Self::CastedFFIConversion(DictionaryName::InterfaceFrom, FFIConversionFromMethod::Opt.to_token_stream(), ffi_ty.to_token_stream(), ty.to_token_stream(), field_expr.to_token_stream())
    }

    pub fn some<T: ToTokens>(body: T) -> Self {
        Self::Some(body.to_token_stream())
    }
    pub fn from_root<T: ToTokens>(body: T) -> Self {
        Self::FromRoot(body.to_token_stream())
    }
    pub fn from_ptr_read<T: ToTokens>(body: T) -> Self {
        Self::FromPtrRead(body.to_token_stream())
    }
    pub fn from_arc<T: ToTokens>(body: T) -> Self {
        Self::FromArc(body.to_token_stream())
    }
    pub fn from_rc<T: ToTokens>(body: T) -> Self {
        Self::FromRc(body.to_token_stream())
    }

    pub fn mapper<T: ToTokens, U: ToTokens>(item: T, result: U) -> Self {
        Self::Mapper(item.to_token_stream(), result.to_token_stream())
    }
}


impl std::fmt::Display for DictionaryExpr {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        std::fmt::Debug::fmt(self, f)
    }
}
impl ToTokens for DictionaryExpr {
    fn to_tokens(&self, tokens: &mut TokenStream2) {
        match self {
            Self::Simple(simple) =>
                simple.to_tokens(tokens),
            Self::DictionaryName(name) =>
                name.to_tokens(tokens),
            Self::Depunctuated(sequence) =>
                sequence.to_tokens(tokens),
            Self::ObjIntoIter => {
                DictionaryName::Obj.to_tokens(tokens);
                quote!(.into_iter()).to_tokens(tokens)
            },
            Self::FfiDeref => {
                quote!(*).to_tokens(tokens);
                DictionaryName::Ffi.to_tokens(tokens);
            },
            Self::FfiDerefAsRef => {
                quote!(&*).to_tokens(tokens);
                DictionaryName::Ffi.to_tokens(tokens);
            },
            Self::LetExpr(left, right) =>
                quote!(let #left = #right).to_tokens(tokens),
            Self::LetFfiRef =>
                quote!(let ffi_ref = &*ffi;).to_tokens(tokens),
            Self::Deref(expr) => {
                quote!(*).to_tokens(tokens);
                expr.to_tokens(tokens);
            }
            Self::DerefRef(expr) => {
                quote!(&*).to_tokens(tokens);
                expr.to_tokens(tokens)
            }
            Self::DerefMutRef(expr) => {
                quote!(&mut *).to_tokens(tokens);
                expr.to_tokens(tokens)
            }
            Self::AsRef(expr) => {
                quote!(&).to_tokens(tokens);
                expr.to_tokens(tokens);
            }
            Self::AsMutRef(expr) => {
                quote!(&mut).to_tokens(tokens);
                expr.to_tokens(tokens);
            }
            Self::Mapper(context, expr) => {
                quote!(|#context| ).to_tokens(tokens);
                expr.to_tokens(tokens);
            }
            Self::Some(content) =>
                quote!(Some(#content)).to_tokens(tokens),
            Self::FfiRefProp(prop) => {
                quote!(ffi_ref.).to_tokens(tokens);
                prop.to_tokens(tokens);
            },
            Self::SelfProp(prop) => {
                quote!(self.).to_tokens(tokens);
                prop.to_tokens(tokens);
            },
            Self::AsMut_(field_path) => {
                field_path.to_tokens(tokens);
                quote!( as *mut _).to_tokens(tokens);
            },
            Self::IfNotNull(condition, expr) => {
                quote!(if (!(#condition).is_null()) { #expr }).to_tokens(tokens);
            },
            Self::IfThen(condition, expr) => {
                condition.to_tokens(tokens);
                quote!(.then(|| #expr)).to_tokens(tokens);
            }
            Self::MapOr(condition, def, mapper) => {
                condition.to_tokens(tokens);
                quote!(.map_or(#def, #mapper)).to_tokens(tokens);
            }
            Self::NullMut =>
                quote!(std::ptr::null_mut()).to_tokens(tokens),
            Self::CChar =>
                quote!(std::os::raw::c_char).to_tokens(tokens),
            Self::Arc =>
                quote!(std::sync::Arc).to_tokens(tokens),
            Self::Rc =>
                quote!(std::rc::Rc).to_tokens(tokens),
            Self::Box =>
                quote!(Box).to_tokens(tokens),
            Self::Mutex =>
                quote!(std::sync::Mutex).to_tokens(tokens),
            Self::OnceLock =>
                quote!(std::sync::OnceLock).to_tokens(tokens),
            Self::RwLock =>
                quote!(std::sync::RwLock).to_tokens(tokens),
            Self::Cell =>
                quote!(std::cell::Cell).to_tokens(tokens),
            Self::RefCell =>
                quote!(std::cell::RefCell).to_tokens(tokens),
            Self::UnsafeCell =>
                quote!(std::cell::UnsafeCell).to_tokens(tokens),
            Self::AsSlice(expr) => {
                expr.to_tokens(tokens);
                quote!(.as_slice()).to_tokens(tokens);
            },
            Self::MapCollect(iter, mapper) => {
                iter.to_tokens(tokens);
                quote!(.map(#mapper).collect()).to_tokens(tokens);
            },
            Self::ToVec(expr) => {
                expr.to_tokens(tokens);
                quote!(.to_vec()).to_tokens(tokens);
            },
            Self::Match(expr) => {
                quote!(match ).to_tokens(tokens);
                expr.to_tokens(tokens);
            },
            Self::MatchFields(expr, sequences) => {
                Self::Match(quote!(#expr { #sequences }))
                    .to_tokens(tokens)
            },
            #[cfg(feature = "objc")]
            Self::SwitchFields(expr, sequences) => {
                quote!(switch (#expr) { #sequences }).to_tokens(tokens);
            },
            #[cfg(feature = "objc")]
            Self::Case(l_value, r_value) => {
                let case = quote! {
                    case #l_value: {
                        #r_value
                    }
                };
                case.to_tokens(tokens);
            },
            Self::MatchResult(to_ok_conversion, to_error_conversion) => {
                let null_mut = DictionaryExpr::NullMut;
                let field_path = DictionaryName::Obj;
                let arg_path = DictionaryName::O;
                Self::MatchFields(field_path.to_token_stream(), CommaPunctuated::from_iter([
                    ArgPresentation::attr_less_arm(Pat::Verbatim(quote!(Ok(#arg_path))), quote!((#to_ok_conversion, #null_mut))),
                    ArgPresentation::attr_less_arm(Pat::Verbatim(quote!(Err(#arg_path))), quote!((#null_mut, #to_error_conversion))),
                ])).to_tokens(tokens)
            },
            Self::FromRoot(conversion) => {
                Self::LetFfiRef.to_tokens(tokens);
                conversion.to_tokens(tokens);
            },
            Self::CountRange =>
                quote!((0..count)).to_tokens(tokens),
            Self::NewSmth(conversion, smth) =>
                quote!(#smth::new(#conversion)).to_tokens(tokens),
            Self::LeakBox(conversion) =>
                quote!(Box::leak(Box::new(#conversion))).to_tokens(tokens),
            Self::MapIntoBox(conversion) => {
                conversion.to_tokens(tokens);
                quote!(.map(Box::new)).to_tokens(tokens);
            },
            Self::FromRawBox(conversion) =>
                quote!(Box::from_raw(#conversion)).to_tokens(tokens),
            Self::Clone(expr) =>
                quote!(#expr.clone()).to_tokens(tokens),

            Self::FromPtrRead(expr) =>
                quote!(std::ptr::read(#expr)).to_tokens(tokens),
            Self::FromArc(expr) =>
                quote!(std::sync::Arc::clone(#expr)).to_tokens(tokens),
            Self::FromRc(expr) =>
                quote!(std::rc::Rc::clone(#expr)).to_tokens(tokens),
            Self::SelfAsTrait(self_ty, acc) =>
                quote!(*((*self_).object as *#acc #self_ty)).to_tokens(tokens),

            Self::TypeDestructuring(ty, content) =>
                quote!(#ty { #content }).to_tokens(tokens),
            Self::TryIntoUnwrap(expr) => {
                expr.to_tokens(tokens);
                quote!(.try_into().unwrap()).to_tokens(tokens)
            }
            Self::CallbackCaller(args_to_conversion, post_processing) => {
                quote!(let ffi_result = (self.caller)(#args_to_conversion);).to_tokens(tokens);
                post_processing.to_tokens(tokens);
            },
            Self::CallbackDestructor(result_conversion, ffi_result) =>
                quote!(
                    let result = #result_conversion;
                    (self.destructor)(#ffi_result);
                    result
                ).to_tokens(tokens),
            Self::CastedFFIConversion(interface, method, ffi_type, target_type, expr) =>
                quote!(<#ffi_type as ferment::#interface<#target_type>>::#method(#expr)).to_tokens(tokens),
            Self::BoxedSelfDestructuring(expr) =>
                InterfacesMethodExpr::Boxed(DictionaryExpr::self_destruct(expr)).to_tokens(tokens),
            Self::IfElse(condition, true_expr, false_expr) =>
                quote!(if #condition { #true_expr } else { #false_expr }).to_tokens(tokens)
        }
    }
}