69 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			69 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| ///
 | |
| /// Trying to get around "".into() for String values.
 | |
| /// Or "".to_owned().
 | |
| /// Or String::from("").
 | |
| /// Or "".to_string().
 | |
| /// Choose your church.
 | |
| ///
 | |
| /// This is as far as you will get declaratively.
 | |
| 
 | |
| #[macro_export]
 | |
| macro_rules! strinto {
 | |
|     ($struct:ident { $($field:ident : $value:expr),* $(,)? }) => {
 | |
|         $struct {
 | |
|             $(
 | |
|                 $field: $crate::strinto!(@convert $value),
 | |
|             )*
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     (@convert $value:literal) => {
 | |
|         match () {
 | |
|             _ if stringify!($value).starts_with("\"") => {
 | |
|                 $value.to_string()
 | |
|             },
 | |
|             _ => $value.into(), // <-- no getting rid of the into!
 | |
|         }
 | |
|     };
 | |
| }
 | |
| 
 | |
| struct SomeStruct {
 | |
|     first_name: String,
 | |
|     //last_name: String, // NOPE because of @convert.
 | |
|     //age: usize, // reason of .into() in the first place.
 | |
| }
 | |
| 
 | |
| pub fn main() {
 | |
|     let x = strinto!(SomeStruct {
 | |
|         first_name: "First",
 | |
|         //last_name: String::from("Last"), // NOPE 2.
 | |
|         //age: 1, // NOPE 1. But I went further.
 | |
|     });
 | |
| }
 | |
| 
 | |
| // while this compiles for only &str "", it is also useless compared to into!
 | |
| // the reason is, that you cannot type check in the declarative macros.
 | |
| // while yes, you would conditionally run stringify!($value) in the match, but the match expansion
 | |
| // will always lead you to type errors if you don't do an .into() in the other arm.
 | |
| // also in the end it fails to compile for anything but all members of the struct being Strings.
 | |
| 
 | |
| // the last idea was going with a helper trait, but that will bleed into the runtime code, and yet again only work on pure String structs.
 | |
| 
 | |
| // I guess I have to embrace String::from(), .to_string(), .to_owned(), .into() madness, for something every human reader can deduce in a second,
 | |
| // if you would just implicitly convert &str to String if literally written in the code.
 | |
| 
 | |
| // It is kinda amusing, that the other solution, to use new() kind of turns me off, because I cannot be explicit about the parameter name in the call.
 | |
| // I would literally love the option to be more explicit in function param names.
 | |
| 
 | |
| // while builder patterns feel a bit bloated for static runtime options, i will probably look into automations for that.
 | |
| 
 | |
| // this is probably the only aesthetic decision in rust I probably will hate forever.
 | |
| // It does not make sense, Strings as literals already are special in your code.
 | |
| // Because numbers are as well, you dont have to write 123.into() either.
 | |
| // I know I probably made some really harsh logical mistakes in my opinion here, and maybe it can be proven, that I am wrong, and I would love to hear that
 | |
| // However it kind of feels like an excuse to not simplify assigning declaratively written &str to Strings in the code.
 | |
| 
 | |
| // And it makes sense to be explicit about creating a String Buffer sometimes, but it does not make sense mostly.
 | |
| 
 | |
| // Anyway, I will still try a procedural macro for this, just for fun.
 |