zerodds_idl_python/lib.rs
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3
4//! Crate `zerodds-idl-python`. Safety classification: **STANDARD**.
5//!
6//! IDL4 → Python code generator for ZeroDDS data types. Reads the IDL AST
7//! from `zerodds-idl` and emits `@idl_struct(...)` + `@dataclass`
8//! classes that meet the convention of the `zerodds-py` crate.
9//!
10//! Build-time tool — `forbid(unsafe_code)`, std-only.
11//!
12//! # Layer position
13//!
14//! Layer 3 (schema) — analogous to `zerodds-idl-cpp` / `-csharp` / `-java` /
15//! `-rust` / `-ts`, but emits Python code that runs against the
16//! `zerodds` Python library at runtime.
17//!
18//! # Public API
19//!
20//! - [`generate_python_module`] — AST + options → Python module source.
21//! - [`PythonGenOptions`] — codegen options.
22//! - [`error::IdlPythonError`] — error family.
23//!
24//! # What is emitted
25//!
26//! Per IDL construct:
27//!
28//! | IDL | Python |
29//! |-----|--------|
30//! | `struct` (any extensibility) | `@idl_struct(typename=...)` + `@dataclass class` |
31//! | `enum` | `class X(IntEnum)` |
32//! | `module M { ... }` | flat class name `M_Inner` (Python-PSM convention) |
33//! | `boolean` | `bool` |
34//! | `short`/`long`/`long long` | `Int16` / `Int32` / `Int64` (zerodds.idl brands) |
35//! | `unsigned short`/... | `UInt16` / `UInt32` / `UInt64` |
36//! | `octet` | `Octet` |
37//! | `float` / `double` / `long double` | `Float32` / `Float64` / `LongDouble` |
38//! | `char` / `wchar` | `Char` / `WChar` |
39//! | `string` / `wstring` | `String` / `WString` |
40//! | `string<N>` / `wstring<N>` | `BoundedString[N]` / `BoundedWString[N]` (bound enforced) |
41//! | `sequence<T>` | `List[T]` |
42//! | `sequence<T, N>` | `Sequence[T, N]` (bound enforced) |
43//! | `map<K, V>` / `map<K, V, N>` | `Dict[K, V]` / `Map[K, V, N]` (bound enforced) |
44//! | `T[N]` | `Array[T, N]` (multi-dim → nested) |
45//!
46//! Bounded collections and strings emit the bound-enforcing `zerodds.idl`
47//! brand so an over-bound value raises at runtime instead of silently
48//! corrupting the wire frame.
49//!
50//! # Unsupported (today `Unsupported`)
51//!
52//! - `valuetype`, `interface`
53//! - `fixed`, `any`
54//!
55//! # Example
56//!
57//! ```rust
58//! use zerodds_idl::config::ParserConfig;
59//! use zerodds_idl_python::{generate_python_module, PythonGenOptions};
60//!
61//! let ast = zerodds_idl::parse(
62//! "struct Greeting { long id; string<128> text; };",
63//! &ParserConfig::default(),
64//! )
65//! .expect("parse");
66//! let py_src =
67//! generate_python_module(&ast, &PythonGenOptions::default()).expect("gen");
68//! assert!(py_src.contains("@dataclass"));
69//! assert!(py_src.contains("class Greeting:"));
70//! assert!(py_src.contains("id: Int32"));
71//! // `string<128>` is bounded → the bound-enforcing brand is emitted.
72//! assert!(py_src.contains("text: BoundedString[128]"));
73//! ```
74
75#![forbid(unsafe_code)]
76#![warn(missing_docs)]
77
78pub mod emitter;
79pub mod error;
80
81pub use emitter::{PythonGenOptions, generate_python_module};
82pub use error::{IdlPythonError, Result};