Skip to main content

limen_build/
lib.rs

1// Copyright © 2025–present Arlo Louis Byrne (idky137)
2// SPDX-License-Identifier: Apache-2.0
3//
4// Licensed under the Apache License, Version 2.0.
5// See the LICENSE-APACHE file in the project root for license terms.
6
7#![warn(missing_docs)]
8#![deny(unsafe_code)]
9//! # limen-build — proc-macro front for `limen-codegen`
10//!
11//! Provides the `define_graph! { ... }` macro which parses the Limen graph DSL
12//! and expands it into fully-typed Rust code via `limen-codegen`.
13//!
14//! See `limen-codegen` crate docs for the DSL shape and the exact generated API.
15
16extern crate proc_macro;
17
18use proc_macro::TokenStream;
19use proc_macro2::{Literal, TokenStream as TokenStream2};
20use quote::quote;
21
22/// Define a Limen graph using the DSL and expand it into generated Rust code.
23///
24/// This macro forwards its input tokens directly to
25/// [`limen_codegen::expand_tokens`] and returns the emitted items.
26///
27/// Each invocation emits a single concrete graph type. Use the trailing
28/// `concurrent;` keyword to additionally request the std-only
29/// `ScopedGraphApi` implementation for that same graph type.
30///
31/// # Example (no_std, `GraphApi` only)
32/// ```ignore
33/// use limen_build::define_graph;
34///
35/// define_graph! {
36///     pub struct MyGraph;
37///
38///     nodes {
39///         0: { ty: my::Src,  in_ports: 0, out_ports: 1, in_payload: (),  out_payload: u32, name: Some("src"), ingress_policy: MY_Q },
40///         1: { ty: my::Map,  in_ports: 1, out_ports: 1, in_payload: u32, out_payload: u32, name: Some("map") },
41///         2: { ty: my::Sink, in_ports: 1, out_ports: 0, in_payload: u32, out_payload: (),  name: Some("sink") },
42///     }
43///
44///     edges {
45///         0: { ty: TestSpscRingBuf<8>, payload: u32, manager: StaticMemoryManager<u32, 8>, from: (0, 0), to: (1, 0), policy: EDGE_POL, name: Some("src->map") },
46///         1: { ty: TestSpscRingBuf<8>, payload: u32, manager: StaticMemoryManager<u32, 8>, from: (1, 0), to: (2, 0), policy: EDGE_POL, name: Some("map->sink") },
47///     }
48/// }
49/// ```
50///
51/// # Example (std, `GraphApi` + `ScopedGraphApi`)
52///
53/// Adding `concurrent;` inside the **same** invocation extends the generated graph type
54/// with a std-only `ScopedGraphApi` impl — it does **not** emit a second graph type.
55///
56/// ```ignore
57/// use limen_build::define_graph;
58///
59/// define_graph! {
60///     pub struct MyGraph;
61///
62///     nodes {
63///         0: { ty: my::Src,  in_ports: 0, out_ports: 1, in_payload: (),  out_payload: u32, name: Some("src"), ingress_policy: MY_Q },
64///         1: { ty: my::Map,  in_ports: 1, out_ports: 1, in_payload: u32, out_payload: u32, name: Some("map") },
65///         2: { ty: my::Sink, in_ports: 1, out_ports: 0, in_payload: u32, out_payload: (),  name: Some("sink") },
66///     }
67///
68///     edges {
69///         0: { ty: TestSpscRingBuf<8>, payload: u32, manager: ConcurrentMemoryManager<u32>, from: (0, 0), to: (1, 0), policy: EDGE_POL, name: Some("src->map") },
70///         1: { ty: TestSpscRingBuf<8>, payload: u32, manager: ConcurrentMemoryManager<u32>, from: (1, 0), to: (2, 0), policy: EDGE_POL, name: Some("map->sink") },
71///     }
72///
73///     concurrent;
74/// }
75/// ```
76#[proc_macro]
77pub fn define_graph(input: TokenStream) -> TokenStream {
78    let tokens2 = TokenStream2::from(input);
79    match limen_codegen::expand_tokens(tokens2) {
80        Ok(out) => out.into(),
81        Err(err) => error_to_tokens(err).into(),
82    }
83}
84
85/// Convert a `CodegenError` into a compile-time error token stream.
86///
87/// - For parse errors, preserve spans using `syn::Error::to_compile_error`.
88/// - For other errors, use `compile_error!("<message>")`.
89fn error_to_tokens(err: limen_codegen::CodegenError) -> TokenStream2 {
90    match err {
91        limen_codegen::CodegenError::Parse(e) => e.to_compile_error(),
92        other => {
93            let lit = Literal::string(&other.to_string());
94            quote! { compile_error!(#lit); }
95        }
96    }
97}