savvy_bindgen/ir/
savvy_struct.rs1use syn::{parse_quote, spanned::Spanned};
2
3use crate::extract_docs;
4
5pub struct SavvyStruct {
6 pub docs: Vec<String>,
8 pub attrs: Vec<syn::Attribute>,
10 pub ty: syn::Ident,
12}
13
14impl SavvyStruct {
15 pub fn new(orig: &syn::ItemStruct) -> syn::Result<Self> {
16 if let Some(lt) = orig.generics.lifetimes().next() {
17 return Err(syn::Error::new(
18 lt.span(),
19 "#[savvy] macro doesn't support lifetime",
20 ));
21 }
22
23 let mut attrs = orig.attrs.clone();
24 attrs.retain(|attr| attr != &parse_quote!(#[savvy]));
26 let docs = extract_docs(attrs.as_slice());
28 let ty = orig.ident.clone();
29
30 Ok(Self { docs, attrs, ty })
31 }
32
33 pub fn generate_try_from_impls(&self) -> Vec<syn::ItemImpl> {
34 let ty = &self.ty;
35
36 let impl_into_external_pointer: syn::ItemImpl =
37 parse_quote!(impl savvy::IntoExtPtrSexp for #ty {});
38
39 let impl_try_from_ty_to_sexp: syn::ItemImpl = parse_quote!(
40 impl TryFrom<#ty> for savvy::Sexp {
41 type Error = savvy::Error;
42
43 fn try_from(value: #ty) -> savvy::Result<Self> {
44 use savvy::IntoExtPtrSexp;
45
46 Ok(value.into_external_pointer())
47 }
48 }
49 );
50
51 let impl_try_from_sexp_to_ref_ty: syn::ItemImpl = parse_quote!(
52 impl TryFrom<savvy::Sexp> for &#ty {
53 type Error = savvy::Error;
54
55 fn try_from(value: savvy::Sexp) -> savvy::Result<Self> {
56 value.assert_external_pointer()?;
58
59 let x = unsafe { savvy::get_external_pointer_addr(value.0)? as *mut #ty };
60 let res = unsafe { x.as_ref() };
61 res.ok_or(savvy::savvy_err!("Failed to convert the external pointer to the Rust object"))
62 }
63 }
64 );
65
66 let impl_try_from_sexp_to_ref_mut_ty: syn::ItemImpl = parse_quote!(
67 impl TryFrom<savvy::Sexp> for &mut #ty {
68 type Error = savvy::Error;
69
70 fn try_from(value: savvy::Sexp) -> savvy::Result<Self> {
71 value.assert_external_pointer()?;
73
74 let x = unsafe { savvy::get_external_pointer_addr(value.0)? as *mut #ty };
75 let res = unsafe { x.as_mut() };
76 res.ok_or(savvy::savvy_err!("Failed to convert the external pointer to the Rust object"))
77 }
78 }
79 );
80
81 let impl_try_from_sexp_to_ty: syn::ItemImpl = parse_quote!(
82 impl TryFrom<savvy::Sexp> for #ty {
83 type Error = savvy::Error;
84
85 fn try_from(value: savvy::Sexp) -> savvy::Result<Self> {
86 value.assert_external_pointer()?;
88
89 unsafe { savvy::take_external_pointer_value::<#ty>(value.0) }
90 }
91 }
92 );
93
94 vec![
95 impl_into_external_pointer,
96 impl_try_from_ty_to_sexp,
97 impl_try_from_sexp_to_ref_ty,
98 impl_try_from_sexp_to_ref_mut_ty,
99 impl_try_from_sexp_to_ty,
100 ]
101 }
102}