mod code_gen;
pub mod error;
mod model_types;
pub mod parsely_read;
pub mod parsely_write;
mod syn_helpers;
pub use bits_io::{
buf::bit_buf::BitBuf,
buf::bit_buf_exts::BitBufExts,
buf::bit_buf_mut::BitBufMut,
buf::bit_buf_mut_exts::BitBufMutExts,
buf::bits::Bits,
buf::bits_mut::BitsMut,
buf::byte_order::{BigEndian, ByteOrder, LittleEndian, NetworkOrder},
io::{bit_cursor::BitCursor, bit_read::BitRead, bit_write::BitWrite},
};
pub mod nsw_types {
pub use bits_io::nsw_types::from_bitslice::BitSliceUxExts;
pub use bits_io::nsw_types::*;
}
pub mod anyhow {
pub use anyhow::*;
}
use code_gen::{gen_read::generate_parsely_read_impl, gen_write::generate_parsely_write_impl};
use darling::{ast, FromDeriveInput, FromField, FromMeta};
use model_types::{Assertion, Context, ExprOrFunc, MapExpr, TypedFnArgList};
use proc_macro2::TokenStream;
use syn::DeriveInput;
use syn_helpers::TypeExts;
#[doc(hidden)]
pub fn derive_parsely_read(item: TokenStream) -> std::result::Result<TokenStream, syn::Error> {
let ast: DeriveInput = syn::parse2(item)?;
let data = ParselyReadData::from_derive_input(&ast)?;
Ok(generate_parsely_read_impl(data))
}
#[doc(hidden)]
pub fn derive_parsely_write(item: TokenStream) -> std::result::Result<TokenStream, syn::Error> {
let ast: DeriveInput = syn::parse2(item)?;
let data = ParselyWriteData::from_derive_input(&ast)?;
Ok(generate_parsely_write_impl(data))
}
#[derive(Debug, FromField, FromMeta)]
pub struct ParselyCommonFieldData {
assertion: Option<Assertion>,
context: Option<Context>,
map: Option<MapExpr>,
alignment: Option<usize>,
}
#[derive(Debug, FromField)]
#[darling(attributes(parsely, parsely_read))]
pub struct ParselyReadFieldData {
ident: Option<syn::Ident>,
ty: syn::Type,
#[darling(flatten)]
common: ParselyCommonFieldData,
count: Option<syn::Expr>,
while_pred: Option<syn::Expr>,
assign_from: Option<syn::Expr>,
when: Option<syn::Expr>,
}
impl ParselyReadFieldData {
pub(crate) fn buffer_type(&self) -> &syn::Type {
if self.ty.is_option() || self.ty.is_collection() {
self.ty
.inner_type()
.expect("Option or collection has an inner type")
} else {
&self.ty
}
}
pub(crate) fn context_values(&self) -> Vec<syn::Expr> {
let field_name = self
.ident
.as_ref()
.expect("Field must have a name")
.to_string();
if let Some(ref field_context) = self.common.context {
field_context.expressions(&format!("Read context for field '{field_name}'"))
} else {
vec![]
}
}
}
#[derive(Debug, FromField)]
#[darling(attributes(parsely, parsely_write))]
pub struct ParselyWriteFieldData {
ident: Option<syn::Ident>,
ty: syn::Type,
#[darling(flatten)]
common: ParselyCommonFieldData,
sync_expr: Option<ExprOrFunc>,
#[darling(default)]
sync_with: Context,
}
impl ParselyWriteFieldData {
pub(crate) fn buffer_type(&self) -> &syn::Type {
if self.ty.is_option() || self.ty.is_collection() {
self.ty
.inner_type()
.expect("Option or collection has an inner type")
} else {
&self.ty
}
}
pub(crate) fn context_values(&self) -> Vec<syn::Expr> {
let field_name = self
.ident
.as_ref()
.expect("Field must have a name")
.to_string();
if let Some(ref field_context) = self.common.context {
field_context.expressions(&format!("Write context for field '{field_name}'"))
} else {
vec![]
}
}
pub(crate) fn sync_with_expressions(&self) -> Vec<syn::Expr> {
let field_name = self
.ident
.as_ref()
.expect("Field must have a name")
.to_string();
self.sync_with
.expressions(&format!("Sync context for field '{field_name}'"))
}
}
#[derive(Debug, FromDeriveInput)]
#[darling(attributes(parsely, parsely_read), supports(struct_any, enum_any))]
pub struct ParselyReadData {
ident: syn::Ident,
required_context: Option<TypedFnArgList>,
alignment: Option<usize>,
data: ast::Data<(), ParselyReadFieldData>,
}
#[derive(Debug, FromDeriveInput)]
#[darling(attributes(parsely, parsely_write), supports(struct_any, enum_any))]
pub struct ParselyWriteData {
ident: syn::Ident,
required_context: Option<TypedFnArgList>,
sync_args: Option<TypedFnArgList>,
alignment: Option<usize>,
data: ast::Data<(), ParselyWriteFieldData>,
}
pub(crate) fn get_crate_name() -> syn::Ident {
let found_crate =
proc_macro_crate::crate_name("parsely-rs").expect("parsely-rs is present in Cargo.toml");
let crate_name = match found_crate {
proc_macro_crate::FoundCrate::Itself => "parsely-rs".to_string(),
proc_macro_crate::FoundCrate::Name(name) => name,
};
syn::Ident::new(&crate_name, proc_macro2::Span::call_site())
}