polyxml 0.30.7__tar.gz → 0.32.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.
Files changed (73) hide show
  1. {polyxml-0.30.7 → polyxml-0.32.0}/Cargo.lock +6 -6
  2. {polyxml-0.30.7 → polyxml-0.32.0}/Cargo.toml +1 -1
  3. {polyxml-0.30.7 → polyxml-0.32.0}/PKG-INFO +1 -1
  4. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/codegen/python/aot.rs +2 -0
  5. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/codegen/rust/mod.rs +155 -9
  6. polyxml-0.32.0/crates/polyxml-core/src/ir/chunker.rs +458 -0
  7. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/ir/mod.rs +327 -1
  8. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_rust_codegen.rs +77 -0
  9. {polyxml-0.30.7 → polyxml-0.32.0}/pyproject.toml +1 -1
  10. {polyxml-0.30.7 → polyxml-0.32.0}/README.md +0 -0
  11. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/Cargo.toml +0 -0
  12. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/README.md +0 -0
  13. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/benches/core_benchmarks.rs +0 -0
  14. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/benches/support/tag_dispatch_fixtures.rs +0 -0
  15. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/benches/tag_dispatch.rs +0 -0
  16. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/codegen/cpp/mod.rs +0 -0
  17. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/codegen/csharp/mod.rs +0 -0
  18. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/codegen/go/mod.rs +0 -0
  19. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/codegen/java/codec.rs +0 -0
  20. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/codegen/java/mod.rs +0 -0
  21. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/codegen/java/models.rs +0 -0
  22. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/codegen/mod.rs +0 -0
  23. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/codegen/python/mod.rs +0 -0
  24. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/codegen/typescript/mod.rs +0 -0
  25. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/converters.rs +0 -0
  26. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/error.rs +0 -0
  27. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/ir/tarjan.rs +0 -0
  28. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/json.rs +0 -0
  29. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/lib.rs +0 -0
  30. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/parser.rs +0 -0
  31. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/schema.rs +0 -0
  32. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/schema_parser/mod.rs +0 -0
  33. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/serializer.rs +0 -0
  34. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/transcoder.rs +0 -0
  35. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/src/value.rs +0 -0
  36. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/fixtures/lexical_union.xsd +0 -0
  37. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/fixtures/mixed_content.xsd +0 -0
  38. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/fixtures/ts_mixed_content_inheritance.xsd +0 -0
  39. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_adversarial_identifiers.rs +0 -0
  40. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_conformance.rs +0 -0
  41. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_core.rs +0 -0
  42. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_cpp_codegen.rs +0 -0
  43. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_csharp_codegen.rs +0 -0
  44. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_go_codegen.rs +0 -0
  45. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_java_codegen.rs +0 -0
  46. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_json.rs +0 -0
  47. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_lexical_union_codegen.rs +0 -0
  48. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_mixed_content.rs +0 -0
  49. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_pattern_codegen.rs +0 -0
  50. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_python_codegen.rs +0 -0
  51. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_rust_codecs.rs +0 -0
  52. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_schema_audit.rs +0 -0
  53. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_schema_ir.rs +0 -0
  54. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_security.rs +0 -0
  55. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_transcoder.rs +0 -0
  56. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_ts_codegen.rs +0 -0
  57. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_unbounded_choice.rs +0 -0
  58. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-core/tests/test_xsi_type.rs +0 -0
  59. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-python/Cargo.toml +0 -0
  60. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-python/README.md +0 -0
  61. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-python/benches/aot_vs_dataclass.py +0 -0
  62. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-python/src/lib.rs +0 -0
  63. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-python/tests/test_conformance.py +0 -0
  64. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-python/tests/test_generated_models.py +0 -0
  65. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-python/tests/test_json.py +0 -0
  66. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-python/tests/test_mixed_content.py +0 -0
  67. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-python/tests/test_polyxml.py +0 -0
  68. {polyxml-0.30.7 → polyxml-0.32.0}/crates/polyxml-python/tests/test_xsi_type.py +0 -0
  69. {polyxml-0.30.7 → polyxml-0.32.0}/python/polyxml/AGENT_GUIDE.md +0 -0
  70. {polyxml-0.30.7 → polyxml-0.32.0}/python/polyxml/__init__.py +0 -0
  71. {polyxml-0.30.7 → polyxml-0.32.0}/python/polyxml/compat/__init__.py +0 -0
  72. {polyxml-0.30.7 → polyxml-0.32.0}/python/polyxml/compat/xsdata.py +0 -0
  73. {polyxml-0.30.7 → polyxml-0.32.0}/python/polyxml/py.typed +0 -0
@@ -608,7 +608,7 @@ dependencies = [
608
608
 
609
609
  [[package]]
610
610
  name = "polyxml"
611
- version = "0.30.7"
611
+ version = "0.32.0"
612
612
  dependencies = [
613
613
  "criterion",
614
614
  "heck",
@@ -629,14 +629,14 @@ dependencies = [
629
629
 
630
630
  [[package]]
631
631
  name = "polyxml-c"
632
- version = "0.30.7"
632
+ version = "0.32.0"
633
633
  dependencies = [
634
634
  "polyxml",
635
635
  ]
636
636
 
637
637
  [[package]]
638
638
  name = "polyxml-cli"
639
- version = "0.30.7"
639
+ version = "0.32.0"
640
640
  dependencies = [
641
641
  "clap",
642
642
  "glob",
@@ -650,7 +650,7 @@ dependencies = [
650
650
 
651
651
  [[package]]
652
652
  name = "polyxml-js"
653
- version = "0.30.7"
653
+ version = "0.32.0"
654
654
  dependencies = [
655
655
  "napi",
656
656
  "napi-build",
@@ -660,7 +660,7 @@ dependencies = [
660
660
 
661
661
  [[package]]
662
662
  name = "polyxml-python"
663
- version = "0.30.7"
663
+ version = "0.32.0"
664
664
  dependencies = [
665
665
  "lexical-core",
666
666
  "polyxml",
@@ -670,7 +670,7 @@ dependencies = [
670
670
 
671
671
  [[package]]
672
672
  name = "polyxml-wasm"
673
- version = "0.30.7"
673
+ version = "0.32.0"
674
674
  dependencies = [
675
675
  "polyxml",
676
676
  "quick-xml",
@@ -3,7 +3,7 @@ resolver = "2"
3
3
  members = ["crates/polyxml-core", "crates/polyxml-python"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.30.7"
6
+ version = "0.32.0"
7
7
  edition = "2021"
8
8
  rust-version = "1.80"
9
9
  license = "MIT"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polyxml
3
- Version: 0.30.7
3
+ Version: 0.32.0
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -147,6 +147,8 @@ restored_json = {module_name}.<ModelName>.from_json(json_data)
147
147
  pyo3: true,
148
148
  pyo3_module_name: Some(module_name.clone()),
149
149
  custom_header: self.options.custom_header.clone(),
150
+ split_units: None,
151
+ chunk_size: None,
150
152
  };
151
153
  let rust_codegen = RustCodegen::new(rust_opts);
152
154
  let lib_rs = rust_codegen.generate_module(ir);
@@ -42,6 +42,12 @@ pub struct RustOptions {
42
42
  pub pyo3_module_name: Option<String>,
43
43
  /// Custom header text to prepend to generated files (default: None).
44
44
  pub custom_header: Option<String>,
45
+ /// Split oversized modules into bounded topological chunks (default: None, auto-split if > 400 types).
46
+ #[serde(default)]
47
+ pub split_units: Option<bool>,
48
+ /// Target maximum types per compilation unit chunk (default: 250).
49
+ #[serde(default)]
50
+ pub chunk_size: Option<usize>,
45
51
  }
46
52
 
47
53
  impl Default for RustOptions {
@@ -58,6 +64,8 @@ impl Default for RustOptions {
58
64
  pyo3: false,
59
65
  pyo3_module_name: None,
60
66
  custom_header: None,
67
+ split_units: None,
68
+ chunk_size: None,
61
69
  }
62
70
  }
63
71
  }
@@ -263,12 +271,7 @@ impl RustCodegen {
263
271
  continue;
264
272
  }
265
273
  out.push('\n');
266
- match type_def {
267
- TypeDef::Simple(s) => self.emit_simple_type(&mut out, s, &types_with_lifetime),
268
- TypeDef::Enum(e) => self.emit_enum(&mut out, e),
269
- TypeDef::Union(u) => self.emit_union(&mut out, u, &types_with_lifetime, ir),
270
- TypeDef::Struct(s) => self.emit_struct(&mut out, s, &types_with_lifetime, ir),
271
- }
274
+ self.emit_single_type(&mut out, type_def, &types_with_lifetime, ir);
272
275
  }
273
276
 
274
277
  if self.options.emit_root_aliases {
@@ -285,6 +288,147 @@ impl RustCodegen {
285
288
  out.replace("var_r#", "var_")
286
289
  }
287
290
 
291
+ fn emit_single_type(
292
+ &self,
293
+ out: &mut String,
294
+ type_def: &TypeDef,
295
+ types_with_lifetime: &HashSet<QName>,
296
+ ir: &SchemaIR,
297
+ ) {
298
+ match type_def {
299
+ TypeDef::Simple(s) => self.emit_simple_type(out, s, types_with_lifetime),
300
+ TypeDef::Enum(e) => self.emit_enum(out, e),
301
+ TypeDef::Union(u) => self.emit_union(out, u, types_with_lifetime, ir),
302
+ TypeDef::Struct(s) => self.emit_struct(out, s, types_with_lifetime, ir),
303
+ }
304
+ }
305
+
306
+ /// Generate a multi-file or single-file module representation.
307
+ /// When `split_units` is requested or the type count exceeds the threshold,
308
+ /// emits topologically sorted, bounded chunk modules (`chunk_00.rs`, `chunk_01.rs`, ...)
309
+ /// and a parent `mod.rs` that re-exports all chunks.
310
+ pub fn generate_files(&self, ir: &SchemaIR, base_name: &str) -> Vec<(String, String)> {
311
+ set_type_name_map(build_type_name_map(ir, |local| {
312
+ AsPascalCase(local).to_string()
313
+ }));
314
+
315
+ let emitted_count = ir.types.keys().filter(|q| !ir.is_external_type(q)).count();
316
+ let should_split = self.options.split_units.unwrap_or(emitted_count > 400);
317
+ let chunk_size = self.options.chunk_size.unwrap_or(250);
318
+
319
+ if !should_split {
320
+ let code = self.generate_module(ir);
321
+ if base_name == "mod" {
322
+ return vec![("mod.rs".to_string(), code)];
323
+ }
324
+ return vec![
325
+ (format!("{}.rs", base_name), code),
326
+ (
327
+ "mod.rs".to_string(),
328
+ format!("pub mod {base_name};\npub use {base_name}::*;\n"),
329
+ ),
330
+ ];
331
+ }
332
+
333
+ let plan = ir.partition_topological_chunks(chunk_size);
334
+ if plan.chunks.len() <= 1 {
335
+ let code = self.generate_module(ir);
336
+ if base_name == "mod" {
337
+ return vec![("mod.rs".to_string(), code)];
338
+ }
339
+ return vec![
340
+ (format!("{}.rs", base_name), code),
341
+ (
342
+ "mod.rs".to_string(),
343
+ format!("pub mod {base_name};\npub use {base_name}::*;\n"),
344
+ ),
345
+ ];
346
+ }
347
+
348
+ let types_with_lifetime = if self.options.zero_copy {
349
+ self.compute_types_with_lifetime(ir)
350
+ } else {
351
+ HashSet::new()
352
+ };
353
+
354
+ let mut files = Vec::new();
355
+
356
+ // 1. Chunks
357
+ for chunk in &plan.chunks {
358
+ let mut out = String::new();
359
+ if let Some(ref header) = self.options.custom_header {
360
+ let trimmed = header.trim();
361
+ if !trimmed.is_empty() {
362
+ out.push_str(trimmed);
363
+ out.push_str("\n\n");
364
+ }
365
+ }
366
+ out.push_str(
367
+ "// @generated by PolyXML Compiler (https://github.com/polyxml/PolyXML)\n",
368
+ );
369
+ out.push_str(
370
+ "#![allow(dead_code, unused_imports, unused_mut, unused_variables, unused_assignments, non_camel_case_types, non_snake_case)]\n\n",
371
+ );
372
+
373
+ self.emit_imports(&mut out, !types_with_lifetime.is_empty());
374
+ out.push_str("\nuse super::*;\n");
375
+
376
+ for qname in &chunk.types {
377
+ if let Some(type_def) = ir.types.get(qname) {
378
+ out.push('\n');
379
+ self.emit_single_type(&mut out, type_def, &types_with_lifetime, ir);
380
+ }
381
+ }
382
+
383
+ let code = out.replace("var_r#", "var_");
384
+ files.push((format!("{}.rs", chunk.name), code));
385
+ }
386
+
387
+ // 2. mod.rs
388
+ let mut mod_out = String::new();
389
+ if let Some(ref header) = self.options.custom_header {
390
+ let trimmed = header.trim();
391
+ if !trimmed.is_empty() {
392
+ mod_out.push_str(trimmed);
393
+ mod_out.push_str("\n\n");
394
+ }
395
+ }
396
+ mod_out
397
+ .push_str("// @generated by PolyXML Compiler (https://github.com/polyxml/PolyXML)\n");
398
+ mod_out.push_str(
399
+ "#![allow(dead_code, unused_imports, unused_mut, unused_variables, unused_assignments, non_camel_case_types, non_snake_case)]\n\n",
400
+ );
401
+
402
+ self.emit_imports(&mut mod_out, !types_with_lifetime.is_empty());
403
+ mod_out.push('\n');
404
+
405
+ for chunk in &plan.chunks {
406
+ let _ = writeln!(mod_out, "pub mod {};", chunk.name);
407
+ }
408
+ mod_out.push('\n');
409
+ for chunk in &plan.chunks {
410
+ let _ = writeln!(mod_out, "pub use {}::*;", chunk.name);
411
+ }
412
+
413
+ if self.options.emit_codecs {
414
+ self.emit_codec_helpers(&mut mod_out);
415
+ }
416
+
417
+ if self.options.emit_root_aliases {
418
+ self.emit_root_aliases(&mut mod_out, ir, &types_with_lifetime);
419
+ }
420
+
421
+ if self.options.pyo3 {
422
+ let sorted_types = self.order_types(ir);
423
+ self.emit_pymodule(&mut mod_out, ir, &sorted_types);
424
+ }
425
+
426
+ let mod_code = mod_out.replace("var_r#", "var_");
427
+ files.push(("mod.rs".to_string(), mod_code));
428
+
429
+ files
430
+ }
431
+
288
432
  /// Fixed-point analysis determining which types in SchemaIR require a lifetime parameter `<'a>`.
289
433
  fn compute_types_with_lifetime(&self, ir: &SchemaIR) -> HashSet<QName> {
290
434
  let mut requires_lifetime = HashSet::new();
@@ -896,7 +1040,9 @@ impl RustCodegen {
896
1040
 
897
1041
  fn emit_codec_helpers(&self, out: &mut String) {
898
1042
  out.push_str("\n#[allow(dead_code)]\n");
899
- out.push_str("fn skip_xml_element(reader: &mut Reader<&[u8]>) -> Result<()> {\n");
1043
+ out.push_str(
1044
+ "pub(crate) fn skip_xml_element(reader: &mut Reader<&[u8]>) -> Result<()> {\n",
1045
+ );
900
1046
  out.push_str(" let mut depth = 1;\n");
901
1047
  out.push_str(" loop {\n");
902
1048
  out.push_str(" match reader.read_event()? {\n");
@@ -916,7 +1062,7 @@ impl RustCodegen {
916
1062
 
917
1063
  if self.options.zero_copy {
918
1064
  out.push_str("#[allow(dead_code)]\n");
919
- out.push_str("fn read_element_text<'a>(reader: &mut Reader<&'a [u8]>, tag_name: &str) -> Result<Cow<'a, str>> {\n");
1065
+ out.push_str("pub(crate) fn read_element_text<'a>(reader: &mut Reader<&'a [u8]>, tag_name: &str) -> Result<Cow<'a, str>> {\n");
920
1066
  out.push_str(" let mut text = Cow::Borrowed(\"\");\n");
921
1067
  out.push_str(" loop {\n");
922
1068
  out.push_str(" match reader.read_event()? {\n");
@@ -963,7 +1109,7 @@ impl RustCodegen {
963
1109
  out.push_str("}\n");
964
1110
  } else {
965
1111
  out.push_str("#[allow(dead_code)]\n");
966
- out.push_str("fn read_element_text(reader: &mut Reader<&[u8]>, tag_name: &str) -> Result<String> {\n");
1112
+ out.push_str("pub(crate) fn read_element_text(reader: &mut Reader<&[u8]>, tag_name: &str) -> Result<String> {\n");
967
1113
  out.push_str(" let mut text = String::new();\n");
968
1114
  out.push_str(" loop {\n");
969
1115
  out.push_str(" match reader.read_event()? {\n");