Skip to main content

greentic_types/
op_descriptor.rs

1//! Shared self-describing operation descriptors.
2use alloc::{string::String, vec::Vec};
3
4use serde::{Deserialize, Serialize};
5
6use crate::{cbor_bytes::CborBytes, schema_id::SchemaSource};
7
8const DEFAULT_CONTENT_TYPE: &str = "application/cbor";
9
10/// Schema plus content type metadata for op I/O.
11#[derive(Clone, Debug, PartialEq, Eq)]
12#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
13pub struct IoSchema {
14    /// Schema reference for invocation inputs/outputs.
15    pub schema: SchemaSource,
16    /// Content type partners should use for the referenced payload.
17    pub content_type: String,
18}
19
20impl IoSchema {
21    /// Create a schema wrapper defaulting to `application/cbor`.
22    pub fn new(schema: SchemaSource) -> Self {
23        Self {
24            schema,
25            content_type: DEFAULT_CONTENT_TYPE.to_owned(),
26        }
27    }
28}
29
30/// Example input/output pairs for referencing operations.
31#[derive(Clone, Debug, PartialEq, Eq)]
32#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
33pub struct OpExample {
34    /// Human-readable title for the example.
35    pub title: String,
36    /// Canonical CBOR input payload.
37    pub input_cbor: CborBytes,
38    /// Optional example output payload.
39    pub output_cbor: Option<CborBytes>,
40    /// Free-text notes for the example.
41    pub notes: Option<String>,
42}
43
44/// Descriptor for a single self-describing operation.
45#[derive(Clone, Debug, PartialEq, Eq)]
46#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
47pub struct OpDescriptor {
48    /// Canonical operation name.
49    pub name: String,
50    /// Optional summary describing the operation.
51    pub summary: Option<String>,
52    /// Input schema descriptor.
53    pub input: IoSchema,
54    /// Output schema descriptor.
55    pub output: IoSchema,
56    /// Documented examples.
57    pub examples: Vec<OpExample>,
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63    use crate::cbor_bytes::CborBytes;
64    use crate::schema_id::SchemaSource;
65    use alloc::string::ToString;
66
67    #[test]
68    fn descriptor_serde_roundtrip() {
69        let schema = SchemaSource::InlineCbor(CborBytes::new(vec![0x01]));
70        let io = IoSchema {
71            schema,
72            content_type: "application/cbor".to_string(),
73        };
74        let descriptor = OpDescriptor {
75            name: "op".to_string(),
76            summary: Some("desc".to_string()),
77            input: io.clone(),
78            output: io,
79            examples: vec![],
80        };
81        let serialized = match serde_json::to_string(&descriptor) {
82            Ok(json) => json,
83            Err(err) => panic!("serialize failed: {err:?}"),
84        };
85        let roundtrip: OpDescriptor = match serde_json::from_str(&serialized) {
86            Ok(desc) => desc,
87            Err(err) => panic!("deserialize failed: {err:?}"),
88        };
89        assert_eq!(roundtrip.name, "op");
90    }
91}