From ce5aa95a09ee2d6bf4954f3135a334f5c865461f Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 11 Sep 2022 21:47:43 +0200 Subject: [PATCH] oh yes --- Cargo.toml | 7 ++ mono-fmt-macro/Cargo.toml | 13 ++++ mono-fmt-macro/src/lib.rs | 31 ++++++++ src/lib.rs | 154 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 199 insertions(+), 6 deletions(-) create mode 100644 mono-fmt-macro/Cargo.toml create mode 100644 mono-fmt-macro/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 45cb616..f2c12fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,9 @@ +[workspace] +members = [ + ".", + "mono-fmt-macro" +] + [package] name = "mono-fmt" version = "0.1.0" @@ -6,3 +12,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +mono-fmt-macro = { path = "./mono-fmt-macro" } \ No newline at end of file diff --git a/mono-fmt-macro/Cargo.toml b/mono-fmt-macro/Cargo.toml new file mode 100644 index 0000000..09fd01c --- /dev/null +++ b/mono-fmt-macro/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "mono-fmt-macro" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +quote = "1.0.21" +syn = "1.0.99" diff --git a/mono-fmt-macro/src/lib.rs b/mono-fmt-macro/src/lib.rs new file mode 100644 index 0000000..aedb30f --- /dev/null +++ b/mono-fmt-macro/src/lib.rs @@ -0,0 +1,31 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{ + parse::{Parse, ParseStream}, + Expr, parse_macro_input, +}; + +struct Input { + format_str: String, + items: Vec, +} + +impl Parse for Input { + fn parse(input: ParseStream) -> syn::Result { + let first = input.parse::()?; + Ok(Self { + format_str: first.value(), + items: Vec::new(), + }) + } +} + +#[proc_macro] +pub fn format_args(tokens: TokenStream) -> TokenStream { + let input = parse_macro_input!(tokens as Input); + let str = input.format_str; + quote! { + (mono_fmt::_private::Str(#str),) + } + .into() +} diff --git a/src/lib.rs b/src/lib.rs index 7d12d9a..35dad59 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,156 @@ -pub fn add(left: usize, right: usize) -> usize { - left + right +pub use mono_fmt_macro::format_args; +use std::fmt::{Error, Write}; + +use crate::arguments::Arguments; + +pub type Result = std::result::Result<(), Error>; + +trait Debug { + fn fmt(&self, f: &mut Formatter) -> Result; +} + +trait Display { + fn fmt(&self, f: &mut Formatter) -> Result; +} + +impl Debug for &'_ str { + fn fmt(&self, f: &mut Formatter) -> Result { + f.write_char('"')?; + f.write_str(self)?; + f.write_char('"') + } +} + +impl Display for &'_ str { + fn fmt(&self, f: &mut Formatter) -> Result { + f.write_str(self) + } +} + +pub struct Formatter { + buf: W, +} + +impl Formatter { + fn new(buf: W) -> Self { + Self { buf } + } +} + +impl Formatter { + pub fn write_char(&mut self, char: char) -> Result { + self.buf.write_char(char) + } + + pub fn write_str(&mut self, str: &str) -> Result { + self.buf.write_str(str) + } +} + +pub fn format(args: A) -> String { + let mut string = String::new(); + let mut fmt = Formatter::new(&mut string); + args.fmt(&mut fmt).unwrap(); + string +} + +mod arguments { + use crate::{Debug, Display, Formatter, Result}; + use std::fmt::Write; + pub trait Arguments { + fn fmt(&self, f: &mut Formatter) -> Result; + } + + macro_rules! impl_arguments { + () => {}; + ($first:ident $($rest:ident)*) => { + impl<$first, $($rest),*> Arguments for ($first, $($rest),*) + where + $first: Arguments, + $($rest: Arguments),* + { + #[allow(non_snake_case)] + fn fmt(&self, f: &mut Formatter) -> Result { + let ($first, $($rest),*) = self; + Arguments::fmt($first, f)?; + $( + Arguments::fmt($rest, f)?; + )* + Ok(()) + } + } + + impl_arguments!($($rest)*); + }; + } + + #[rustfmt::skip] + impl_arguments!( + A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 + // A11 A12 A13 A14 A15 A16 A17 A18 A19 A20 + // A21 A22 A23 A24 A25 A26 A27 A28 A29 A30 + // A31 A32 A33 A34 A35 A36 A37 A38 A39 A40 + // A41 A42 A43 A44 A45 A46 A47 A48 A49 A50 + // A51 A52 A53 A54 A55 A56 A57 A58 A59 A60 + // A61 A62 A63 A64 A65 A66 A67 A68 A69 A70 + // A71 A72 A73 A74 A75 A76 A77 A78 A79 A80 + // A81 A82 A83 A84 A85 A86 A87 A88 A89 A90 + // A91 A92 A93 A94 A95 A96 A97 A98 A99 A100 + ); + + pub struct Str(pub &'static str); + + impl Arguments for Str { + fn fmt(&self, f: &mut Formatter) -> Result { + f.write_str(self.0) + } + } + + pub struct DebugArg(pub T); + + impl Arguments for DebugArg { + fn fmt(&self, f: &mut Formatter) -> Result { + Debug::fmt(&self.0, f) + } + } + + pub struct DisplayArg(pub T); + + impl Arguments for DisplayArg { + fn fmt(&self, f: &mut Formatter) -> Result { + Display::fmt(&self.0, f) + } + } +} + +mod _private { + pub use super::arguments::{DebugArg, DisplayArg, Str}; +} + +#[macro_export] +macro_rules! format { + ($($tt:tt)*) => { + $crate::format($crate::format_args!($($tt)*)) + }; } #[cfg(test)] mod tests { - use super::*; + // for the macros + use crate as mono_fmt; + + use crate::arguments::DebugArg; + use crate::format; #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); + fn hello_world() { + let result = format!("Hello, World"); + assert_eq!(result, "Hello, World"); + } + + #[test] + fn debug() { + let result = format((DebugArg("uwu"),)); + assert_eq!(result, "\"uwu\""); } }