chore: Reorganize file tree for easier onboarding. Rust project now at the root for simple git clone && cargo run

This commit is contained in:
2025-02-12 15:32:59 -05:00
parent 83b4efd625
commit 96bbef8195
144 changed files with 0 additions and 32 deletions

46
harmony_macros/Cargo.lock generated Normal file
View File

@@ -0,0 +1,46 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "harmony_macros"
version = "1.0.0"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "syn"
version = "2.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"

19
harmony_macros/Cargo.toml Normal file
View File

@@ -0,0 +1,19 @@
[package]
name = "harmony_macros"
edition = "2024"
version.workspace = true
readme.workspace = true
license.workspace = true
[lib]
proc-macro = true
[dependencies]
harmony_types = { path = "../harmony_types" }
quote = "1.0.37"
serde = "1.0.217"
serde_yaml = "0.9.34"
syn = "2.0.90"
[dev-dependencies]
serde = { version = "1.0.217", features = ["derive"] }

118
harmony_macros/src/lib.rs Normal file
View File

@@ -0,0 +1,118 @@
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use serde_yaml::Value;
use syn::LitStr;
use syn::parse_macro_input;
#[proc_macro]
pub fn ip(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as LitStr);
let ip_str = input.value();
if let Ok(_) = ip_str.parse::<std::net::Ipv4Addr>() {
let expanded =
quote! { std::net::IpAddr::V4(#ip_str.parse::<std::net::Ipv4Addr>().unwrap()) };
return TokenStream::from(expanded);
}
if let Ok(_) = ip_str.parse::<std::net::Ipv6Addr>() {
let expanded =
quote! { std::net::IpAddr::V6(#ip_str.parse::<std::net::Ipv6Addr>().unwrap()) };
return TokenStream::from(expanded);
}
panic!("Invalid IP address: {}", ip_str);
}
#[proc_macro]
pub fn ipv4(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as LitStr);
let ip_str = input.value();
if let Ok(_) = ip_str.parse::<std::net::Ipv4Addr>() {
let expanded = quote! { #ip_str.parse::<std::net::Ipv4Addr>().unwrap() };
return TokenStream::from(expanded);
}
panic!("Invalid IPv4 address: {}", ip_str);
}
#[proc_macro]
pub fn mac_address(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as LitStr);
let mac_str = input.value();
match parse_mac_address(&mac_str) {
Ok(bytes) => {
let b0 = bytes[0];
let b1 = bytes[1];
let b2 = bytes[2];
let b3 = bytes[3];
let b4 = bytes[4];
let b5 = bytes[5];
quote! {
harmony_types::net::MacAddress( [#b0, #b1, #b2, #b3, #b4, #b5] )
}
.into()
}
Err(err) => syn::Error::new(input.span(), err).to_compile_error().into(),
}
}
fn parse_mac_address(mac: &str) -> Result<[u8; 6], String> {
let parts: Vec<&str> = mac.split(':').collect();
if parts.len() != 6 {
return Err("MAC address must contain exactly six octets separated by colons".to_string());
}
let mut bytes = [0u8; 6];
for (i, part) in parts.iter().enumerate() {
match u8::from_str_radix(part, 16) {
Ok(byte) => bytes[i] = byte,
Err(_) => return Err(format!("Invalid MAC address octet: {}", part)),
}
}
Ok(bytes)
}
/// Verify that input is valid yaml by trying to deserialize it using
/// serde_yaml::from_str::<serde_yaml::value::Value>(input)
///
/// panics: If yaml is not valid
#[proc_macro]
pub fn yaml(input: TokenStream) -> TokenStream {
// TODO, accept a second argument that is the type to be deserialized to and validate at
// compile-time that deserialization is possible
//
// It does not seem to be doable with the way macros are designed : we may pass an ident to the
// macro, but the macro only has access to the ident, not the type itself.
//
// I also tried to create a restricted version of this macro, but this time serde got in the
// way : my use case is to make sure that the yaml I am given can deserialize strictly (with
// deny_unknown_attributes option on) to k8s-openapi types. But the k8s-openapi types are not
// annotated with deny_unknown_attributes and there does not seem to be a way to tell serde to
// deserialize in "strict mode" when calling the deserialization function itself. I tried
// wrapping the types in something like :
//
// ```rust
// #[derive(Deserialize, Debug)]
// #[serde(deny_unknown_fields)]
// struct Strict<T>(pub T);
// ```
//
// But it still does actually deserialize T strictly. I gave up for now at this point. Will
// find a solution some day!
let yaml = parse_macro_input!(input as LitStr);
serde_yaml::from_str::<Value>(yaml.value().as_str()).expect("Should be valid yaml");
quote! {
serde_yaml::from_str(#yaml)
}
.into()
}