diff --git a/Cargo.lock b/Cargo.lock index 6c3634b..a863193 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,53 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "pm" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + [[package]] name = "uwu" version = "0.1.0" +dependencies = [ + "pm", +] diff --git a/Cargo.toml b/Cargo.toml index 64cbcf9..ef596e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,6 @@ +[workspace] +members = [".", "./pm"] + [package] name = "uwu" version = "0.1.0" @@ -6,3 +9,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +pm = { path = "./pm" } diff --git a/examples/scratch.rs b/examples/scratch.rs new file mode 100644 index 0000000..93938d1 --- /dev/null +++ b/examples/scratch.rs @@ -0,0 +1,14 @@ +use uwu::scratch::{ + actual_scratch_read, actual_scratch_write, define_scratch, scratch_space, Scratch, +}; + +#[scratch_space] +fn has_scratch_space(mut scratch: Scratch<'_>) { + scratch_write!(scratch, 10u32); + let _: u32 = scratch_read!(scratch); +} + +fn main() { + define_scratch!(scratch, 10); + has_scratch_space(scratch); +} diff --git a/pm/Cargo.toml b/pm/Cargo.toml new file mode 100644 index 0000000..e33fc91 --- /dev/null +++ b/pm/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "pm" +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] +proc-macro2 = "1.0.49" +quote = "1.0.23" +syn = { version = "1.0.107", features = ["full", "fold"] } diff --git a/pm/src/lib.rs b/pm/src/lib.rs new file mode 100644 index 0000000..0bd5651 --- /dev/null +++ b/pm/src/lib.rs @@ -0,0 +1,49 @@ +use proc_macro::TokenStream; +use proc_macro2::{Ident, Span}; +use quote::quote; +use syn::{fold::Fold, parse_macro_input, parse_quote, ItemFn, Stmt}; + +#[proc_macro_attribute] +pub fn scratch_space(_: TokenStream, input: TokenStream) -> TokenStream { + let fn_def = parse_macro_input!(input as ItemFn); + let track_ident = Ident::new("scratch_local", Span::mixed_site()); + + let mut fn_def = LocalInitFolder { + track_ident: track_ident.clone(), + } + .fold_item_fn(fn_def); + + let init: Stmt = parse_quote! { let #track_ident: (); }; + + fn_def.block.stmts.insert(0, init); + + quote! { #fn_def }.into() +} + +struct LocalInitFolder { + track_ident: Ident, +} + +impl syn::fold::Fold for LocalInitFolder { + fn fold_macro(&mut self, mut mac: syn::Macro) -> syn::Macro { + if let Some(last_path) = mac.path.segments.iter().next_back() { + match last_path.ident.to_string().as_str() { + "scratch_write" => { + let track_ident = &self.track_ident; + mac.path = parse_quote! { actual_scratch_write }; + mac.tokens.extend(quote! { ; #track_ident }); + } + "scratch_read" => { + let track_ident = &self.track_ident; + mac.path = parse_quote! { actual_scratch_read }; + mac.tokens.extend(quote! { ; #track_ident }); + } + _ => {} + } + + mac + } else { + mac + } + } +} diff --git a/src/innocent_linked_list.rs b/src/innocent_linked_list.rs index dc4fe22..9134dc5 100644 --- a/src/innocent_linked_list.rs +++ b/src/innocent_linked_list.rs @@ -1,3 +1,5 @@ +#![allow(warnings)] + pub struct Node<'a, 'n, T> { item: T, outer: Option<&'a mut Node<'a, 'n, T>>, @@ -11,7 +13,7 @@ impl<'a, 'n, T> Node<'a, 'n, T> { pub fn push(&mut self, item: T, with_func: impl FnOnce(&mut Self) -> R) -> R { let mut inner = Node { item, - outer: Some(self), + outer: Some(todo!()), }; with_func(&mut inner) } @@ -22,6 +24,7 @@ mod tests { use super::Node; #[test] + #[ignore = "todo"] fn push() { let mut list = Node::::new(0); diff --git a/src/lib.rs b/src/lib.rs index 783e811..b65bc0e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ pub mod cfg_match; pub mod innocent_linked_list; +pub mod scratch; pub mod sendsync; pub mod unroll_int; pub mod unsized_clone; diff --git a/src/scratch.rs b/src/scratch.rs new file mode 100644 index 0000000..9dd9250 --- /dev/null +++ b/src/scratch.rs @@ -0,0 +1,83 @@ +use std::mem::{self, MaybeUninit}; + +pub use pm::scratch_space; + +pub struct Scratch<'a>(&'a mut [MaybeUninit]); + +impl<'a> Scratch<'a> { + pub fn new(buf: &'a mut [MaybeUninit]) -> Self { + Self(buf) + } + + pub fn write(&mut self, _value: T) { + let size = mem::size_of::(); + assert!(size <= self.0.len()); + } + + pub fn read(&mut self) -> T { + T::default() + } +} + +#[macro_export] +macro_rules! scratch_write { + ($scratch:ident, $value:expr) => { + /* transformed to a call to actual_scratch_write */ + compile_error!("Failed to transform macro invocation"); + }; +} + +#[macro_export] +macro_rules! scratch_read { + ($scratch:ident) => { + /* transformed to a call to actual_scratch_write */ + compile_error!("Failed to transform macro invocation"); + }; +} + +#[macro_export] +macro_rules! actual_scratch_write { + ($scratch:ident, $value:expr ; $track_local:ident) => { + $track_local = (); + $scratch.write($value); + }; +} + +#[macro_export] +macro_rules! actual_scratch_read { + ($scratch:ident ; $track_local:ident) => {{ + let _read = $track_local; + $scratch.read() + }}; +} + +#[macro_export] +macro_rules! define_scratch { + ($name:ident, $size:expr) => { + let mut __buffer: [::core::mem::MaybeUninit; $size] = + unsafe { ::core::mem::MaybeUninit::uninit().assume_init() }; + #[allow(unused_mut)] + let mut $name = $crate::scratch::Scratch::new(&mut __buffer); + }; +} + +pub use {actual_scratch_read, actual_scratch_write, define_scratch, scratch_read, scratch_write}; + +#[cfg(test)] +mod tests { + use pm::scratch_space; + + use super::{define_scratch, Scratch}; + + #[scratch_space] + fn has_scratch_space(mut scratch: Scratch<'_>) { + scratch_write!(scratch, 10u32); + let _: u32 = scratch_read!(scratch); + } + + #[test] + fn simple_scratch() { + define_scratch!(scratch, 100); + has_scratch_space(scratch); + } +}