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::*;
21}
22
23pub mod anyhow {
24 pub use anyhow::*;
25}
26
27use code_gen::{gen_read::generate_parsely_read_impl, gen_write::generate_parsely_write_impl};
28use darling::{ast, FromDeriveInput, FromField, FromMeta};
29use model_types::{Assertion, Context, ExprOrFunc, MapExpr, TypedFnArgList};
30use proc_macro2::TokenStream;
31use syn::DeriveInput;
32use syn_helpers::TypeExts;
33
34#[doc(hidden)]
35pub fn derive_parsely_read(item: TokenStream) -> std::result::Result<TokenStream, syn::Error> {
36 let ast: DeriveInput = syn::parse2(item)?;
37 let data = ParselyReadData::from_derive_input(&ast)?;
38 Ok(generate_parsely_read_impl(data))
42}
43
44#[doc(hidden)]
45pub fn derive_parsely_write(item: TokenStream) -> std::result::Result<TokenStream, syn::Error> {
46 let ast: DeriveInput = syn::parse2(item)?;
47 let data = ParselyWriteData::from_derive_input(&ast)?;
48 Ok(generate_parsely_write_impl(data))
52}
53
54#[derive(Debug, FromField, FromMeta)]
55pub struct ParselyCommonFieldData {
56 assertion: Option<Assertion>,
61
62 context: Option<Context>,
64
65 map: Option<MapExpr>,
67
68 alignment: Option<usize>,
71}
72
73#[derive(Debug, FromField)]
74#[darling(attributes(parsely, parsely_read))]
75pub struct ParselyReadFieldData {
76 ident: Option<syn::Ident>,
77
78 ty: syn::Type,
79
80 #[darling(flatten)]
81 common: ParselyCommonFieldData,
82 count: Option<syn::Expr>,
84 while_pred: Option<syn::Expr>,
88
89 assign_from: Option<syn::Expr>,
92
93 when: Option<syn::Expr>,
95}
96
97impl ParselyReadFieldData {
98 pub(crate) fn buffer_type(&self) -> &syn::Type {
102 if self.ty.is_option() || self.ty.is_collection() {
103 self.ty
104 .inner_type()
105 .expect("Option or collection has an inner type")
106 } else {
107 &self.ty
108 }
109 }
110
111 pub(crate) fn context_values(&self) -> Vec<syn::Expr> {
113 let field_name = self
114 .ident
115 .as_ref()
116 .expect("Field must have a name")
117 .to_string();
118 if let Some(ref field_context) = self.common.context {
119 field_context.expressions(&format!("Read context for field '{field_name}'"))
120 } else {
121 vec![]
122 }
123 }
124}
125
126#[derive(Debug, FromField)]
127#[darling(attributes(parsely, parsely_write))]
128pub struct ParselyWriteFieldData {
129 ident: Option<syn::Ident>,
130
131 ty: syn::Type,
132
133 #[darling(flatten)]
134 common: ParselyCommonFieldData,
135
136 sync_expr: Option<ExprOrFunc>,
139
140 #[darling(default)]
144 sync_with: Context,
145}
146
147impl ParselyWriteFieldData {
148 pub(crate) fn buffer_type(&self) -> &syn::Type {
152 if self.ty.is_option() || self.ty.is_collection() {
153 self.ty
154 .inner_type()
155 .expect("Option or collection has an inner type")
156 } else {
157 &self.ty
158 }
159 }
160
161 pub(crate) fn context_values(&self) -> Vec<syn::Expr> {
163 let field_name = self
164 .ident
165 .as_ref()
166 .expect("Field must have a name")
167 .to_string();
168 if let Some(ref field_context) = self.common.context {
169 field_context.expressions(&format!("Write context for field '{field_name}'"))
170 } else {
171 vec![]
172 }
173 }
174
175 pub(crate) fn sync_with_expressions(&self) -> Vec<syn::Expr> {
177 let field_name = self
178 .ident
179 .as_ref()
180 .expect("Field must have a name")
181 .to_string();
182 self.sync_with
183 .expressions(&format!("Sync context for field '{field_name}'"))
184 }
185}
186
187#[derive(Debug, FromDeriveInput)]
188#[darling(attributes(parsely, parsely_read), supports(struct_any, enum_any))]
189pub struct ParselyReadData {
190 ident: syn::Ident,
191 required_context: Option<TypedFnArgList>,
192 alignment: Option<usize>,
193 data: ast::Data<(), ParselyReadFieldData>,
194}
195
196#[derive(Debug, FromDeriveInput)]
197#[darling(attributes(parsely, parsely_write), supports(struct_any, enum_any))]
198pub struct ParselyWriteData {
199 ident: syn::Ident,
200 required_context: Option<TypedFnArgList>,
201 sync_args: Option<TypedFnArgList>,
202 alignment: Option<usize>,
203 data: ast::Data<(), ParselyWriteFieldData>,
204}
205
206pub(crate) fn get_crate_name() -> syn::Ident {
207 let found_crate =
208 proc_macro_crate::crate_name("parsely-rs").expect("parsely-rs is present in Cargo.toml");
209
210 let crate_name = match found_crate {
211 proc_macro_crate::FoundCrate::Itself => "parsely-rs".to_string(),
212 proc_macro_crate::FoundCrate::Name(name) => name,
213 };
214
215 syn::Ident::new(&crate_name, proc_macro2::Span::call_site())
216}