From d0d81af796c9bcd778618acfa4f2000060f0d509 Mon Sep 17 00:00:00 2001 From: Jean-Gabriel Gill-Couture Date: Tue, 17 Dec 2024 09:54:23 -0500 Subject: [PATCH] feat(macro): Add mac_address macro --- harmony-rs/Cargo.lock | 1 + .../harmony/src/infra/opnsense/management.rs | 6 +-- harmony-rs/harmony_macros/Cargo.toml | 1 + harmony-rs/harmony_macros/src/lib.rs | 49 +++++++++++++++++-- 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/harmony-rs/Cargo.lock b/harmony-rs/Cargo.lock index 2c2c29b..dc80e38 100644 --- a/harmony-rs/Cargo.lock +++ b/harmony-rs/Cargo.lock @@ -909,6 +909,7 @@ dependencies = [ name = "harmony_macros" version = "1.0.0" dependencies = [ + "harmony", "quote", "syn 2.0.90", ] diff --git a/harmony-rs/harmony/src/infra/opnsense/management.rs b/harmony-rs/harmony/src/infra/opnsense/management.rs index ce0c6b9..81f062f 100644 --- a/harmony-rs/harmony/src/infra/opnsense/management.rs +++ b/harmony-rs/harmony/src/infra/opnsense/management.rs @@ -3,9 +3,7 @@ use derive_new::new; use crate::{hardware::ManagementInterface, topology::MacAddress}; #[derive(new)] -pub struct OPNSenseManagementInterface { - mac: MacAddress, -} +pub struct OPNSenseManagementInterface {} impl ManagementInterface for OPNSenseManagementInterface { fn boot_to_pxe(&self) { @@ -13,7 +11,7 @@ impl ManagementInterface for OPNSenseManagementInterface { } fn get_mac_address(&self) -> MacAddress { - self.mac.clone() + todo!("OPNSense can have multiple mac addresses using SSH. I'm not sure it even belongs in the ManagementInterface trait") } fn get_supported_protocol_names(&self) -> String { diff --git a/harmony-rs/harmony_macros/Cargo.toml b/harmony-rs/harmony_macros/Cargo.toml index 8dbebeb..e43389c 100644 --- a/harmony-rs/harmony_macros/Cargo.toml +++ b/harmony-rs/harmony_macros/Cargo.toml @@ -7,5 +7,6 @@ version = "1.0.0" proc-macro = true [dependencies] +harmony = { version = "0.1.0", path = "../harmony" } quote = "1.0.37" syn = "2.0.90" diff --git a/harmony-rs/harmony_macros/src/lib.rs b/harmony-rs/harmony_macros/src/lib.rs index 3ea6a40..6a86640 100644 --- a/harmony-rs/harmony_macros/src/lib.rs +++ b/harmony-rs/harmony_macros/src/lib.rs @@ -1,8 +1,9 @@ extern crate proc_macro; +use harmony::topology::MacAddress; use proc_macro::TokenStream; use quote::quote; -use syn::{parse_macro_input, LitStr}; +use syn::{LitStr, parse_macro_input}; #[proc_macro] pub fn ip(input: TokenStream) -> TokenStream { @@ -10,14 +11,56 @@ pub fn ip(input: TokenStream) -> TokenStream { let ip_str = input.value(); if let Ok(_) = ip_str.parse::() { - let expanded = quote! { std::net::IpAddr::V4(#ip_str.parse::().unwrap()) }; + let expanded = + quote! { std::net::IpAddr::V4(#ip_str.parse::().unwrap()) }; return TokenStream::from(expanded); } if let Ok(_) = ip_str.parse::() { - let expanded = quote! { std::net::IpAddr::V4(#ip_str.parse::().unwrap()) }; + let expanded = + quote! { std::net::IpAddr::V4(#ip_str.parse::().unwrap()) }; return TokenStream::from(expanded); } panic!("Invalid IP 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! { + 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) +}