# π¦ UniStructGen Codegen
**ΠΠ΅Π½Π΅ΡΠ°ΡΠΎΡ ΠΈΠ΄ΠΈΠΎΠΌΠ°ΡΠΈΡΠ½ΠΎΠ³ΠΎ Rust-ΠΊΠΎΠ΄Π° ΠΈΠ· Intermediate Representation**
[](https://crates.io/crates/unistructgen-codegen)
[](https://docs.rs/unistructgen-codegen)
[](../LICENSE-MIT)
---
## π Π‘ΠΎΠ΄Π΅ΡΠΆΠ°Π½ΠΈΠ΅
- [ΠΠ±Π·ΠΎΡ](#-ΠΎΠ±Π·ΠΎΡ)
- [Π£ΡΡΠ°Π½ΠΎΠ²ΠΊΠ°](#-ΡΡΡΠ°Π½ΠΎΠ²ΠΊΠ°)
- [ΠΡΡΡΡΡΠΉ ΡΡΠ°ΡΡ](#-Π±ΡΡΡΡΡΠΉ-ΡΡΠ°ΡΡ)
- [RustRenderer](#-rustrenderer)
- [RenderOptions](#-renderoptions)
- [RustRendererBuilder](#-rustrendererbuilder)
- [ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΡΠΈΠΏΠΎΠ²](#-ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ°-ΡΠΈΠΏΠΎΠ²)
- [ΠΠ°Π»ΠΈΠ΄Π°ΡΠΈΡ](#-Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΡ)
- [ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΠΎΡΠΈΠ±ΠΎΠΊ](#-ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ°-ΠΎΡΠΈΠ±ΠΎΠΊ)
- [ΠΡΠΈΠΌΠ΅ΡΡ](#-ΠΏΡΠΈΠΌΠ΅ΡΡ)
---
## π― ΠΠ±Π·ΠΎΡ
`unistructgen-codegen` β ΡΡΠΎ ΠΌΠΎΠ΄ΡΠ»Ρ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΠΈ Rust-ΠΊΠΎΠ΄Π° ΠΈΠ· IR (Intermediate Representation). ΠΠ½ ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠΈΠ²Π°Π΅Ρ:
- **ΠΠ΄ΠΈΠΎΠΌΠ°ΡΠΈΡΠ½ΡΠΉ Rust** β ΠΏΡΠ°Π²ΠΈΠ»ΡΠ½ΠΎΠ΅ ΡΠΎΡΠΌΠ°ΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅, ΡΡΠΈΠ»Ρ ΠΈ ΡΠΎΠ³Π»Π°ΡΠ΅Π½ΠΈΡ
- **Derive macros** β Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΎΠ΅ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ Debug, Clone, PartialEq, serde
- **ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΡ** β ΡΠΎΡ
ΡΠ°Π½Π΅Π½ΠΈΠ΅ doc-ΠΊΠΎΠΌΠΌΠ΅Π½ΡΠ°ΡΠΈΠ΅Π² ΠΈΠ· IR
- **ΠΡΡΠΈΠ±ΡΡΡ** β ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠ° #[serde(...)], #[validate(...)], etc.
- **Type safety** β ΠΊΠΎΡΡΠ΅ΠΊΡΠ½ΠΎΠ΅ ΠΌΠ°ΠΏΠΏΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ IR ΡΠΈΠΏΠΎΠ² Π² Rust ΡΠΈΠΏΡ
- **ΠΠ»ΠΎΠΆΠ΅Π½Π½ΡΠ΅ ΡΠΈΠΏΡ** β Π³Π΅Π½Π΅ΡΠ°ΡΠΈΡ Π²ΡΠ΅Ρ
ΡΠ²ΡΠ·Π°Π½Π½ΡΡ
ΡΡΡΡΠΊΡΡΡ
### ΠΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΡΠ΅ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ
| Structs | ΠΡΠ±Π»ΠΈΡΠ½ΡΠ΅ ΡΡΡΡΠΊΡΡΡΡ Ρ ΠΏΠΎΠ»ΡΠΌΠΈ |
| Enums | ΠΠ΅ΡΠ΅ΡΠΈΡΠ»Π΅Π½ΠΈΡ Ρ Π²Π°ΡΠΈΠ°Π½ΡΠ°ΠΌΠΈ |
| Doc comments | `/// ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΡ` |
| Derives | `#[derive(...)]` |
| Serde attributes | `#[serde(rename = "...")]` |
| Validation | `#[validate(...)]` |
| Nested types | ΠΠ²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΎΠ΅ ΡΠ°Π·ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠ΅ΠΉ |
| Option/Vec/Map | `Option<T>`, `Vec<T>`, `HashMap<K, V>` |
---
## π¦ Π£ΡΡΠ°Π½ΠΎΠ²ΠΊΠ°
```toml
[dependencies]
unistructgen-codegen = "0.1"
unistructgen-core = "0.1"
```
---
## π ΠΡΡΡΡΡΠΉ ΡΡΠ°ΡΡ
```rust
use unistructgen_codegen::{RustRenderer, RenderOptions};
use unistructgen_core::{
CodeGenerator, IRModule, IRStruct, IRType, IRField,
IRTypeRef, PrimitiveKind
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Π‘ΠΎΠ·Π΄Π°ΡΠΌ IR ΠΌΠΎΠ΄ΡΠ»Ρ
let mut module = IRModule::new("users".to_string());
// Π‘ΠΎΠ·Π΄Π°ΡΠΌ ΡΡΡΡΠΊΡΡΡΡ
let mut user = IRStruct::new("User".to_string());
user.doc = Some("Represents a user in the system".to_string());
user.add_derive("Debug".to_string());
user.add_derive("Clone".to_string());
user.add_derive("serde::Serialize".to_string());
user.add_derive("serde::Deserialize".to_string());
user.add_field(IRField::new(
"id".to_string(),
IRTypeRef::Primitive(PrimitiveKind::I64)
));
user.add_field(IRField::new(
"email".to_string(),
IRTypeRef::Primitive(PrimitiveKind::String)
));
let mut age = IRField::new(
"age".to_string(),
IRTypeRef::Option(Box::new(IRTypeRef::Primitive(PrimitiveKind::I32)))
);
age.doc = Some("User's age (optional)".to_string());
user.add_field(age);
module.add_type(IRType::Struct(user));
// ΠΠ΅Π½Π΅ΡΠΈΡΡΠ΅ΠΌ ΠΊΠΎΠ΄
let renderer = RustRenderer::new(RenderOptions::default());
let code = renderer.generate(&module)?;
println!("{}", code);
Ok(())
}
```
**Π Π΅Π·ΡΠ»ΡΡΠ°Ρ:**
```rust
// Generated by unistructgen v0.1.0
// Do not edit this file manually
#![allow(dead_code)]
#![allow(unused_imports)]
/// Represents a user in the system
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct User {
pub id: i64,
pub email: String,
/// User's age (optional)
pub age: Option<i32>,
}
```
---
## π¨ RustRenderer
ΠΡΠ½ΠΎΠ²Π½ΠΎΠΉ ΠΊΠ»Π°ΡΡ Π΄Π»Ρ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΠΈ Rust-ΠΊΠΎΠ΄Π°.
### Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅
```rust
use unistructgen_codegen::{RustRenderer, RenderOptions};
// Π‘ Π΄Π΅ΡΠΎΠ»ΡΠ½ΡΠΌΠΈ ΠΎΠΏΡΠΈΡΠΌΠΈ
let renderer = RustRenderer::new(RenderOptions::default());
// Π‘ ΠΊΠ°ΡΡΠΎΠΌΠ½ΡΠΌΠΈ ΠΎΠΏΡΠΈΡΠΌΠΈ
let renderer = RustRenderer::new(RenderOptions {
add_header: false, // ΠΠ΅Π· Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ° "Generated by..."
add_clippy_allows: false, // ΠΠ΅Π· #![allow(...)]
});
```
### ΠΠ΅ΡΠΎΠ΄Ρ
```rust
use unistructgen_core::CodeGenerator;
// ΠΡΠ½ΠΎΠ²Π½ΠΎΠΉ ΠΌΠ΅ΡΠΎΠ΄ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΠΈ (ΡΠ΅ΡΠ΅Π· ΡΡΠ΅ΠΉΡ CodeGenerator)
let code = renderer.generate(&module)?;
// ΠΠ»ΡΡΠ΅ΡΠ½Π°ΡΠΈΠ²Π½ΡΠΉ ΠΌΠ΅ΡΠΎΠ΄ (ΠΏΡΡΠΌΠΎΠΉ Π²ΡΠ·ΠΎΠ²)
let code = renderer.render(&module)?;
// ΠΠ΅ΡΠ°Π΄Π°Π½Π½ΡΠ΅ Π³Π΅Π½Π΅ΡΠ°ΡΠΎΡΠ°
let metadata = renderer.metadata();
println!("Language: {}", renderer.language()); // "Rust"
println!("Extension: {}", renderer.file_extension()); // "rs"
// ΠΠ°Π»ΠΈΠ΄Π°ΡΠΈΡ IR ΠΏΠ΅ΡΠ΅Π΄ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΠ΅ΠΉ
renderer.validate(&module)?;
// Π€ΠΎΡΠΌΠ°ΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ (placeholder Π΄Π»Ρ rustfmt)
let formatted = renderer.format(code)?;
```
---
## βοΈ RenderOptions
ΠΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΠΈ ΠΊΠΎΠ΄Π°.
### ΠΠΏΡΠΈΠΈ
| `add_header` | `bool` | `true` | ΠΠΎΠ±Π°Π²Π»ΡΡΡ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ Ρ Π²Π΅ΡΡΠΈΠ΅ΠΉ |
| `add_clippy_allows` | `bool` | `true` | ΠΠΎΠ±Π°Π²Π»ΡΡΡ `#![allow(...)]` |
### ΠΡΠΈΠΌΠ΅ΡΡ
```rust
use unistructgen_codegen::RenderOptions;
// ΠΠ»Ρ production: Ρ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΎΠΌ ΠΈ clippy allows
let prod_options = RenderOptions::default();
// ΠΠ»Ρ ΡΠ΅ΡΡΠΎΠ²/ΠΌΠ°ΠΊΡΠΎΡΠΎΠ²: ΡΠΈΡΡΡΠΉ ΠΊΠΎΠ΄
let test_options = RenderOptions {
add_header: false,
add_clippy_allows: false,
};
// Π’ΠΎΠ»ΡΠΊΠΎ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ, Π±Π΅Π· clippy
let custom_options = RenderOptions {
add_header: true,
add_clippy_allows: false,
};
```
---
## ποΈ RustRendererBuilder
Fluent-Π±ΠΈΠ»Π΄Π΅Ρ Π΄Π»Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΡΠ΅Π½Π΄Π΅ΡΠ΅ΡΠ°.
```rust
use unistructgen_codegen::RustRendererBuilder;
let renderer = RustRendererBuilder::new()
.with_header(true)
.with_clippy_allows(true)
.build();
```
---
## π€ ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΡΠΈΠΏΠΎΠ²
### ΠΡΠΈΠΌΠΈΡΠΈΠ²Π½ΡΠ΅ ΡΠΈΠΏΡ
| `String` | `String` |
| `I8` | `i8` |
| `I16` | `i16` |
| `I32` | `i32` |
| `I64` | `i64` |
| `I128` | `i128` |
| `U8` | `u8` |
| `U16` | `u16` |
| `U32` | `u32` |
| `U64` | `u64` |
| `U128` | `u128` |
| `F32` | `f32` |
| `F64` | `f64` |
| `Bool` | `bool` |
| `Char` | `char` |
| `DateTime` | `chrono::DateTime<chrono::Utc>` |
| `Uuid` | `uuid::Uuid` |
| `Decimal` | `rust_decimal::Decimal` |
| `Json` | `serde_json::Value` |
### Π‘ΠΎΡΡΠ°Π²Π½ΡΠ΅ ΡΠΈΠΏΡ
```rust
// Option<T>
IRTypeRef::Option(Box::new(IRTypeRef::Primitive(PrimitiveKind::String)))
// β Option<String>
// Vec<T>
IRTypeRef::Vec(Box::new(IRTypeRef::Primitive(PrimitiveKind::I32)))
// β Vec<i32>
// HashMap<K, V>
IRTypeRef::Map(
Box::new(IRTypeRef::Primitive(PrimitiveKind::String)),
Box::new(IRTypeRef::Primitive(PrimitiveKind::I64))
)
// β std::collections::HashMap<String, i64>
// Π‘ΡΡΠ»ΠΊΠ° Π½Π° ΡΠΈΠΏ
IRTypeRef::Named("Address".to_string())
// β Address
```
### ΠΠ»ΠΎΠΆΠ΅Π½Π½ΡΠ΅ ΡΠΈΠΏΡ
```rust
// Option<Vec<String>>
IRTypeRef::Option(Box::new(
IRTypeRef::Vec(Box::new(
IRTypeRef::Primitive(PrimitiveKind::String)
))
))
// β Option<Vec<String>>
// Vec<HashMap<String, User>>
IRTypeRef::Vec(Box::new(
IRTypeRef::Map(
Box::new(IRTypeRef::Primitive(PrimitiveKind::String)),
Box::new(IRTypeRef::Named("User".to_string()))
)
))
// β Vec<std::collections::HashMap<String, User>>
```
---
## β
ΠΠ°Π»ΠΈΠ΄Π°ΡΠΈΡ
ΠΠ΅Π½Π΅ΡΠ°ΡΠΎΡ Π²Π°Π»ΠΈΠ΄ΠΈΡΡΠ΅Ρ Π°ΡΡΠΈΠ±ΡΡΡ ΠΈΠ· `FieldConstraints` ΠΈ ΡΠΎΠ·Π΄Π°ΡΡ `#[validate(...)]`.
### ΠΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΡΠ΅ ΠΎΠ³ΡΠ°Π½ΠΈΡΠ΅Π½ΠΈΡ
```rust
use unistructgen_core::FieldConstraints;
let constraints = FieldConstraints {
// ΠΠ»ΠΈΠ½Π° ΡΡΡΠΎΠΊΠΈ/ΠΌΠ°ΡΡΠΈΠ²Π°
min_length: Some(3),
max_length: Some(100),
// β #[validate(length(min = 3, max = 100))]
// ΠΠΈΠ°ΠΏΠ°Π·ΠΎΠ½ ΡΠΈΡΠ΅Π»
min_value: Some(0.0),
max_value: Some(100.0),
// β #[validate(range(min = 0, max = 100))]
// Regex ΠΏΠ°ΡΡΠ΅ΡΠ½
pattern: Some(r"^\w+$".to_string()),
// β #[validate(regex = "^\w+$")]
// Π€ΠΎΡΠΌΠ°Ρ
format: Some("email".to_string()),
// β #[validate(email)]
};
```
### ΠΡΠΈΠΌΠ΅Ρ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΠΈ
```rust
let mut field = IRField::new("email".to_string(), IRTypeRef::Primitive(PrimitiveKind::String));
field.constraints = FieldConstraints {
min_length: Some(5),
max_length: Some(255),
format: Some("email".to_string()),
..Default::default()
};
// Π Π΅Π·ΡΠ»ΡΡΠ°Ρ:
// #[validate(length(min = 5, max = 255), email)]
// pub email: String,
```
---
## β ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΠΎΡΠΈΠ±ΠΎΠΊ
### CodegenError
```rust
use unistructgen_codegen::CodegenError;
pub enum CodegenError {
/// ΠΡΠΈΠ±ΠΊΠ° ΡΠ΅Π½Π΄Π΅ΡΠΈΠ½Π³Π°
RenderError {
component: String, // "struct", "field", "enum"
context: String, // ΠΠΌΡ ΡΠΈΠΏΠ°
message: String,
},
/// ΠΡΠΈΠ±ΠΊΠ° ΡΠΎΡΠΌΠ°ΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ
FormatError {
context: String,
source: std::fmt::Error,
},
/// ΠΡΠΈΠ±ΠΊΠ° Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΠΈ
ValidationError {
reason: String,
suggestion: Option<String>,
},
/// ΠΠ΅Π²Π°Π»ΠΈΠ΄Π½ΡΠΉ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡ
InvalidIdentifier {
name: String,
context: String, // "struct name", "field name"
reason: String,
},
/// ΠΠ΅ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΡΠΉ ΡΠΈΠΏ
UnsupportedType {
type_name: String,
context: String,
reason: String,
alternative: Option<String>,
},
/// ΠΡΠ΅Π²ΡΡΠ΅Π½Π° ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½Π°Ρ Π³Π»ΡΠ±ΠΈΠ½Π° Π²Π»ΠΎΠΆΠ΅Π½Π½ΠΎΡΡΠΈ
MaxDepthExceeded {
context: String,
max_depth: usize,
},
}
```
### ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΠΎΡΠΈΠ±ΠΎΠΊ
```rust
use unistructgen_codegen::{RustRenderer, RenderOptions, CodegenError};
let renderer = RustRenderer::new(RenderOptions::default());
match renderer.generate(&module) {
Ok(code) => println!("{}", code),
Err(CodegenError::ValidationError { reason, suggestion }) => {
eprintln!("Validation failed: {}", reason);
if let Some(sug) = suggestion {
eprintln!("Suggestion: {}", sug);
}
},
Err(CodegenError::InvalidIdentifier { name, context, reason }) => {
eprintln!("Invalid {} '{}': {}", context, name, reason);
},
Err(e) => eprintln!("Error: {}", e),
}
```
### ΠΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ suggestions
```rust
use unistructgen_codegen::CodegenError;
let error = CodegenError::validation_error("Module is empty")
.with_suggestion("Add at least one struct or enum to the module");
```
---
## π ΠΡΠΈΠΌΠ΅ΡΡ
### ΠΠ΅Π½Π΅ΡΠ°ΡΠΈΡ ΡΡΡΡΠΊΡΡΡΡ Ρ serde
```rust
use unistructgen_codegen::{RustRenderer, RenderOptions};
use unistructgen_core::*;
let mut user = IRStruct::new("User".to_string());
user.add_derive("serde::Serialize".to_string());
user.add_derive("serde::Deserialize".to_string());
let mut id_field = IRField::new("id".to_string(), IRTypeRef::Primitive(PrimitiveKind::I64));
let mut name_field = IRField::new("user_name".to_string(), IRTypeRef::Primitive(PrimitiveKind::String));
name_field.source_name = Some("userName".to_string());
name_field.attributes.push("serde(rename = \"userName\")".to_string());
user.add_field(id_field);
user.add_field(name_field);
let mut module = IRModule::new("users".to_string());
module.add_type(IRType::Struct(user));
let renderer = RustRenderer::new(RenderOptions::default());
let code = renderer.generate(&module)?;
```
**Π Π΅Π·ΡΠ»ΡΡΠ°Ρ:**
```rust
#[derive(serde::Serialize, serde::Deserialize)]
pub struct User {
pub id: i64,
#[serde(rename = "userName")]
pub user_name: String,
}
```
### ΠΠ΅Π½Π΅ΡΠ°ΡΠΈΡ enum
```rust
use unistructgen_core::*;
let status = IREnum {
name: "OrderStatus".to_string(),
variants: vec![
IREnumVariant {
name: "Pending".to_string(),
source_value: None,
doc: Some("Order is pending".to_string()),
},
IREnumVariant {
name: "InProgress".to_string(),
source_value: Some("in_progress".to_string()),
doc: None,
},
IREnumVariant {
name: "Completed".to_string(),
source_value: None,
doc: None,
},
],
derives: vec!["Debug".to_string(), "Clone".to_string(), "serde::Serialize".to_string()],
doc: Some("Order status enum".to_string()),
};
let mut module = IRModule::new("orders".to_string());
module.add_type(IRType::Enum(status));
let renderer = RustRenderer::new(RenderOptions::default());
let code = renderer.generate(&module)?;
```
**Π Π΅Π·ΡΠ»ΡΡΠ°Ρ:**
```rust
/// Order status enum
#[derive(Debug, Clone, serde::Serialize)]
pub enum OrderStatus {
/// Order is pending
Pending,
#[serde(rename = "in_progress")]
InProgress,
Completed,
}
```
### ΠΠ΅Π½Π΅ΡΠ°ΡΠΈΡ Ρ Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΠ΅ΠΉ
```rust
let mut email_field = IRField::new(
"email".to_string(),
IRTypeRef::Primitive(PrimitiveKind::String)
);
email_field.doc = Some("User's email address".to_string());
email_field.constraints = FieldConstraints {
min_length: Some(5),
max_length: Some(255),
format: Some("email".to_string()),
pattern: Some(r"^[\w@.]+$".to_string()),
..Default::default()
};
let mut age_field = IRField::new(
"age".to_string(),
IRTypeRef::Primitive(PrimitiveKind::I32)
);
age_field.constraints = FieldConstraints {
min_value: Some(0.0),
max_value: Some(150.0),
..Default::default()
};
```
**Π Π΅Π·ΡΠ»ΡΡΠ°Ρ:**
```rust
/// User's email address
#[validate(length(min = 5, max = 255), regex = "^[\w@.]+$", email)]
pub email: String,
#[validate(range(min = 0, max = 150))]
pub age: i32,
```
---
## π Π‘Π²ΡΠ·Π°Π½Π½ΡΠ΅ ΠΌΠΎΠ΄ΡΠ»ΠΈ
- [unistructgen-core](../core/README.md) β IR, ΡΡΠ΅ΠΉΡΡ, pipeline
- [unistructgen-json-parser](../parsers/json_parser/README.md) β JSON β IR
- [unistructgen-markdown-parser](../parsers/markdown_parser/README.md) β Markdown β IR
- [unistructgen-openapi-parser](../parsers/openapi_parser/README.md) β OpenAPI β IR
---
## πΊ Roadmap
- [ ] ΠΠ½ΡΠ΅Π³ΡΠ°ΡΠΈΡ Ρ `rustfmt` Π΄Π»Ρ ΡΠΎΡΠΌΠ°ΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ
- [ ] ΠΠ΅Π½Π΅ΡΠ°ΡΠΈΡ `impl` Π±Π»ΠΎΠΊΠΎΠ²
- [ ] ΠΠ΅Π½Π΅ΡΠ°ΡΠΈΡ `From`/`Into` ΡΡΠ΅ΠΉΡΠΎΠ²
- [ ] ΠΠ΅Π½Π΅ΡΠ°ΡΠΈΡ `Builder` ΠΏΠ°ΡΡΠ΅ΡΠ½Π°
- [ ] ΠΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠ° `#[cfg(...)]` Π°ΡΡΠΈΠ±ΡΡΠΎΠ²
---
## π ΠΠΈΡΠ΅Π½Π·ΠΈΡ
MIT ΠΈΠ»ΠΈ Apache-2.0 β Π½Π° Π²Π°Ρ Π²ΡΠ±ΠΎΡ.