Skip to main content

Crate atune_derive

Crate atune_derive 

Expand description

Procedural macros for atune.

This crate provides #[derive(Space)], which turns a flat configuration struct into a typed search space (two ways to write a space). It is the static, well-lit counterpart of the string DSL: both lower to the same atune_core::space::{SpaceSchema, Distribution, Assignment} engine — the derive invents no parallel model.

Do not depend on this crate directly. The generated code names the atune facade (::atune::…), which re-exports both the Space trait and this derive, so a crate using #[derive(Space)] must have atune in scope. If it is in scope under another name — a dependency renamed in Cargo.toml, tuner = { package = "atune" } — say so once on the struct: #[space(crate = ::tuner)]. That is the only #[space(...)] key a struct takes; every key in the table below belongs on a field.

§The attribute grammar

Every field carries exactly one #[space(...)] attribute (a field with no attribute is a compile error, so nothing is silently dropped). The forms:

AttributeField typesLowers to
#[space(range = LOW..=HIGH)]f32/f64, any integerFloat / Int
#[space(log, range = LOW..=HIGH)]dittologarithmic Float/Int
#[space(range = LOW..=HIGH, step = S)]dittostepped Float/Int
#[space(choices = [A, B, C])]any integer, an enum, …Cat (value ↔ index)
#[space]bool onlyBool
#[space(fixed)]anyexcluded from the schema
#[space(fixed = EXPR)]anyexcluded from the schema
  • range is always inclusive (low..=high). Float ranges take float literals (1e-5..=1e-2), integer ranges take integer literals (1..=16); a mismatched literal is a plain type error from the generated constructor call.
  • log and step cannot be combined (a logarithmic and uniformly stepped grid is ill-defined — Optuna rejects it too).
  • choices maps the listed values to categorical indices in order: the labels stored in the schema are the source text of each choice (64, Optimizer::Adam, …), so an enum is expressed as #[space(choices = [Enum::A, Enum::B])]. encode finds a value’s index with ==, so a choice field’s type must be PartialEq. Automatic enumeration of a bare enum field’s variants (the companion #[derive(Categorical)]) is a later slice.
  • fixed is a field that is present on the decoded value but not tuned: it is excluded from the schema and never appears in an encoded point. On decode a bare #[space(fixed)] takes the field from the struct’s Default (so the struct must implement Default), and #[space(fixed = EXPR)] takes the given expression.

§Type mapping

Rust field typeDistribution kind
f32, f64Float
i8…i64, u8…u64, isize, usizeInt
boolBool
a choices = [...] list (integers, enum variants)Cat

An integer that does not fit its field type on decode (for example a stored -1 for a u32 field) is a clean Err, never a panic. encode is total: an integer field wider than i64 (only u64/usize) saturates rather than wrapping — a value HPO ranges never reach.

§What is a compile error

Malformed attributes are rejected at compile time with a spanned compile_error!, never a panic in the macro:

  • an unknown key (#[space(foo = 1)]);
  • a non-inclusive range (#[space(range = 0..1)]);
  • choices on a floating-point field, or range on a bool field;
  • range on a non-numeric field, or a bare non-bool field with no range/choices/fixed;
  • log and step together, or fixed combined with any of range/choices/log/step;
  • a field with no #[space(...)] attribute at all;
  • a tuple struct, unit struct, enum or union (only named-field structs).

Malformed values (low > high, a logarithmic range with a non-positive lower bound, a non-positive step, …) are surfaced at run time as an Err from Space::schema, because they flow through the fallible Distribution constructors and a library path must not panic.

Derive Macros§

Space
Derives Space for a flat configuration struct.