From f8527d60e7074b1e8a76fe54c8c7ac1cf86b9a34 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Fri, 12 Sep 2025 19:51:06 +0300 Subject: [PATCH] feat: handle error cases --- filecaster-derive/src/from_file/parser.rs | 12 ++++++-- filecaster-derive/src/lib.rs | 35 +++++++++++++++++++++-- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/filecaster-derive/src/from_file/parser.rs b/filecaster-derive/src/from_file/parser.rs index 5a97cb6..1e3b565 100644 --- a/filecaster-derive/src/from_file/parser.rs +++ b/filecaster-derive/src/from_file/parser.rs @@ -5,9 +5,15 @@ use unsynn::*; pub fn parse_from_file_default_attr(attrs: &[Attribute]) -> Result> { for attr in attrs { if attr.path == "from_file" { - return extract_default_token(attr.tokens.clone()) - .map(Some) - .ok_or_else(|| Error::no_error()); // TODO: different error + let tokens = attr.tokens.clone(); + let iter = tokens.clone().into_token_iter(); + + match extract_default_token(tokens) { + Some(ts) => return Ok(Some(ts)), + None => { + return Error::other(&iter, "missing default value in #[from_file]".into()); + } + }; } } Ok(None) diff --git a/filecaster-derive/src/lib.rs b/filecaster-derive/src/lib.rs index 67f3783..ef8bb76 100644 --- a/filecaster-derive/src/lib.rs +++ b/filecaster-derive/src/lib.rs @@ -97,14 +97,43 @@ mod from_file; use crate::from_file::impl_from_file; -use proc_macro::TokenStream; +use proc_macro::TokenStream as ProcTokenStream; +use quote::quote; +use unsynn::*; /// Implements the [`FromFile`] trait. /// /// This macro processes the `#[from_file]` attribute on structs to generate /// code for loading data from files. #[proc_macro_derive(FromFile, attributes(from_file))] -pub fn derive_from_file(input: TokenStream) -> TokenStream { +pub fn derive_from_file(input: ProcTokenStream) -> ProcTokenStream { let ts = input.into(); - impl_from_file(ts).unwrap().into() + match impl_from_file(ts) { + Ok(ts) => ts.into(), + Err(e) => error_to_compile_error(&e).into(), + } +} + +fn error_to_compile_error(err: &Error) -> TokenStream { + let msg = format_error(err); + quote! { + compile_error!(#msg); + } +} + +fn format_error(err: &Error) -> String { + let pos = err.pos(); + match &err.kind { + ErrorKind::NoError => { + format!("FromFile derive failed (internal): no error recorded (pos={pos})") + } + ErrorKind::UnexpectedToken { + expected, + at: _iter, + } => { + format!("FromFile derive parse error: expected {expected} at position {pos}",) + } + ErrorKind::Other { reason } => format!("FromFile derive error: {reason} (pos={pos})"), + ErrorKind::Dynamic(inner) => format!("FromFile derive dynamic error: {inner} (pos={pos})"), + } }