Skip to main content

merman_bindings_core/
lib.rs

1#![forbid(unsafe_code)]
2
3//! Safe shared facade used by external binding crates.
4//!
5//! This crate owns options parsing, renderer setup, result-code classification, and byte payload
6//! production. Unsafe transport concerns such as raw pointers and owned C buffers remain in
7//! `merman-ffi`.
8
9mod common;
10mod engine;
11mod metadata;
12
13#[cfg(feature = "ascii")]
14mod ascii;
15#[cfg(feature = "render")]
16mod render;
17
18pub use common::{BindingError, BindingStatus, error_payload_json_bytes};
19pub use engine::BindingEngine;
20pub use metadata::{
21    ascii_supported_diagrams, ascii_supported_diagrams_json, supported_diagrams,
22    supported_diagrams_json, supported_host_theme_presets, supported_host_theme_presets_json,
23    supported_themes, supported_themes_json,
24};
25
26#[cfg(feature = "ascii")]
27pub use ascii::render_ascii;
28#[cfg(feature = "render")]
29pub use render::{layout_json, parse_json, render_svg, validate_json};
30
31#[cfg(not(feature = "ascii"))]
32pub fn render_ascii(source: &[u8], options_json: &[u8]) -> Result<Vec<u8>, BindingError> {
33    let _ = (source, options_json);
34    Err(common::feature_required_error("ASCII rendering", "ascii"))
35}
36
37#[cfg(not(feature = "render"))]
38pub fn render_svg(source: &[u8], options_json: &[u8]) -> Result<Vec<u8>, BindingError> {
39    let _ = (source, options_json);
40    Err(common::feature_required_error("SVG rendering", "render"))
41}
42
43#[cfg(not(feature = "render"))]
44pub fn parse_json(source: &[u8], options_json: &[u8]) -> Result<Vec<u8>, BindingError> {
45    let _ = (source, options_json);
46    Err(common::feature_required_error("parse_json", "render"))
47}
48
49#[cfg(not(feature = "render"))]
50pub fn layout_json(source: &[u8], options_json: &[u8]) -> Result<Vec<u8>, BindingError> {
51    let _ = (source, options_json);
52    Err(common::feature_required_error("layout_json", "render"))
53}
54
55#[cfg(not(feature = "render"))]
56pub fn validate_json(source: &[u8], options_json: &[u8]) -> Result<Vec<u8>, BindingError> {
57    let _ = (source, options_json);
58    common::validation_payload_json(Err(common::feature_required_error("validation", "render")))
59}
60
61#[cfg(all(test, any(not(feature = "render"), not(feature = "ascii"))))]
62mod tests {
63    use super::*;
64    #[cfg(not(feature = "render"))]
65    use serde_json::Value;
66
67    #[cfg(not(feature = "render"))]
68    #[test]
69    fn render_entry_points_report_missing_render_feature() {
70        let err = render_svg(b"flowchart TD\nA", b"").unwrap_err();
71        assert_eq!(err.status(), BindingStatus::UnsupportedFormat);
72        assert!(err.message().contains("render feature"));
73
74        let err = parse_json(b"flowchart TD\nA", b"").unwrap_err();
75        assert_eq!(err.status(), BindingStatus::UnsupportedFormat);
76
77        let err = layout_json(b"flowchart TD\nA", b"").unwrap_err();
78        assert_eq!(err.status(), BindingStatus::UnsupportedFormat);
79
80        let validation: Value =
81            serde_json::from_slice(&validate_json(b"flowchart TD\nA", b"").unwrap()).unwrap();
82        assert_eq!(validation["valid"], false);
83        assert_eq!(
84            validation["code_name"],
85            BindingStatus::UnsupportedFormat.code_name()
86        );
87    }
88
89    #[cfg(not(feature = "ascii"))]
90    #[test]
91    fn ascii_entry_point_reports_missing_ascii_feature() {
92        let err = render_ascii(b"flowchart TD\nA", b"").unwrap_err();
93        assert_eq!(err.status(), BindingStatus::UnsupportedFormat);
94        assert!(err.message().contains("ascii feature"));
95    }
96}