Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 103 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 3 additions & 14 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
[package]
name = "athena"
# versions
version = "0.1.0"
edition = "2024"
rust-version = "1.95.0"
# info
authors = ["commanderxa"]
readme = "README.md"
repository = "https://github.com/CommanderXA/athena"
license-file = "LICENSE.txt"
[workspace]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
members = ["delta", "delta-macros", "delta-py"]

[dependencies]
rand = "0.10.1"
resolver = "2"
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
py_develop:
cd ./delta-py && maturin develop --uv

py_release:
cd ./delta-py && maturin build --release
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@

<br>

<h1 align="left">The <b>ATHENA</b> Project</h1>
<h1 align="left">The <b>DELTA</b> Project</h1>

<div align="left">
<a href="https://github.com/commanderxa/athena">
<a href="https://github.com/commanderxa/delta">
<img src="https://img.shields.io/badge/Rust-1.95.0%2B-000000?style=for-the-badge&logo=rust&logoColor=white" alt="Rust 1.95.0+">
</a>
<a href="https://github.com/commanderxa/athena/actions">
<img src="https://img.shields.io/github/actions/workflow/status/commanderxa/athena/rust.yml?branch=master&style=for-the-badge&logo=githubactions&logoColor=white&label=Build" alt="Build">
<a href="https://github.com/commanderxa/delta/actions">
<img src="https://img.shields.io/github/actions/workflow/status/commanderxa/delta/rust.yml?branch=master&style=for-the-badge&logo=githubactions&logoColor=white&label=Build" alt="Build">
</a>
<a href="https://github.com/commanderxa/athena/stargazers">
<img src="https://img.shields.io/github/stars/commanderxa/athena?style=for-the-badge&logo=github&logoColor=white&label=Stars" alt="Stars">
<a href="https://github.com/commanderxa/delta/stargazers">
<img src="https://img.shields.io/github/stars/commanderxa/delta?style=for-the-badge&logo=github&logoColor=white&label=Stars" alt="Stars">
</a>
<a href="https://github.com/commanderxa/athena/commits/master">
<img src="https://img.shields.io/github/last-commit/commanderxa/athena?style=for-the-badge&logo=git&logoColor=white&label=Last%20Commit" alt="Last Commit">
<a href="https://github.com/commanderxa/delta/commits/master">
<img src="https://img.shields.io/github/last-commit/commanderxa/delta?style=for-the-badge&logo=git&logoColor=white&label=Last%20Commit" alt="Last Commit">
</a>
<a href="https://github.com/commanderxa/athena/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/commanderxa/athena?style=for-the-badge&logo=opensourceinitiative&logoColor=white&label=License" alt="License">
<a href="https://github.com/commanderxa/delta/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/commanderxa/delta?style=for-the-badge&logo=opensourceinitiative&logoColor=white&label=License" alt="License">
</a>
</div>

Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

If you have found a security vulnerability in this project, then please share your finding.

Please, report security issues here: https://github.com/CommanderXA/athena/security/advisories/new
Please, report security issues here: https://github.com/CommanderXA/delta/security/advisories/new

Describe the issue in detail as much as possible.
12 changes: 12 additions & 0 deletions delta-macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "delta-macros"
version = "0.1.0"
edition = "2024"

[lib]
proc-macro = true

[dependencies]
syn = { version = "2", features = ["full"] }
quote = "1"
proc-macro2 = "1"
154 changes: 154 additions & 0 deletions delta-macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Fields, Type};

/// Derive macro for the `Module` trait.
///
/// Automatically implements:
/// - `module_name()` → returns the struct's name as a `String`
/// - `parameters()` → collects all fields of type `nn::Parameter`
/// - `submodules()` → collects all fields that implement `Module`
/// (detected via the `#[module]` field attribute)
///
/// The user must still implement `forward()` manually.
///
/// # Field Attributes
///
/// - `#[module]` — marks a field as a sub-module (must be `Box<dyn Module>` or
/// a concrete type implementing `Module`). The macro will include it in the
/// `submodules()` return value.
///
/// Fields of type `nn::Parameter` are picked up **automatically** without any
/// attribute, because the type itself is unambiguous.
///
/// # Example
///
/// ```ignore
/// use your_crate::nn;
/// use module_derive::Module;
///
/// #[derive(Module)]
/// pub struct Linear {
/// pub weight: nn::Parameter,
/// pub bias: nn::Parameter,
/// #[module]
/// pub activation: Box<dyn Module>,
/// }
///
/// impl Module for Linear {
/// fn forward(&self, args: Vec<IValue>, kwargs: HashMap<String, IValue>) -> IValue {
/// todo!()
/// }
/// }
/// ```
#[proc_macro_derive(Module, attributes(module))]
pub fn derive_module(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let struct_name = &input.ident;
let struct_name_str = struct_name.to_string();

let fields = match &input.data {
Data::Struct(data) => match &data.fields {
Fields::Named(f) => &f.named,
Fields::Unnamed(_) => {
return syn::Error::new_spanned(
struct_name,
"Module derive does not support tuple structs",
)
.to_compile_error()
.into()
}
Fields::Unit => {
// Unit struct — no parameters or submodules
return expand(struct_name, &struct_name_str, vec![], vec![]);
}
},
_ => {
return syn::Error::new_spanned(struct_name, "Module can only be derived for structs")
.to_compile_error()
.into()
}
};

let mut param_fields = Vec::new();
let mut submodule_fields = Vec::new();

for field in fields {
let field_name = field.ident.as_ref().expect("named field");

// Check for #[module] attribute → submodule
let is_submodule = field
.attrs
.iter()
.any(|a| a.path().is_ident("module"));

if is_submodule {
submodule_fields.push(field_name.clone());
} else if is_nn_parameter(&field.ty) {
// Automatically detect nn::Parameter fields
param_fields.push(field_name.clone());
}
}

expand(struct_name, &struct_name_str, param_fields, submodule_fields)
}

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

/// Returns `true` when the type path ends in `Parameter` (covers both
/// `nn::Parameter` and a bare `Parameter` import).
fn is_nn_parameter(ty: &Type) -> bool {
if let Type::Path(type_path) = ty {
if let Some(last) = type_path.path.segments.last() {
return last.ident == "Parameter";
}
}
false
}

/// Emit the `module_name`, `parameters`, and `submodules` impl block.
fn expand(
struct_name: &syn::Ident,
struct_name_str: &str,
param_fields: Vec<syn::Ident>,
submodule_fields: Vec<syn::Ident>,
) -> TokenStream {
let parameters_body = if param_fields.is_empty() {
quote! { vec![] }
} else {
quote! {
vec![
#( self.#param_fields.clone() ),*
]
}
};

let submodules_body = if submodule_fields.is_empty() {
quote! { vec![] }
} else {
quote! {
vec![
#( &self.#submodule_fields as &dyn Module ),*
]
}
};

quote! {
impl Module for #struct_name {
fn module_name(&self) -> String {
#struct_name_str.to_string()
}

fn parameters(&self) -> Vec<nn::Parameter> {
#parameters_body
}

fn submodules(&self) -> Vec<&dyn Module> {
#submodules_body
}
}
}
.into()
}
Loading
Loading