omega restructuring + a bunch of changes i have made over the last weeks
This commit is contained in:
13
macros/Cargo.toml
Normal file
13
macros/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "mize_macros"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "1.0.44"
|
||||
syn = "2.0.114"
|
||||
proc-macro2 = "1.0"
|
||||
ciborium = "0.2"
|
||||
1
macros/src/data.rs
Normal file
1
macros/src/data.rs
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
280
macros/src/lib.rs
Normal file
280
macros/src/lib.rs
Normal file
@@ -0,0 +1,280 @@
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{Data, DeriveInput, Fields, parse_macro_input};
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn mize_part(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(item as DeriveInput);
|
||||
let struct_name = &input.ident;
|
||||
|
||||
// Parse name from attribute
|
||||
let part_name = if !attr.is_empty() {
|
||||
let lit: syn::LitStr = parse_macro_input!(attr);
|
||||
lit.value()
|
||||
} else {
|
||||
struct_name.to_string().to_lowercase()
|
||||
};
|
||||
|
||||
// Verify mize field exists
|
||||
let has_mize = match &input.data {
|
||||
Data::Struct(s) => match &s.fields {
|
||||
Fields::Named(f) => f
|
||||
.named
|
||||
.iter()
|
||||
.any(|field| field.ident.as_ref().map(|i| i == "mize").unwrap_or(false)),
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if !has_mize {
|
||||
return syn::Error::new_spanned(struct_name, "Struct must have a 'mize: Mize' field")
|
||||
.to_compile_error()
|
||||
.into();
|
||||
}
|
||||
|
||||
let part_getter_fn_name_str = format!("make_mize_part_{}", part_name);
|
||||
let part_getter_fn_name = syn::Ident::new(&part_getter_fn_name_str, struct_name.span());
|
||||
|
||||
let expanded = quote! {
|
||||
#input
|
||||
|
||||
// impl the default new impl
|
||||
impl mize::MizePartGenerated for #struct_name {
|
||||
fn name_generated(&self) -> &'static str {
|
||||
#part_name
|
||||
}
|
||||
fn get_mize_generated(&mut self) -> &mut Mize {
|
||||
&mut self.mize
|
||||
}
|
||||
fn as_any_generated(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn as_any_mut_generated(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn into_any_generated(self: Box<Self>) -> Box<dyn std::any::Any> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl mize::MizePartCreateGenerated for #struct_name {
|
||||
fn create_generated(mize: Mize) -> Self {
|
||||
Self {
|
||||
mize,
|
||||
.. Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use mize::instance::MizePartCreateThisSucks;
|
||||
|
||||
impl MizePartCreateThisSucks for #struct_name {}
|
||||
|
||||
// the function to get the part from a .so file
|
||||
#[unsafe(no_mangle)]
|
||||
extern "C" fn #part_getter_fn_name(part: &mut Box<dyn MizePart + Send + Sync>, mut mize: Mize) {
|
||||
#struct_name::create_this_sucks(&mut mize);
|
||||
}
|
||||
|
||||
/*
|
||||
impl std::ops::Deref for mize::MizePartGuard<#struct_name> {
|
||||
type Target = #struct_name;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&*self.part.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::DerefMut for mize::MizePartGuard<#struct_name> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut *self.part.as_mut().unwrap()
|
||||
}
|
||||
}
|
||||
*/
|
||||
};
|
||||
|
||||
TokenStream::from(expanded)
|
||||
}
|
||||
|
||||
//////////////////////////////////// data! macro ///////////////////////////////////////
|
||||
// A procedural macro to define data in Nix-style and expand to a `ciborium::Value` (CBOR).
|
||||
//
|
||||
// Add this to your `Cargo.toml`:
|
||||
// ```toml
|
||||
// [lib]
|
||||
// proc-macro = true
|
||||
//
|
||||
// [dependencies]
|
||||
// syn = { version = "2.0", features = ["full", "extra-traits"] }
|
||||
// quote = "1.0"
|
||||
// proc-macro2 = "1.0"
|
||||
// ciborium = "0.2"
|
||||
// ```
|
||||
|
||||
use syn::{Ident, Lit, Token, parse::Parse, parse::ParseStream, punctuated::Punctuated, token};
|
||||
|
||||
// --- AST ---
|
||||
|
||||
#[derive(Debug)]
|
||||
enum NixExpr {
|
||||
Map(Vec<(String, NixExpr)>),
|
||||
List(Vec<NixExpr>),
|
||||
Literal(Literal),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Literal {
|
||||
String(String),
|
||||
Int(i128),
|
||||
Float(f64),
|
||||
Bool(bool),
|
||||
Null,
|
||||
}
|
||||
|
||||
// --- Code Generation ---
|
||||
|
||||
impl NixExpr {
|
||||
fn to_cbor_tokens(&self) -> proc_macro2::TokenStream {
|
||||
match self {
|
||||
NixExpr::Map(entries) => {
|
||||
let entry_tokens: Vec<_> = entries
|
||||
.iter()
|
||||
.map(|(k, v)| {
|
||||
let key = syn::LitStr::new(k, proc_macro2::Span::call_site());
|
||||
let value_tokens = v.to_cbor_tokens();
|
||||
quote! {
|
||||
(mize::ciborium::Value::Text(#key.to_string()), #value_tokens)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
quote! {
|
||||
mize::ciborium::Value::Map({
|
||||
let mut m = Vec::<(mize::ciborium::Value, mize::ciborium::Value)>::new();
|
||||
#(m.push(#entry_tokens);)*
|
||||
m
|
||||
})
|
||||
}
|
||||
}
|
||||
NixExpr::List(items) => {
|
||||
let item_tokens: Vec<_> = items.iter().map(|item| item.to_cbor_tokens()).collect();
|
||||
quote! {
|
||||
mize::ciborium::Value::Array({
|
||||
let mut v = Vec::<mize::ciborium::Value>::new();
|
||||
#(v.push(#item_tokens);)*
|
||||
v
|
||||
})
|
||||
}
|
||||
}
|
||||
NixExpr::Literal(lit) => lit.to_cbor_tokens(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Literal {
|
||||
fn to_cbor_tokens(&self) -> proc_macro2::TokenStream {
|
||||
match self {
|
||||
Literal::String(s) => {
|
||||
let s = syn::LitStr::new(s, proc_macro2::Span::call_site());
|
||||
quote! { mize::ciborium::Value::Text(#s.to_string()) }
|
||||
}
|
||||
Literal::Int(i) => quote! { mize::ciborium::Value::Integer(#i) },
|
||||
Literal::Float(f) => quote! { mize::ciborium::Value::Float(#f) },
|
||||
Literal::Bool(b) => quote! { mize::ciborium::Value::Bool(#b) },
|
||||
Literal::Null => quote! { mize::ciborium::Value::Null },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Parsing ---
|
||||
|
||||
struct NixKeyValue {
|
||||
key: Ident,
|
||||
_eq: Token![=],
|
||||
value: NixExpr,
|
||||
}
|
||||
|
||||
impl Parse for NixKeyValue {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
Ok(NixKeyValue {
|
||||
key: input.parse()?,
|
||||
_eq: input.parse()?,
|
||||
value: input.parse()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for NixExpr {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
// Parse a map: { a = 1; b = 2; }
|
||||
if input.peek(token::Brace) {
|
||||
let content;
|
||||
syn::braced!(content in input);
|
||||
let pairs = Punctuated::<NixKeyValue, Token![;]>::parse_terminated(&content)?;
|
||||
let entries = pairs
|
||||
.into_iter()
|
||||
.map(|kv| (kv.key.to_string(), kv.value))
|
||||
.collect();
|
||||
return Ok(NixExpr::Map(entries));
|
||||
}
|
||||
|
||||
// Parse a list: [ 1, 2, 3 ]
|
||||
if input.peek(token::Bracket) {
|
||||
let content;
|
||||
syn::bracketed!(content in input);
|
||||
let items = Punctuated::<NixExpr, Token![,]>::parse_terminated(&content)?;
|
||||
return Ok(NixExpr::List(items.into_iter().collect()));
|
||||
}
|
||||
|
||||
// Parse literals
|
||||
if input.peek(Lit) {
|
||||
let lit = input.parse::<Lit>()?;
|
||||
return match lit {
|
||||
Lit::Str(s) => Ok(NixExpr::Literal(Literal::String(s.value()))),
|
||||
Lit::Int(i) => Ok(NixExpr::Literal(Literal::Int(i.base10_parse::<i128>()?))),
|
||||
Lit::Float(f) => Ok(NixExpr::Literal(Literal::Float(f.base10_parse::<f64>()?))),
|
||||
Lit::Bool(b) => Ok(NixExpr::Literal(Literal::Bool(b.value))),
|
||||
_ => Err(input.error("Unsupported literal")),
|
||||
};
|
||||
}
|
||||
|
||||
Err(input.error("Expected a Nix expression (map, list, or literal)"))
|
||||
}
|
||||
}
|
||||
|
||||
// --- Top-level AttrSet Parsing ---
|
||||
|
||||
struct NixAttrSet(Vec<NixKeyValue>);
|
||||
|
||||
impl syn::parse::Parse for NixAttrSet {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let pairs = Punctuated::<NixKeyValue, Token![;]>::parse_terminated(input)?;
|
||||
Ok(NixAttrSet(pairs.into_iter().collect()))
|
||||
}
|
||||
}
|
||||
|
||||
// --- Macro Entry ---
|
||||
|
||||
#[proc_macro]
|
||||
pub fn data(input: TokenStream) -> TokenStream {
|
||||
// Try to parse top-level attrset (without outer braces)
|
||||
let expr = syn::parse::<NixAttrSet>(input.clone())
|
||||
.map(|attrset| {
|
||||
NixExpr::Map(
|
||||
attrset.0
|
||||
.into_iter()
|
||||
.map(|kv| (kv.key.to_string(), kv.value))
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
.or_else(|_| {
|
||||
// fallback: parse legacy behavior (braced map, list, or literal)
|
||||
syn::parse::<NixExpr>(input)
|
||||
});
|
||||
|
||||
let tokens = match expr {
|
||||
Ok(expr) => expr.to_cbor_tokens(),
|
||||
Err(e) => return e.to_compile_error().into(),
|
||||
};
|
||||
TokenStream::from(tokens)
|
||||
}
|
||||
Reference in New Issue
Block a user