herolib-toschema

Crates.ioherolib-toschema
lib.rsherolib-toschema
version0.1.0
created_at2025-12-18 06:30:45.474939+00
updated_at2025-12-18 06:30:45.474939+00
descriptionDerive macros for JSON Schema generation and HeroScript serialization
homepage
repositoryhttps://github.com/threefoldtech/sal
max_upload_size
id1991808
size91,522
kristof de spiegeleer (despiegk)

documentation

README

ToSchema - JSON Schema Derive Macro

A procedural macro that automatically generates JSON Schema from Rust structs. Nested structs are fully inlined, producing a complete self-contained schema.

Usage

Add to your Cargo.toml:

[dependencies]
toschema = { path = "../toschema" }  # or appropriate path

Then derive ToSchema on your structs:

use toschema::ToSchema;

#[derive(ToSchema)]
struct Inner {
    value: i32,
}

#[derive(ToSchema)]
struct MyConfig {
    name: String,
    count: u32,
    enabled: bool,
    items: Vec<String>,
    optional_field: Option<String>,
    nested: Inner,  // Fully inlined in output
}

fn main() {
    // Get compact JSON Schema
    let schema = MyConfig::json_schema();
    println!("{}", schema);

    // Get pretty-printed JSON Schema
    let schema_pretty = MyConfig::json_schema_pretty();
    println!("{}", schema_pretty);
}

Output Example (NodeSpec with nested types)

For a complex struct with nested types, the schema is fully inlined:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "NodeSpec",
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "hardware": {
      "type": "object",
      "properties": {
        "hardware_cost_usd": {
          "type": "number"
        },
        "power_consumption_watts": {
          "type": "number"
        },
        "rack_units": {
          "type": "number"
        }
      },
      "required": [
        "hardware_cost_usd",
        "power_consumption_watts",
        "rack_units"
      ]
    },
    "capacity": {
      "type": "object",
      "properties": {
        "memory_gb": {
          "type": "integer"
        },
        "vcpu": {
          "type": "integer"
        },
        "ssd_gb": {
          "type": "integer"
        },
        "hdd_gb": {
          "type": "integer"
        },
        "nr_gpu": {
          "type": "integer"
        },
        "passmark": {
          "type": "integer"
        },
        "llm_tps_performance_70b": {
          "type": "integer"
        }
      },
      "required": [
        "memory_gb",
        "vcpu",
        "ssd_gb",
        "hdd_gb",
        "nr_gpu",
        "passmark",
        "llm_tps_performance_70b"
      ]
    },
    "agents": {
      "type": "object",
      "properties": {
        "max_agents": {
          "type": "integer"
        },
        "agent_type": {
          "type": "string"
        }
      },
      "required": [
        "max_agents",
        "agent_type"
      ]
    },
    "slices": {
      "type": "object",
      "properties": {
        "nr_slices": {
          "type": "integer"
        }
      },
      "required": [
        "nr_slices"
      ]
    },
    "pricing": {
      "type": "object",
      "properties": {
        "node_price_per_slice_per_month": {
          "type": "number"
        },
        "agent_price_per_month": {
          "type": "number"
        },
        "hdd_price_per_gb_per_month": {
          "type": "number"
        }
      },
      "required": [
        "node_price_per_slice_per_month",
        "agent_price_per_month",
        "hdd_price_per_gb_per_month"
      ]
    }
  },
  "required": [
    "name",
    "hardware",
    "capacity",
    "agents",
    "slices",
    "pricing"
  ]
}

Supported Types

Rust Type JSON Schema Type
String, &str "string"
bool "boolean"
i8, i16, i32, i64, i128, isize "integer"
u8, u16, u32, u64, u128, usize "integer"
f32, f64 "number"
Vec<T> "array" with items
Option<T> Type with ["type", "null"]
HashMap<K, V>, BTreeMap<K, V> "object" with additionalProperties
Custom structs Fully inlined object schema
Enums (unit variants) "enum": ["Variant1", "Variant2", ...]
Enums (with data) "oneOf": [...] with variant schemas

Enum Support

Enums are fully supported with proper JSON Schema generation:

Simple Enums (Unit Variants)

#[derive(ToSchema)]
enum Color {
    Red,
    Green,
    Blue,
}

// Generates:
// {
//   "$schema": "http://json-schema.org/draft-07/schema#",
//   "title": "Color",
//   "enum": ["Red", "Green", "Blue"]
// }

Complex Enums (With Data)

Enums with tuple or struct variants use oneOf:

#[derive(ToSchema)]
enum Message {
    Quit,                           // Unit variant -> {"const": "Quit"}
    Move { x: i32, y: i32 },        // Struct variant -> object with "Move" property
    Write(String),                  // Single tuple variant -> object with "Write" property
    ChangeColor(i32, i32, i32),     // Multi-element tuple -> object with array
}

// Generates:
// {
//   "$schema": "http://json-schema.org/draft-07/schema#",
//   "title": "Message",
//   "oneOf": [
//     {"const": "Quit"},
//     {"type": "object", "properties": {"Move": {"type": "object", "properties": {"x": {"type": "integer"}, "y": {"type": "integer"}}, "required": ["x", "y"]}}, "required": ["Move"]},
//     {"type": "object", "properties": {"Write": {"type": "string"}}, "required": ["Write"]},
//     {"type": "object", "properties": {"ChangeColor": {"type": "array", "items": [...], "minItems": 3, "maxItems": 3}}, "required": ["ChangeColor"]}
//   ]
// }

Enums in Structs

Enums can be used as field types in structs:

#[derive(ToSchema)]
enum Status {
    Pending,
    Active,
    Completed,
}

#[derive(ToSchema)]
struct Task {
    name: String,
    status: Status,  // Enum field - schema is fully inlined
}

Methods Added

The derive macro adds these methods to your struct:

  • fn json_schema() -> String - Returns compact JSON Schema with $schema header
  • fn json_schema_pretty() -> String - Returns formatted JSON Schema with indentation
  • fn schema_object() -> String - Returns just the object schema (for embedding)

AI Agent Instructions

When using this crate to generate schemas for AI agents:

  1. Add the derive macro to any struct that needs schema generation:

    use toschema::ToSchema;
    
    #[derive(ToSchema)]
    struct YourStruct { ... }
    
  2. Call json_schema_pretty() to get a human-readable schema:

    let schema = YourStruct::json_schema_pretty();
    
  3. For nested structs, each struct needs its own #[derive(ToSchema)]:

    #[derive(ToSchema)]
    struct Inner {
        value: i32,
    }
    
    #[derive(ToSchema)]
    struct Outer {
        name: String,
        inner: Inner,  // Will be FULLY INLINED in the schema
    }
    
  4. Optional fields are automatically detected and excluded from required:

    #[derive(ToSchema)]
    struct Config {
        required_field: String,      // In "required" array
        optional_field: Option<i32>, // NOT in "required" array, type is ["integer", "null"]
    }
    
  5. The schema is self-contained - all nested types are fully inlined, no $ref pointers. This makes the schema directly usable by AI tools without needing to resolve references.

  6. The schema follows JSON Schema draft-07 and can be used with any JSON Schema validator or AI tool that accepts JSON Schema definitions.

Limitations

  • Tuple structs are treated as arrays
  • Unit structs are treated as null type
  • Unions are not supported
  • No support for custom schema attributes (yet)
  • Recursive types will cause infinite loops (not currently detected)
Commit count: 0

cargo fmt