parsely_impl/
model_types.rs1use darling::{ast, FromMeta};
2use proc_macro2::TokenStream;
3use quote::{format_ident, quote, ToTokens};
4use syn::parse::Parse;
5
6use crate::get_crate_name;
7
8pub(crate) enum CollectionLimit {
9 Count(syn::Expr),
10 While(syn::Expr),
11}
12
13#[derive(Debug)]
14pub(crate) struct TypedFnArgList(pub(crate) Vec<TypedFnArg>);
15
16impl TypedFnArgList {
17 pub(crate) fn types(&self) -> Vec<&syn::Type> {
19 self.0.iter().map(|t| t.ty()).collect()
20 }
21
22 pub(crate) fn names(&self) -> Vec<&syn::Ident> {
23 self.0.iter().map(|t| t.name()).collect()
24 }
25
26 pub(crate) fn assignments(&self) -> Vec<Local> {
28 self.0
29 .iter()
30 .enumerate()
31 .map(|(idx, fn_arg)| {
32 let idx: syn::Index = idx.into();
33 syn::parse2::<Local>(quote! {
34 let #fn_arg = ctx.#idx;
35 })
36 .unwrap()
37 })
38 .collect::<Vec<_>>()
39 }
40}
41
42impl FromMeta for TypedFnArgList {
43 fn from_none() -> Option<Self> {
44 None
45 }
46
47 fn from_list(items: &[ast::NestedMeta]) -> darling::Result<Self> {
48 let required_context: Vec<TypedFnArg> = items
49 .iter()
50 .map(|item| {
51 match item {
52 ast::NestedMeta::Meta(_) => Err(darling::Error::unsupported_format(
54 "FnArg literals required",
55 )),
56 ast::NestedMeta::Lit(lit) => match lit {
57 syn::Lit::Str(s) => s.parse().map_err(|e| e.into()),
58 l => Err(darling::Error::unexpected_lit_type(l)),
59 },
60 }
61 })
62 .collect::<Result<Vec<_>, _>>()?;
63
64 Ok(Self(required_context))
65 }
66}
67
68#[derive(Debug, Default)]
69pub(crate) struct Context(Vec<syn::Expr>);
70
71impl Context {
72 pub(crate) fn expressions(&self, context: &str) -> Vec<syn::Expr> {
75 self.0
79 .iter()
80 .cloned()
81 .enumerate()
82 .map(|(idx, e)| {
83 syn::parse2(quote! {
84 (#e).into_parsely_result().with_context(|| format!("{}: expression {}", #context, #idx))?
85 })
86 .unwrap()
87 })
88 .collect()
89 }
90
91 pub(crate) fn is_empty(&self) -> bool {
92 self.0.is_empty()
93 }
94}
95
96impl FromMeta for Context {
97 fn from_none() -> Option<Self> {
98 None
99 }
100 fn from_list(items: &[ast::NestedMeta]) -> darling::Result<Self> {
101 let expressions: Vec<syn::Expr> = items
102 .iter()
103 .map(|item| {
104 match item {
105 ast::NestedMeta::Meta(_) => Err(darling::Error::unsupported_format(
107 "FnArg literals required",
108 )),
109 ast::NestedMeta::Lit(lit) => match lit {
110 syn::Lit::Str(s) => s.parse().map_err(|e| e.into()),
111 l => Err(darling::Error::unexpected_lit_type(l)),
112 },
113 }
114 })
115 .collect::<Result<Vec<_>, _>>()?;
116
117 Ok(Self(expressions))
118 }
119}
120
121#[derive(Debug)]
123pub(crate) struct TypedFnArg(syn::FnArg);
124
125impl Parse for TypedFnArg {
126 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
127 match syn::FnArg::parse(input) {
128 Ok(syn::FnArg::Typed(t)) => Ok(Self(syn::FnArg::Typed(t))),
129 Ok(syn::FnArg::Receiver(_)) => todo!("figure out error to return here"),
130 Err(e) => Err(e),
131 }
132 }
133}
134
135impl TypedFnArg {
136 pub(crate) fn ty(&self) -> &syn::Type {
137 match self.0 {
138 syn::FnArg::Typed(ref t) => &t.ty,
139 _ => unreachable!("TypedFnArg should always be typed"),
140 }
141 }
142
143 pub(crate) fn name(&self) -> &syn::Ident {
144 match self.0 {
145 syn::FnArg::Typed(ref pat_type) => match *pat_type.pat {
146 syn::Pat::Ident(ref pat_ident) => &pat_ident.ident,
147 _ => unreachable!("TypedFnArg should always have an ident"),
148 },
149 _ => unreachable!("TypedFnArg should always be typed"),
150 }
151 }
152}
153
154impl ToTokens for TypedFnArg {
155 fn to_tokens(&self, tokens: &mut TokenStream) {
156 self.0.to_tokens(tokens)
157 }
158}
159
160pub(crate) struct Local(pub(crate) syn::Local);
163
164impl Parse for Local {
165 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
166 match syn::Stmt::parse(input) {
167 Ok(syn::Stmt::Local(l)) => Ok(Self(l)),
168 _ => Err(input.error("Failed to parse Local, expected a local declaration")),
169 }
170 }
171}
172
173impl ToTokens for Local {
174 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
175 self.0.to_tokens(tokens)
176 }
177}
178
179#[derive(Debug)]
180pub(crate) enum ExprOrFunc {
181 Expr(syn::Expr),
182 Func(syn::Ident),
183}
184
185impl Parse for ExprOrFunc {
186 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
187 if let Ok(expr) = syn::Expr::parse(input) {
188 Ok(ExprOrFunc::Expr(expr))
189 } else if let Ok(id) = syn::Ident::parse(input) {
190 Ok(ExprOrFunc::Func(id))
191 } else {
192 Err(input.error("Failed to parse ExporOrFunc: expected ExprClosure or Ident"))
193 }
194 }
195}
196
197impl ToTokens for ExprOrFunc {
198 fn to_tokens(&self, tokens: &mut TokenStream) {
199 match self {
200 ExprOrFunc::Expr(e) => e.to_tokens(tokens),
201 ExprOrFunc::Func(f) => f.to_tokens(tokens),
202 }
203 }
204}
205
206impl FromMeta for ExprOrFunc {
207 fn from_string(value: &str) -> darling::Result<Self> {
208 syn::parse_str::<ExprOrFunc>(value).map_err(darling::Error::custom)
209 }
210}
211
212#[derive(Debug)]
213pub(crate) enum FuncOrClosure {
214 Func(syn::Ident),
215 Closure(syn::ExprClosure),
216}
217
218impl Parse for FuncOrClosure {
219 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
220 if let Ok(expr_closure) = syn::ExprClosure::parse(input) {
221 Ok(FuncOrClosure::Closure(expr_closure))
222 } else if let Ok(id) = syn::Ident::parse(input) {
223 Ok(FuncOrClosure::Func(id))
224 } else {
225 Err(input.error("Failed to parse FuncOrClosure: expected ExprClosure or Ident"))
226 }
227 }
228}
229
230impl ToTokens for FuncOrClosure {
231 fn to_tokens(&self, tokens: &mut TokenStream) {
232 match self {
233 FuncOrClosure::Func(m) => m.to_tokens(tokens),
234 FuncOrClosure::Closure(c) => c.to_tokens(tokens),
235 }
236 }
237}
238
239impl FromMeta for FuncOrClosure {
240 fn from_string(value: &str) -> darling::Result<Self> {
241 syn::parse_str::<FuncOrClosure>(value).map_err(darling::Error::custom)
242 }
243}
244
245#[derive(Debug)]
247pub(crate) struct MapExpr(FuncOrClosure);
248
249impl FromMeta for MapExpr {
250 fn from_string(value: &str) -> darling::Result<Self> {
251 Ok(Self(FuncOrClosure::from_string(value)?))
252 }
253}
254
255impl MapExpr {
256 pub(crate) fn to_read_map_tokens(&self, field_name: &syn::Ident, tokens: &mut TokenStream) {
257 let crate_name = get_crate_name();
258 let field_name_string = field_name.to_string();
259 let map_expr = &self.0;
260 tokens.extend(quote! {
263 {
264 let original_value = ::#crate_name::ParselyRead::read::<T>(buf, ())
265 .with_context(|| format!("Reading raw value for field '{}'", #field_name_string))?;
266 (#map_expr)(original_value).into_parsely_result()
267 .with_context(|| format!("Mapping raw value for field '{}'", #field_name_string))
268 }
269 })
270 }
271
272 pub(crate) fn to_write_map_tokens(&self, field_name: &syn::Ident, tokens: &mut TokenStream) {
273 let crate_name = get_crate_name();
274 let field_name_string = field_name.to_string();
275 let map_expr = &self.0;
276 tokens.extend(quote! {
277 {
278 let mapped_value = (#map_expr)(&self.#field_name);
279 let result = <_ as IntoWritableParselyResult<_, B>>::into_writable_parsely_result(mapped_value)
283 .with_context(|| format!("Mapping raw value for field '{}'", #field_name_string))?;
284 ::#crate_name::ParselyWrite::write::<T>(&result, buf, ())
285 .with_context(|| format!("Writing mapped value for field '{}'", #field_name_string))?;
286 }
287 })
288 }
289}
290
291#[derive(Debug)]
293pub(crate) struct Assertion(FuncOrClosure);
294
295impl Parse for Assertion {
296 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
297 Ok(Self(FuncOrClosure::parse(input)?))
298 }
299}
300
301impl FromMeta for Assertion {
302 fn from_string(value: &str) -> darling::Result<Self> {
303 Ok(Self(FuncOrClosure::from_string(value)?))
304 }
305}
306
307impl Assertion {
308 pub(crate) fn to_read_assertion_tokens(&self, field_name: &str, tokens: &mut TokenStream) {
309 let assertion = &self.0;
310 let assertion_string = quote! { #assertion }.to_string();
311 tokens.extend(quote! {
312 .and_then(|read_value| {
313 let assertion_func = #assertion;
314 if !assertion_func(&read_value) {
315 bail!("Assertion failed: value of field '{}' ('{:?}') didn't pass assertion: '{}'", #field_name, read_value, #assertion_string)
316 }
317 Ok(read_value)
318 })
319 });
320 }
321
322 pub(crate) fn to_write_assertion_tokens(&self, field_name: &str, tokens: &mut TokenStream) {
323 let assertion = &self.0;
324 let assertion_string = quote! { #assertion }.to_string();
325 let assertion_func_ident = format_ident!("__{}_assertion_func", field_name);
326 let field_name_ident = format_ident!("{field_name}");
327 tokens.extend(quote! {
328 let #assertion_func_ident = #assertion;
329 if !#assertion_func_ident(&self.#field_name_ident) {
330 bail!("Assertion failed: value of field '{}' ('{:?}') didn't pass assertion: '{}'", #field_name, self.#field_name_ident, #assertion_string)
331 }
332 })
333 }
334}
335
336pub(crate) fn wrap_read_with_padding_handling(
337 element_ident: &syn::Ident,
338 alignment: usize,
339 inner: TokenStream,
340) -> TokenStream {
341 let bytes_read_before_ident = format_ident!("__bytes_read_before_{element_ident}_read");
342 let bytes_read_after_ident = format_ident!("__bytes_read_after_{element_ident}_read");
343 let amount_read_ident = format_ident!("__bytes_read_for_{element_ident}");
344
345 quote! {
346 let #bytes_read_before_ident = buf.remaining_bytes();
347
348 #inner
349
350 let #bytes_read_after_ident = buf.remaining_bytes();
351 let mut #amount_read_ident = #bytes_read_before_ident - #bytes_read_after_ident;
352 while #amount_read_ident % #alignment != 0 {
353 let _ = buf.get_u8().context("padding")?;
354 #amount_read_ident += 1;
355 }
356 }
357}
358
359pub(crate) fn wrap_write_with_padding_handling(
360 element_ident: &syn::Ident,
361 alignment: usize,
362 inner: TokenStream,
363) -> TokenStream {
364 let bytes_written_before_ident = format_ident!("__bytes_written_before_{element_ident}_write");
365 let bytes_written_after_ident = format_ident!("__bytes_written_after_{element_ident}_write");
366 let amount_written_ident = format_ident!("__bytes_written_for_{element_ident}");
367
368 quote! {
369 let #bytes_written_before_ident = buf.remaining_bytes();
370
371 #inner
372
373 let #bytes_written_after_ident = buf.remaining_bytes();
374 let mut #amount_written_ident = #bytes_written_after_ident - #bytes_written_before_ident;
375 while #amount_written_ident % #alignment != 0 {
376 buf.put_u8(0).context("padding")?;
377 #amount_written_ident += 1;
378 }
379 }
380}