1mod config; 2mod encode; 3mod enums; 4mod partialclone; 5mod serialization; 6 7use proc_macro::TokenStream; 8 9/// Implement the `std::fmt::Display` trait for the given enum. Only supports enums which have only 10/// fieldless variants. 11/// 12/// This macro also implements a method `to_str(&self) -> &'static str` for cases where an owned 13/// String is not needed. 14/// 15/// # Panics 16/// 17/// This macro will panic if applied to a struct, a union, or an enum with any variants that have 18/// fields. 19#[proc_macro_derive(EnumDisplay)] 20pub fn enum_display(input: TokenStream) -> TokenStream { 21 enums::enum_display(input) 22} 23 24/// Implement the `std::str::FromStr` trait for the given enum, with `FromStr::Err` set to `String`. 25/// Only supports enums which have only fieldless variants. The generated implementation will be 26/// case-insensitive. 27/// 28/// # Panics 29/// 30/// This macro will panic if applied to a struct, a union, or an enum with any variants that have 31/// fields. 32#[proc_macro_derive(EnumFromStr)] 33pub fn enum_from_str(input: TokenStream) -> TokenStream { 34 enums::enum_from_str(input) 35} 36 37/// On an enum with only fieldless variants, add an `ALL` constant of type `[Self; N]` that contains 38/// every variant of the enum. The variant order in `ALL` will equal the variant declaration order. 39/// 40/// Example: 41/// ``` 42/// use jgenesis_proc_macros::EnumAll; 43/// 44/// #[derive(Debug, PartialEq, EnumAll)] 45/// enum Foo { 46/// A, 47/// B, 48/// C, 49/// } 50/// 51/// // Explicit type for clarity 52/// let expected: [Foo; 3] = [Foo::A, Foo::B, Foo::C]; 53/// assert_eq!(Foo::ALL, expected); 54/// ``` 55/// 56/// # Panics 57/// 58/// This macro will panic if applied to a struct, a union, or an enum with non-fieldless variants. 59#[proc_macro_derive(EnumAll)] 60pub fn enum_all(input: TokenStream) -> TokenStream { 61 enums::enum_all(input) 62} 63 64/// Implement the `clap::ValueEnum` trait for a struct, using a custom implementation rather than 65/// the one provided by `derive(clap::ValueEnum)`. 66/// 67/// The implementation differs only in the string values generated. Where `derive(clap::ValueEnum)` 68/// lowercases variant names and inserts a `-` character at every word break, this implementation 69/// uses the variant name directly. 70/// 71/// This macro requires that the [`EnumAll`] and [`EnumDisplay`] macros are also used. 72#[proc_macro_derive(CustomValueEnum, attributes(value_enum))] 73pub fn custom_value_enum(input: TokenStream) -> TokenStream { 74 enums::custom_value_enum(input) 75} 76 77/// Implement the `std::fmt::Display` trait for a struct, with an implementation meant for 78/// pretty-printing configs. By default all fields are printed using their own `std::fmt::Display` 79/// implementation. 80/// 81/// For example: 82/// ``` 83/// use jgenesis_proc_macros::ConfigDisplay; 84/// 85/// #[derive(ConfigDisplay)] 86/// struct Config { 87/// foo: u32, 88/// bar: String, 89/// } 90/// 91/// // This prints the following output: 92/// // config: 93/// // foo: 5 94/// // bar: asdf 95/// let s = format!("config: {}", Config { foo: 5, bar: "asdf".into() }); 96/// assert_eq!(s, "config: \n foo: 5\n bar: asdf".to_owned()); 97/// ``` 98/// 99/// The `#[cfg_display(debug_fmt)]` attribute can be used to indicate that a field should be formatted using its 100/// `std::fmt::Debug` implementation rather than its `std::fmt::Display` implementation. For example: 101/// ``` 102/// use jgenesis_proc_macros::ConfigDisplay; 103/// 104/// #[derive(Debug)] 105/// struct NotDisplay(String); 106/// 107/// #[derive(ConfigDisplay)] 108/// struct Config { 109/// bar: bool, 110/// #[cfg_display(debug_fmt)] 111/// baz: NotDisplay, 112/// } 113/// 114/// // This prints the following output: 115/// // config: 116/// // foo: Some(5) 117/// // bar: true 118/// // baz: NotDisplay("fdsa") 119/// let config = Config { 120/// bar: true, 121/// baz: NotDisplay("fdsa".into()), 122/// }; 123/// let s = format!("config: {config}"); 124/// assert_eq!(s, "config: \n bar: true\n baz: NotDisplay(\"fdsa\")"); 125/// ``` 126/// 127/// The `#[cfg_display(indent_nested)]` attribute allows indenting when printing a field that also implements 128/// the `Display` trait through this macro: 129/// ``` 130/// use jgenesis_proc_macros::ConfigDisplay; 131/// 132/// #[derive(ConfigDisplay)] 133/// struct Inner { 134/// foo: u32, 135/// } 136/// 137/// #[derive(ConfigDisplay)] 138/// struct Outer { 139/// bar: u32, 140/// #[cfg_display(indent_nested)] 141/// inner: Inner, 142/// baz: u32, 143/// } 144/// 145/// // This prints the following output: 146/// // config: 147/// // bar: 3 148/// // inner: 149/// // foo: 4 150/// // baz: 5 151/// let config = Outer { 152/// bar: 3, 153/// inner: Inner { foo: 4 }, 154/// baz: 5, 155/// }; 156/// let s = format!("config: {config}"); 157/// assert_eq!(s, "config: \n bar: 3\n inner: \n foo: 4\n baz: 5"); 158/// ``` 159/// 160/// Options will automatically be formatted by unwrapping if the value is Some(v) and printing 161/// the string "<None>" if the value is None: 162/// ``` 163/// use jgenesis_proc_macros::ConfigDisplay; 164/// 165/// #[derive(ConfigDisplay)] 166/// struct Config { 167/// a: Option<String>, 168/// b: Option<u32>, 169/// } 170/// 171/// // This prints the following output: 172/// // config: 173/// // a: hello 174/// // b: <None> 175/// let config = Config { a: Some("hello".into()), b: None }; 176/// let s = format!("config: {config}"); 177/// assert_eq!(s, "config: \n a: hello\n b: <None>"); 178/// ``` 179/// 180/// # Panics 181/// 182/// This macro only supports structs with named fields and it will panic if applied to any other 183/// data type, including structs with no fields. 184#[proc_macro_derive(ConfigDisplay, attributes(cfg_display))] 185pub fn config_display(input: TokenStream) -> TokenStream { 186 config::config_display(input) 187} 188 189/// Implements the `bincode::Encode` trait fpr the given type, with a fake implementation that 190/// does not encode anything and always returns `Ok(())`. 191/// 192/// # Panics 193/// 194/// This macro will panic only if it is unable to parse its input. 195#[proc_macro_derive(FakeEncode)] 196pub fn fake_encode(input: TokenStream) -> TokenStream { 197 encode::fake_encode(input) 198} 199 200/// Implements the `bincode::Decode` and `bincode::BorrowDecode` traits for the given type, 201/// with fake implementations that do not decode anything and always return `Ok(Self::default())`. 202/// 203/// The type must have a `default()` associated function, preferably through implementing the 204/// `Default` trait. 205/// 206/// # Panics 207/// 208/// This macro will panic only if it is unable to parse its input. 209#[proc_macro_derive(FakeDecode)] 210pub fn fake_decode(input: TokenStream) -> TokenStream { 211 encode::fake_decode(input) 212} 213 214/// Implement the `jgenesis_common::frontend::PartialClone` trait for a given struct or enum. 215/// 216/// This macro should be imported through `jgenesis_common` instead of directly from this crate so 217/// that both the macro and the trait are imported. 218/// 219/// Fields that are not marked with a `#[partial_clone]` attribute will be cloned using that type's 220/// implementation of the `Clone` trait. 221/// 222/// Fields that are marked with `#[partial_clone(default)]` will not be cloned, and instead the 223/// partial clone will contain the default value for that type (via the `Default` trait). 224/// 225/// Fields that are marked with `#[partial_clone(partial)]` will be cloned using that type's 226/// implementation of the `PartialClone` trait. 227/// 228/// If the struct has any generic type parameters, the `PartialClone` trait will only be implemented 229/// where all of the generic types implement `PartialClone`. 230/// 231/// Example: 232/// ``` 233/// use jgenesis_common::frontend::PartialClone; 234/// 235/// #[derive(Debug, PartialEq, PartialClone)] 236/// struct Nested(Vec<u8>, #[partial_clone(default)] Vec<u16>, String); 237/// 238/// #[derive(Debug, PartialEq, PartialClone)] 239/// struct UnnamedFields(Vec<u8>, #[partial_clone(default)] Vec<u16>, #[partial_clone(partial)] Nested); 240/// 241/// let inner = Nested(vec![1, 2, 3], vec![4, 5, 6], "hello".into()); 242/// let outer = UnnamedFields(vec![7, 8, 9], vec![10, 11, 12], inner); 243/// 244/// let expected = UnnamedFields(vec![7, 8, 9], vec![], Nested(vec![1, 2, 3], vec![], "hello".into())); 245/// assert_eq!(outer.partial_clone(), expected); 246/// ``` 247/// 248/// # Panics 249/// 250/// This macro currently only supports structs and enums, and it will panic if applied to a union. 251#[proc_macro_derive(PartialClone, attributes(partial_clone))] 252pub fn partial_clone(input: TokenStream) -> TokenStream { 253 partialclone::partial_clone(input) 254} 255 256/// This macro is fairly specific to the NES Mapper enum, although it could theoretically 257/// be more generalized if needed. 258/// 259/// This macro is meant for use with enums in which every variant has exactly one field, and those 260/// fields have different concrete types but extremely similar APIs (e.g. perhaps they all implement 261/// a given trait). 262/// 263/// It generates a declarative macro called `match_each_variant` that generates an enum match 264/// expression and always takes three parameters: the value to match on, the identifier to bind the 265/// single unnamed field to, and an expression to use as the match arm for every variant. 266/// 267/// Example usage: 268/// ``` 269/// use jgenesis_proc_macros::MatchEachVariantMacro; 270/// 271/// #[derive(MatchEachVariantMacro)] 272/// enum Example { 273/// VariantA(u16), 274/// VariantB(u32), 275/// VariantC(u64), 276/// } 277/// 278/// impl Example { 279/// fn add_20(&self) -> u64 { 280/// match_each_variant!(*self, number => u64::from(number) + 20) 281/// } 282/// } 283/// 284/// assert_eq!(25_u64, Example::VariantA(5).add_20()); 285/// assert_eq!(30_u64, Example::VariantB(10).add_20()); 286/// assert_eq!(35_u64, Example::VariantC(15).add_20()); 287/// ``` 288/// 289/// The macro can optionally wrap the match arm expression in the variant constructor by using the 290/// `:variant` marker: 291/// ``` 292/// use jgenesis_proc_macros::MatchEachVariantMacro; 293/// 294/// #[derive(Debug, PartialEq, Eq, MatchEachVariantMacro)] 295/// enum Example { 296/// VariantA(u16), 297/// VariantB(u32), 298/// } 299/// 300/// impl Example { 301/// fn add_20(&self) -> Self { 302/// match_each_variant!(*self, number => :variant(number + 20)) 303/// } 304/// } 305/// 306/// assert_eq!(Example::VariantA(25), Example::VariantA(5).add_20()); 307/// assert_eq!(Example::VariantB(120), Example::VariantB(100).add_20()); 308/// ``` 309/// 310/// # Panics 311/// 312/// This macro will panic if applied to a struct, a union, or an enum in which not every variant 313/// has exactly one unnamed field. 314#[proc_macro_derive(MatchEachVariantMacro)] 315pub fn match_each_variant_macro(input: TokenStream) -> TokenStream { 316 enums::match_each_variant_macro(input) 317} 318 319/// Augment a struct definition such that when deserializing a struct value using serde, if any 320/// errors are encountered while deserializing a field, the deserializer will set that field based 321/// on the struct's [`Default::default()`] implementation instead of propagating the error. 322/// 323/// This macro can only be applied to struct definitions, not enums or unions. It also only supports 324/// structs with named fields, not tuple structs. The struct cannot have any generic parameters. 325/// 326/// The struct must implement the [`Default`] trait and it must use the [`serde::Deserialize`] derive 327/// macro. 328/// 329/// The macro adds a `#[serde(deserialize_with = ...)]` attribute to each field, so no fields can 330/// already have that attribute or else the generated code will not compile. 331/// 332/// At runtime, all deserialization errors encountered will be logged at ERROR level. 333/// 334/// Example usage: 335/// ``` 336/// use jgenesis_proc_macros::deserialize_default_on_error; 337/// 338/// #[deserialize_default_on_error] 339/// #[derive(Debug, PartialEq, Eq, serde::Deserialize)] 340/// #[serde(default)] 341/// struct Foo { 342/// a: u32, 343/// b: String, 344/// } 345/// 346/// impl Default for Foo { 347/// fn default() -> Self { 348/// Self { a: 5, b: "hello".into() } 349/// } 350/// } 351/// 352/// const TOML_INVALID_A: &str = r#" 353/// a = "not a number" 354/// b = "world" 355/// "#; 356/// 357/// let foo: Foo = toml::from_str(TOML_INVALID_A).unwrap(); 358/// assert_eq!(foo, Foo { a: 5, b: "world".into() }); 359/// ``` 360#[proc_macro_attribute] 361pub fn deserialize_default_on_error(_attrs: TokenStream, input: TokenStream) -> TokenStream { 362 serialization::deserialize_default_on_error(input) 363}