1mod code_gen;
2pub mod error;
3mod model_types;
4pub mod parsely_read;
5pub mod parsely_write;
6mod syn_helpers;
7
8pub use bits_io::{
9 buf::bit_buf::BitBuf,
10 buf::bit_buf_exts::BitBufExts,
11 buf::bit_buf_mut::BitBufMut,
12 buf::bit_buf_mut_exts::BitBufMutExts,
13 buf::bits::Bits,
14 buf::bits_mut::BitsMut,
15 buf::byte_order::{BigEndian, ByteOrder, LittleEndian, NetworkOrder},
16 io::{bit_cursor::BitCursor, bit_read::BitRead, bit_write::BitWrite},
17};
18
19pub mod nsw_types {
20 pub use bits_io::nsw_types::from_bitslice::BitSliceUxExts;
21 pub use bits_io::nsw_types::*;
22}
23
24pub mod anyhow {
25 pub use anyhow::*;
26}
27
28use code_gen::{gen_read::generate_parsely_read_impl, gen_write::generate_parsely_write_impl};
29use darling::{ast, FromDeriveInput, FromField, FromMeta};
30use model_types::{Assertion, Context, ExprOrFunc, MapExpr, TypedFnArgList};
31use proc_macro2::TokenStream;
32use syn::DeriveInput;
33use syn_helpers::TypeExts;
34
35#[doc(hidden)]
36pub fn derive_parsely_read(item: TokenStream) -> std::result::Result<TokenStream, syn::Error> {
37 let ast: DeriveInput = syn::parse2(item)?;
38 let data = ParselyReadData::from_derive_input(&ast)?;
39 Ok(generate_parsely_read_impl(data))
43}
44
45#[doc(hidden)]
46pub fn derive_parsely_write(item: TokenStream) -> std::result::Result<TokenStream, syn::Error> {
47 let ast: DeriveInput = syn::parse2(item)?;
48 let data = ParselyWriteData::from_derive_input(&ast)?;
49 Ok(generate_parsely_write_impl(data))
53}
54
55#[derive(Debug, FromField, FromMeta)]
56pub struct ParselyCommonFieldData {
57 assertion: Option<Assertion>,
62
63 context: Option<Context>,
65
66 map: Option<MapExpr>,
68
69 alignment: Option<usize>,
72}
73
74#[derive(Debug, FromField)]
75#[darling(attributes(parsely, parsely_read))]
76pub struct ParselyReadFieldData {
77 ident: Option<syn::Ident>,
78
79 ty: syn::Type,
80
81 #[darling(flatten)]
82 common: ParselyCommonFieldData,
83 count: Option<syn::Expr>,
85 while_pred: Option<syn::Expr>,
89
90 assign_from: Option<syn::Expr>,
93
94 when: Option<syn::Expr>,
96}
97
98impl ParselyReadFieldData {
99 pub(crate) fn buffer_type(&self) -> &syn::Type {
103 if self.ty.is_option() || self.ty.is_collection() {
104 self.ty
105 .inner_type()
106 .expect("Option or collection has an inner type")
107 } else {
108 &self.ty
109 }
110 }
111
112 pub(crate) fn context_values(&self) -> Vec<syn::Expr> {
114 let field_name = self
115 .ident
116 .as_ref()
117 .expect("Field must have a name")
118 .to_string();
119 if let Some(ref field_context) = self.common.context {
120 field_context.expressions(&format!("Read context for field '{field_name}'"))
121 } else {
122 vec![]
123 }
124 }
125}
126
127#[derive(Debug, FromField)]
128#[darling(attributes(parsely, parsely_write))]
129pub struct ParselyWriteFieldData {
130 ident: Option<syn::Ident>,
131
132 ty: syn::Type,
133
134 #[darling(flatten)]
135 common: ParselyCommonFieldData,
136
137 sync_expr: Option<ExprOrFunc>,
140
141 #[darling(default)]
145 sync_with: Context,
146}
147
148impl ParselyWriteFieldData {
149 pub(crate) fn buffer_type(&self) -> &syn::Type {
153 if self.ty.is_option() || self.ty.is_collection() {
154 self.ty
155 .inner_type()
156 .expect("Option or collection has an inner type")
157 } else {
158 &self.ty
159 }
160 }
161
162 pub(crate) fn context_values(&self) -> Vec<syn::Expr> {
164 let field_name = self
165 .ident
166 .as_ref()
167 .expect("Field must have a name")
168 .to_string();
169 if let Some(ref field_context) = self.common.context {
170 field_context.expressions(&format!("Write context for field '{field_name}'"))
171 } else {
172 vec![]
173 }
174 }
175
176 pub(crate) fn sync_with_expressions(&self) -> Vec<syn::Expr> {
178 let field_name = self
179 .ident
180 .as_ref()
181 .expect("Field must have a name")
182 .to_string();
183 self.sync_with
184 .expressions(&format!("Sync context for field '{field_name}'"))
185 }
186}
187
188#[derive(Debug, FromDeriveInput)]
189#[darling(attributes(parsely, parsely_read), supports(struct_any, enum_any))]
190pub struct ParselyReadData {
191 ident: syn::Ident,
192 required_context: Option<TypedFnArgList>,
193 alignment: Option<usize>,
194 data: ast::Data<(), ParselyReadFieldData>,
195}
196
197#[derive(Debug, FromDeriveInput)]
198#[darling(attributes(parsely, parsely_write), supports(struct_any, enum_any))]
199pub struct ParselyWriteData {
200 ident: syn::Ident,
201 required_context: Option<TypedFnArgList>,
202 sync_args: Option<TypedFnArgList>,
203 alignment: Option<usize>,
204 data: ast::Data<(), ParselyWriteFieldData>,
205}
206
207pub(crate) fn get_crate_name() -> syn::Ident {
208 let found_crate =
209 proc_macro_crate::crate_name("parsely-rs").expect("parsely-rs is present in Cargo.toml");
210
211 let crate_name = match found_crate {
212 proc_macro_crate::FoundCrate::Itself => "parsely-rs".to_string(),
213 proc_macro_crate::FoundCrate::Name(name) => name,
214 };
215
216 syn::Ident::new(&crate_name, proc_macro2::Span::call_site())
217}