polyxml 0.15.0__tar.gz → 0.16.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {polyxml-0.15.0 → polyxml-0.16.0}/Cargo.lock +5 -5
- {polyxml-0.15.0 → polyxml-0.16.0}/Cargo.toml +1 -1
- {polyxml-0.15.0 → polyxml-0.16.0}/PKG-INFO +1 -1
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/codegen/cpp/mod.rs +156 -4
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/codegen/mod.rs +1 -1
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/tests/test_cpp_codegen.rs +140 -2
- {polyxml-0.15.0 → polyxml-0.16.0}/pyproject.toml +1 -1
- {polyxml-0.15.0 → polyxml-0.16.0}/README.md +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/Cargo.toml +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/README.md +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/benches/core_benchmarks.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/codegen/csharp/mod.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/codegen/go/mod.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/codegen/java/mod.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/codegen/python/mod.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/codegen/rust/mod.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/codegen/typescript/mod.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/converters.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/error.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/ir/mod.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/ir/tarjan.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/json.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/lib.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/parser.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/schema.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/schema_parser/mod.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/serializer.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/transcoder.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/src/value.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/tests/test_conformance.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/tests/test_core.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/tests/test_csharp_codegen.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/tests/test_go_codegen.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/tests/test_java_codegen.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/tests/test_json.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/tests/test_python_codegen.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/tests/test_rust_codecs.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/tests/test_rust_codegen.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/tests/test_schema_ir.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/tests/test_security.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/tests/test_transcoder.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-core/tests/test_ts_codegen.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-python/Cargo.toml +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-python/README.md +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-python/src/lib.rs +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-python/tests/test_conformance.py +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-python/tests/test_generated_models.py +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-python/tests/test_json.py +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/crates/polyxml-python/tests/test_polyxml.py +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/python/polyxml/AGENT_GUIDE.md +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/python/polyxml/__init__.py +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/python/polyxml/compat/__init__.py +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/python/polyxml/compat/xsdata.py +0 -0
- {polyxml-0.15.0 → polyxml-0.16.0}/python/polyxml/py.typed +0 -0
|
@@ -549,7 +549,7 @@ dependencies = [
|
|
|
549
549
|
|
|
550
550
|
[[package]]
|
|
551
551
|
name = "polyxml"
|
|
552
|
-
version = "0.
|
|
552
|
+
version = "0.16.0"
|
|
553
553
|
dependencies = [
|
|
554
554
|
"criterion",
|
|
555
555
|
"heck",
|
|
@@ -567,14 +567,14 @@ dependencies = [
|
|
|
567
567
|
|
|
568
568
|
[[package]]
|
|
569
569
|
name = "polyxml-c"
|
|
570
|
-
version = "0.
|
|
570
|
+
version = "0.16.0"
|
|
571
571
|
dependencies = [
|
|
572
572
|
"polyxml",
|
|
573
573
|
]
|
|
574
574
|
|
|
575
575
|
[[package]]
|
|
576
576
|
name = "polyxml-cli"
|
|
577
|
-
version = "0.
|
|
577
|
+
version = "0.16.0"
|
|
578
578
|
dependencies = [
|
|
579
579
|
"clap",
|
|
580
580
|
"glob",
|
|
@@ -588,7 +588,7 @@ dependencies = [
|
|
|
588
588
|
|
|
589
589
|
[[package]]
|
|
590
590
|
name = "polyxml-js"
|
|
591
|
-
version = "0.
|
|
591
|
+
version = "0.16.0"
|
|
592
592
|
dependencies = [
|
|
593
593
|
"napi",
|
|
594
594
|
"napi-build",
|
|
@@ -598,7 +598,7 @@ dependencies = [
|
|
|
598
598
|
|
|
599
599
|
[[package]]
|
|
600
600
|
name = "polyxml-python"
|
|
601
|
-
version = "0.
|
|
601
|
+
version = "0.16.0"
|
|
602
602
|
dependencies = [
|
|
603
603
|
"lexical-core",
|
|
604
604
|
"polyxml",
|
|
@@ -20,6 +20,40 @@ pub enum CppMode {
|
|
|
20
20
|
Module,
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
impl CppMode {
|
|
24
|
+
pub fn from_str_loose(s: &str) -> Option<Self> {
|
|
25
|
+
match s.to_lowercase().trim() {
|
|
26
|
+
"header" | "headeronly" | "header-only" | "headers" | "hpp" => Some(Self::HeaderOnly),
|
|
27
|
+
"module" | "modules" | "cppm" | "c++20-modules" => Some(Self::Module),
|
|
28
|
+
_ => None,
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/// Target backend for C++ serialization/reflection metadata.
|
|
34
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
|
|
35
|
+
pub enum CppBackend {
|
|
36
|
+
/// Zero-dependency standard C++20 (default)
|
|
37
|
+
#[default]
|
|
38
|
+
Standard,
|
|
39
|
+
/// Glaze compile-time reflectionless serde (`glz::meta`)
|
|
40
|
+
Glaze,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
impl CppBackend {
|
|
44
|
+
pub fn from_str_loose(s: &str) -> Option<Self> {
|
|
45
|
+
match s.to_lowercase().trim() {
|
|
46
|
+
"standard" | "std" | "default" | "none" => Some(Self::Standard),
|
|
47
|
+
"glaze" | "glz" => Some(Self::Glaze),
|
|
48
|
+
_ => None,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
pub fn is_glaze(self) -> bool {
|
|
53
|
+
matches!(self, Self::Glaze)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
23
57
|
/// Options configuring modern C++20/C++23 code generation.
|
|
24
58
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
25
59
|
pub struct CppOptions {
|
|
@@ -27,6 +61,8 @@ pub struct CppOptions {
|
|
|
27
61
|
pub namespace: String,
|
|
28
62
|
/// Header-only (.hpp) or C++20 Module (.cppm) mode (default: HeaderOnly)
|
|
29
63
|
pub mode: CppMode,
|
|
64
|
+
/// Target serialization and metadata backend (default: Standard)
|
|
65
|
+
pub backend: CppBackend,
|
|
30
66
|
/// Standard language dialect (default: "c++20")
|
|
31
67
|
pub standard: String,
|
|
32
68
|
/// Emit C++20 defaulted equality operators `bool operator==(const T&) const = default;` (default: true)
|
|
@@ -48,6 +84,7 @@ impl Default for CppOptions {
|
|
|
48
84
|
Self {
|
|
49
85
|
namespace: "polyxml::generated".to_string(),
|
|
50
86
|
mode: CppMode::HeaderOnly,
|
|
87
|
+
backend: CppBackend::Standard,
|
|
51
88
|
standard: "c++20".to_string(),
|
|
52
89
|
emit_equality_operators: true,
|
|
53
90
|
emit_enum_converters: true,
|
|
@@ -229,6 +266,11 @@ impl CppCodegen {
|
|
|
229
266
|
self.emit_root_aliases(&mut out, ir);
|
|
230
267
|
|
|
231
268
|
writeln!(out, "\n}} // namespace {}", ns).unwrap();
|
|
269
|
+
|
|
270
|
+
if self.options.backend.is_glaze() {
|
|
271
|
+
self.emit_glaze_meta(&mut out, ir);
|
|
272
|
+
}
|
|
273
|
+
|
|
232
274
|
out
|
|
233
275
|
}
|
|
234
276
|
|
|
@@ -261,6 +303,11 @@ impl CppCodegen {
|
|
|
261
303
|
self.emit_root_aliases(&mut out, ir);
|
|
262
304
|
|
|
263
305
|
writeln!(out, "\n}} // namespace {}", ns).unwrap();
|
|
306
|
+
|
|
307
|
+
if self.options.backend.is_glaze() {
|
|
308
|
+
self.emit_glaze_meta(&mut out, ir);
|
|
309
|
+
}
|
|
310
|
+
|
|
264
311
|
out
|
|
265
312
|
}
|
|
266
313
|
|
|
@@ -314,8 +361,26 @@ impl CppCodegen {
|
|
|
314
361
|
/// Generate CMakeLists.txt definition for integration via add_subdirectory or FetchContent.
|
|
315
362
|
pub fn generate_cmake(&self, project_name: &str) -> String {
|
|
316
363
|
let safe_name = AsSnakeCase(project_name).to_string();
|
|
317
|
-
|
|
318
|
-
|
|
364
|
+
if self.options.mode == CppMode::Module {
|
|
365
|
+
format!(
|
|
366
|
+
r#"cmake_minimum_required(VERSION 3.28)
|
|
367
|
+
project({safe_name}_models LANGUAGES CXX)
|
|
368
|
+
|
|
369
|
+
set(CMAKE_CXX_STANDARD 20)
|
|
370
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
371
|
+
|
|
372
|
+
add_library({safe_name})
|
|
373
|
+
target_sources({safe_name}
|
|
374
|
+
PUBLIC
|
|
375
|
+
FILE_SET CXX_MODULES FILES
|
|
376
|
+
{safe_name}.cppm
|
|
377
|
+
)
|
|
378
|
+
target_compile_features({safe_name} PUBLIC cxx_std_20)
|
|
379
|
+
"#
|
|
380
|
+
)
|
|
381
|
+
} else {
|
|
382
|
+
format!(
|
|
383
|
+
r#"cmake_minimum_required(VERSION 3.20)
|
|
319
384
|
project({safe_name}_models LANGUAGES CXX)
|
|
320
385
|
|
|
321
386
|
set(CMAKE_CXX_STANDARD 20)
|
|
@@ -328,7 +393,8 @@ target_include_directories({safe_name} INTERFACE
|
|
|
328
393
|
)
|
|
329
394
|
target_compile_features({safe_name} INTERFACE cxx_std_20)
|
|
330
395
|
"#
|
|
331
|
-
|
|
396
|
+
)
|
|
397
|
+
}
|
|
332
398
|
}
|
|
333
399
|
|
|
334
400
|
/// Generate standalone PolyXMLConfig.cmake for `find_package(PolyXML)`.
|
|
@@ -372,7 +438,93 @@ endif()
|
|
|
372
438
|
writeln!(out, "#include <string>").unwrap();
|
|
373
439
|
writeln!(out, "#include <string_view>").unwrap();
|
|
374
440
|
writeln!(out, "#include <variant>").unwrap();
|
|
375
|
-
writeln!(out, "#include <vector
|
|
441
|
+
writeln!(out, "#include <vector>").unwrap();
|
|
442
|
+
|
|
443
|
+
if self.options.backend.is_glaze() {
|
|
444
|
+
writeln!(out, "#include <glaze/glaze.hpp>").unwrap();
|
|
445
|
+
}
|
|
446
|
+
writeln!(out).unwrap();
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
fn emit_glaze_meta(&self, out: &mut String, ir: &SchemaIR) {
|
|
450
|
+
let ns = to_cpp_namespace(&self.options.namespace);
|
|
451
|
+
writeln!(out, "\n// Glaze compile-time reflection metadata\n").unwrap();
|
|
452
|
+
|
|
453
|
+
// 1. Enums
|
|
454
|
+
for type_def in ir.types.values() {
|
|
455
|
+
if let TypeDef::Enum(enum_def) = type_def {
|
|
456
|
+
let enum_name = to_cpp_type_name(&enum_def.qname.local);
|
|
457
|
+
let full_type = format!("{}::{}", ns, enum_name);
|
|
458
|
+
writeln!(out, "template <>").unwrap();
|
|
459
|
+
writeln!(out, "struct glz::meta<{}> {{", full_type).unwrap();
|
|
460
|
+
writeln!(out, " using T = {};", full_type).unwrap();
|
|
461
|
+
if enum_def.variants.is_empty() {
|
|
462
|
+
writeln!(out, " static constexpr auto value = enumerate();").unwrap();
|
|
463
|
+
} else {
|
|
464
|
+
writeln!(out, " static constexpr auto value = enumerate(").unwrap();
|
|
465
|
+
for (i, v) in enum_def.variants.iter().enumerate() {
|
|
466
|
+
let var_name = to_cpp_enum_variant(&v.name);
|
|
467
|
+
let comma = if i + 1 < enum_def.variants.len() {
|
|
468
|
+
","
|
|
469
|
+
} else {
|
|
470
|
+
""
|
|
471
|
+
};
|
|
472
|
+
writeln!(out, " {:?}, T::{}{}", v.value, var_name, comma).unwrap();
|
|
473
|
+
}
|
|
474
|
+
writeln!(out, " );").unwrap();
|
|
475
|
+
}
|
|
476
|
+
writeln!(out, "}};\n").unwrap();
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// 2. Structs
|
|
481
|
+
let sorted_qnames = self.topological_sort_types(ir);
|
|
482
|
+
for qname in sorted_qnames {
|
|
483
|
+
if let Some(TypeDef::Struct(s)) = ir.types.get(&qname) {
|
|
484
|
+
let struct_name = to_cpp_type_name(&s.qname.local);
|
|
485
|
+
let full_type = format!("{}::{}", ns, struct_name);
|
|
486
|
+
writeln!(out, "template <>").unwrap();
|
|
487
|
+
writeln!(out, "struct glz::meta<{}> {{", full_type).unwrap();
|
|
488
|
+
writeln!(out, " using T = {};", full_type).unwrap();
|
|
489
|
+
|
|
490
|
+
let mut field_bindings = Vec::new();
|
|
491
|
+
|
|
492
|
+
// Check for simple_content_base "value"
|
|
493
|
+
if let Some(ref base_qname) = s.base_type {
|
|
494
|
+
let has_value_field = s
|
|
495
|
+
.fields
|
|
496
|
+
.iter()
|
|
497
|
+
.any(|f| f.name == "value" || f.kind == crate::ir::FieldKind::Text);
|
|
498
|
+
if !has_value_field
|
|
499
|
+
&& (PrimitiveType::from_xsd_name(&base_qname.local).is_some()
|
|
500
|
+
|| matches!(ir.types.get(base_qname), Some(TypeDef::Simple(_))))
|
|
501
|
+
{
|
|
502
|
+
field_bindings.push(r#""value", &T::value"#.to_string());
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
for f in &s.fields {
|
|
507
|
+
let field_name = to_cpp_field_name(&f.name);
|
|
508
|
+
field_bindings.push(format!("{:?}, &T::{}", f.xml_name, field_name));
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if field_bindings.is_empty() {
|
|
512
|
+
writeln!(out, " static constexpr auto value = object();").unwrap();
|
|
513
|
+
} else {
|
|
514
|
+
writeln!(out, " static constexpr auto value = object(").unwrap();
|
|
515
|
+
for (i, fb) in field_bindings.iter().enumerate() {
|
|
516
|
+
let comma = if i + 1 < field_bindings.len() {
|
|
517
|
+
","
|
|
518
|
+
} else {
|
|
519
|
+
""
|
|
520
|
+
};
|
|
521
|
+
writeln!(out, " {}{}", fb, comma).unwrap();
|
|
522
|
+
}
|
|
523
|
+
writeln!(out, " );").unwrap();
|
|
524
|
+
}
|
|
525
|
+
writeln!(out, "}};\n").unwrap();
|
|
526
|
+
}
|
|
527
|
+
}
|
|
376
528
|
}
|
|
377
529
|
|
|
378
530
|
fn emit_utilities(&self, out: &mut String) {
|
|
@@ -13,7 +13,7 @@ pub mod python;
|
|
|
13
13
|
pub mod rust;
|
|
14
14
|
pub mod typescript;
|
|
15
15
|
|
|
16
|
-
pub use cpp::{CppCodegen, CppMode, CppOptions};
|
|
16
|
+
pub use cpp::{CppBackend, CppCodegen, CppMode, CppOptions};
|
|
17
17
|
pub use csharp::{CSharpCodegen, CSharpOptions, CSharpRecordKind};
|
|
18
18
|
pub use go::{GoCodegen, GoOptions};
|
|
19
19
|
pub use java::{JavaBackend, JavaCodegen, JavaOptions};
|
|
@@ -3,8 +3,8 @@ use std::process::Command;
|
|
|
3
3
|
use tempfile::tempdir;
|
|
4
4
|
|
|
5
5
|
use polyxml::codegen::cpp::{
|
|
6
|
-
to_cpp_enum_variant, to_cpp_field_name, to_cpp_namespace, to_cpp_type_name,
|
|
7
|
-
CppMode, CppOptions,
|
|
6
|
+
to_cpp_enum_variant, to_cpp_field_name, to_cpp_namespace, to_cpp_type_name, CppBackend,
|
|
7
|
+
CppCodegen, CppMode, CppOptions,
|
|
8
8
|
};
|
|
9
9
|
use polyxml::ir::{
|
|
10
10
|
Cardinality, EnumDef, EnumValue, FieldDef, FieldKind, PrimitiveType, QName, RestrictionFacets,
|
|
@@ -154,6 +154,7 @@ fn test_cpp_struct_and_enum_codegen_compilation() {
|
|
|
154
154
|
let options = CppOptions {
|
|
155
155
|
namespace: "crm::models".to_string(),
|
|
156
156
|
mode: CppMode::HeaderOnly,
|
|
157
|
+
backend: CppBackend::Standard,
|
|
157
158
|
standard: "c++20".to_string(),
|
|
158
159
|
emit_equality_operators: true,
|
|
159
160
|
emit_enum_converters: true,
|
|
@@ -862,3 +863,140 @@ int main() {
|
|
|
862
863
|
"ISO 20022 test binary execution failed"
|
|
863
864
|
);
|
|
864
865
|
}
|
|
866
|
+
|
|
867
|
+
#[test]
|
|
868
|
+
fn test_cpp_mode_and_backend_from_str_loose() {
|
|
869
|
+
assert_eq!(CppMode::from_str_loose("header"), Some(CppMode::HeaderOnly));
|
|
870
|
+
assert_eq!(
|
|
871
|
+
CppMode::from_str_loose("header-only"),
|
|
872
|
+
Some(CppMode::HeaderOnly)
|
|
873
|
+
);
|
|
874
|
+
assert_eq!(CppMode::from_str_loose("hpp"), Some(CppMode::HeaderOnly));
|
|
875
|
+
assert_eq!(CppMode::from_str_loose("modules"), Some(CppMode::Module));
|
|
876
|
+
assert_eq!(CppMode::from_str_loose("module"), Some(CppMode::Module));
|
|
877
|
+
assert_eq!(CppMode::from_str_loose("cppm"), Some(CppMode::Module));
|
|
878
|
+
assert_eq!(CppMode::from_str_loose("unknown"), None);
|
|
879
|
+
|
|
880
|
+
assert_eq!(
|
|
881
|
+
CppBackend::from_str_loose("standard"),
|
|
882
|
+
Some(CppBackend::Standard)
|
|
883
|
+
);
|
|
884
|
+
assert_eq!(
|
|
885
|
+
CppBackend::from_str_loose("default"),
|
|
886
|
+
Some(CppBackend::Standard)
|
|
887
|
+
);
|
|
888
|
+
assert_eq!(CppBackend::from_str_loose("glaze"), Some(CppBackend::Glaze));
|
|
889
|
+
assert_eq!(CppBackend::from_str_loose("glz"), Some(CppBackend::Glaze));
|
|
890
|
+
assert_eq!(CppBackend::from_str_loose("unknown"), None);
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
#[test]
|
|
894
|
+
fn test_cpp_glaze_backend_meta_generation() {
|
|
895
|
+
let mut ir = SchemaIR::new().with_target_namespace("https://example.com/shop");
|
|
896
|
+
|
|
897
|
+
// Enum
|
|
898
|
+
ir.add_type(TypeDef::Enum(EnumDef {
|
|
899
|
+
qname: QName::new(Some("https://example.com/shop"), "OrderStatus"),
|
|
900
|
+
base_type: TypeRef::Primitive(PrimitiveType::String),
|
|
901
|
+
variants: vec![
|
|
902
|
+
EnumValue {
|
|
903
|
+
name: "pending".into(),
|
|
904
|
+
value: "pending".into(),
|
|
905
|
+
documentation: None,
|
|
906
|
+
},
|
|
907
|
+
EnumValue {
|
|
908
|
+
name: "shipped".into(),
|
|
909
|
+
value: "shipped".into(),
|
|
910
|
+
documentation: None,
|
|
911
|
+
},
|
|
912
|
+
],
|
|
913
|
+
documentation: None,
|
|
914
|
+
}));
|
|
915
|
+
|
|
916
|
+
// Struct
|
|
917
|
+
ir.add_type(TypeDef::Struct(StructDef {
|
|
918
|
+
qname: QName::new(Some("https://example.com/shop"), "Order"),
|
|
919
|
+
base_type: None,
|
|
920
|
+
is_abstract: false,
|
|
921
|
+
fields: vec![
|
|
922
|
+
FieldDef {
|
|
923
|
+
name: "order_id".into(),
|
|
924
|
+
xml_name: "orderId".into(),
|
|
925
|
+
namespace: None,
|
|
926
|
+
kind: FieldKind::Element,
|
|
927
|
+
type_ref: TypeRef::Primitive(PrimitiveType::Int),
|
|
928
|
+
cardinality: Cardinality::required_one(),
|
|
929
|
+
nillable: false,
|
|
930
|
+
default_value: None,
|
|
931
|
+
fixed_value: None,
|
|
932
|
+
documentation: None,
|
|
933
|
+
facets: None,
|
|
934
|
+
is_cycle_cut: false,
|
|
935
|
+
},
|
|
936
|
+
FieldDef {
|
|
937
|
+
name: "status".into(),
|
|
938
|
+
xml_name: "status".into(),
|
|
939
|
+
namespace: None,
|
|
940
|
+
kind: FieldKind::Element,
|
|
941
|
+
type_ref: TypeRef::Named(QName::new(
|
|
942
|
+
Some("https://example.com/shop"),
|
|
943
|
+
"OrderStatus",
|
|
944
|
+
)),
|
|
945
|
+
cardinality: Cardinality::required_one(),
|
|
946
|
+
nillable: false,
|
|
947
|
+
default_value: None,
|
|
948
|
+
fixed_value: None,
|
|
949
|
+
documentation: None,
|
|
950
|
+
facets: None,
|
|
951
|
+
is_cycle_cut: false,
|
|
952
|
+
},
|
|
953
|
+
],
|
|
954
|
+
documentation: None,
|
|
955
|
+
}));
|
|
956
|
+
|
|
957
|
+
let options = CppOptions {
|
|
958
|
+
namespace: "shop".to_string(),
|
|
959
|
+
backend: CppBackend::Glaze,
|
|
960
|
+
..Default::default()
|
|
961
|
+
};
|
|
962
|
+
|
|
963
|
+
let codegen = CppCodegen::new(options);
|
|
964
|
+
let header_code = codegen.generate_header(&ir);
|
|
965
|
+
|
|
966
|
+
// Includes Glaze header
|
|
967
|
+
assert!(header_code.contains("#include <glaze/glaze.hpp>"));
|
|
968
|
+
|
|
969
|
+
// Glaze enum reflection
|
|
970
|
+
assert!(header_code.contains("template <>"));
|
|
971
|
+
assert!(header_code.contains("struct glz::meta<shop::OrderStatus> {"));
|
|
972
|
+
assert!(header_code.contains("using T = shop::OrderStatus;"));
|
|
973
|
+
assert!(header_code.contains("static constexpr auto value = enumerate("));
|
|
974
|
+
assert!(header_code.contains("\"pending\", T::Pending,"));
|
|
975
|
+
assert!(header_code.contains("\"shipped\", T::Shipped"));
|
|
976
|
+
|
|
977
|
+
// Glaze struct reflection
|
|
978
|
+
assert!(header_code.contains("struct glz::meta<shop::Order> {"));
|
|
979
|
+
assert!(header_code.contains("using T = shop::Order;"));
|
|
980
|
+
assert!(header_code.contains("static constexpr auto value = object("));
|
|
981
|
+
assert!(header_code.contains("\"orderId\", &T::order_id,"));
|
|
982
|
+
assert!(header_code.contains("\"status\", &T::status"));
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
#[test]
|
|
986
|
+
fn test_cpp_cmake_modules_file_set() {
|
|
987
|
+
let _ir = SchemaIR::new();
|
|
988
|
+
|
|
989
|
+
let options = CppOptions {
|
|
990
|
+
namespace: "telemetry".to_string(),
|
|
991
|
+
mode: CppMode::Module,
|
|
992
|
+
emit_cmake: true,
|
|
993
|
+
..Default::default()
|
|
994
|
+
};
|
|
995
|
+
|
|
996
|
+
let codegen = CppCodegen::new(options);
|
|
997
|
+
let cmake = codegen.generate_cmake("telemetry");
|
|
998
|
+
|
|
999
|
+
assert!(cmake.contains("cmake_minimum_required(VERSION 3.28)"));
|
|
1000
|
+
assert!(cmake.contains("FILE_SET CXX_MODULES FILES"));
|
|
1001
|
+
assert!(cmake.contains("telemetry.cppm"));
|
|
1002
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|