ddex_parser/streaming/
element.rs

1// src/streaming/element.rs
2//! Parsed element types for streaming interface
3
4use ddex_core::models::graph::*;
5use ddex_core::models::versions::ERNVersion;
6use ddex_core::models::Identifier;
7
8/// Element yielded by streaming parser
9#[derive(Debug, Clone)]
10pub enum ParsedElement {
11    /// Message header (yielded first)
12    Header {
13        sender: MessageSender,
14        recipients: Vec<MessageRecipient>,
15        message_id: Identifier,
16        created_date_time: String,
17        version: ERNVersion,
18    },
19    /// Complete release element
20    Release(Release),
21    /// Complete resource element
22    Resource(Resource),
23    /// Complete party element
24    Party(Party),
25    /// Complete deal element
26    Deal(Deal),
27    /// End of stream marker
28    EndOfStream,
29}
30
31impl ParsedElement {
32    /// Get the element type as a string
33    pub fn element_type(&self) -> &'static str {
34        match self {
35            ParsedElement::Header { .. } => "Header",
36            ParsedElement::Release(_) => "Release",
37            ParsedElement::Resource(_) => "Resource",
38            ParsedElement::Party(_) => "Party",
39            ParsedElement::Deal(_) => "Deal",
40            ParsedElement::EndOfStream => "EndOfStream",
41        }
42    }
43
44    /// Estimate memory usage of this element
45    pub fn memory_estimate(&self) -> usize {
46        match self {
47            ParsedElement::Header { .. } => std::mem::size_of::<MessageHeader>() + 1024,
48            ParsedElement::Release(r) => estimate_release_size(r),
49            ParsedElement::Resource(r) => estimate_resource_size(r),
50            ParsedElement::Party(p) => estimate_party_size(p),
51            ParsedElement::Deal(d) => estimate_deal_size(d),
52            ParsedElement::EndOfStream => std::mem::size_of::<ParsedElement>(),
53        }
54    }
55
56    /// Get a reference ID if applicable
57    pub fn reference_id(&self) -> Option<&str> {
58        match self {
59            ParsedElement::Release(r) => Some(&r.release_reference),
60            ParsedElement::Resource(r) => Some(&r.resource_reference),
61            ParsedElement::Party(p) => p.party_id.first().map(|id| id.value.as_str()),
62            ParsedElement::Deal(d) => d.deal_reference.as_deref(),
63            _ => None,
64        }
65    }
66
67    /// Check if this element is complete and ready for consumption
68    pub fn is_complete(&self) -> bool {
69        match self {
70            ParsedElement::Header {
71                sender, message_id, ..
72            } => !sender.party_name.is_empty() && !message_id.value.is_empty(),
73            ParsedElement::Release(r) => {
74                !r.release_reference.is_empty() && !r.release_title.is_empty()
75            }
76            ParsedElement::Resource(r) => {
77                !r.resource_reference.is_empty() && !r.reference_title.is_empty()
78            }
79            ParsedElement::Party(p) => !p.party_id.is_empty() && !p.party_name.is_empty(),
80            ParsedElement::Deal(d) => d.deal_reference.as_ref().is_some_and(|r| !r.is_empty()),
81            ParsedElement::EndOfStream => true,
82        }
83    }
84}
85
86/// Rough memory estimation for release
87fn estimate_release_size(release: &Release) -> usize {
88    let mut size = std::mem::size_of::<Release>();
89    size += release.release_reference.len();
90    size += release.release_id.len() * std::mem::size_of::<Identifier>();
91    size += release.release_title.len() * 100; // Estimate for LocalizedString
92    size += release.display_artist.len() * std::mem::size_of::<Artist>();
93    size += release
94        .genre
95        .iter()
96        .map(|g| g.genre_text.len())
97        .sum::<usize>();
98    size += release.release_resource_reference_list.len()
99        * std::mem::size_of::<ReleaseResourceReference>();
100    size
101}
102
103/// Rough memory estimation for resource
104fn estimate_resource_size(resource: &Resource) -> usize {
105    let mut size = std::mem::size_of::<Resource>();
106    size += resource.resource_reference.len();
107    size += std::mem::size_of::<ResourceType>();
108    size += resource.resource_id.len() * std::mem::size_of::<Identifier>();
109    size += resource.reference_title.len() * 100; // Estimate for LocalizedString
110    size
111}
112
113/// Rough memory estimation for party
114fn estimate_party_size(party: &Party) -> usize {
115    let mut size = std::mem::size_of::<Party>();
116    size += party
117        .party_id
118        .iter()
119        .map(|id| id.value.len())
120        .sum::<usize>();
121    size += party.party_name.len() * 100; // Estimate for LocalizedString
122    size += party.party_id.len() * std::mem::size_of::<Identifier>();
123    size
124}
125
126/// Rough memory estimation for deal
127fn estimate_deal_size(deal: &Deal) -> usize {
128    let mut size = std::mem::size_of::<Deal>();
129    size += deal.deal_reference.as_ref().map_or(0, |r| r.len());
130    size +=
131        deal.deal_terms.commercial_model_type.len() * std::mem::size_of::<CommercialModelType>();
132    size += deal.deal_terms.use_type.len() * std::mem::size_of::<UseType>();
133    size += deal
134        .deal_terms
135        .territory_code
136        .iter()
137        .map(|t| t.len())
138        .sum::<usize>();
139    // Add DealTerms size estimate
140    size += std::mem::size_of::<DealTerms>();
141    size
142}
143
144/// Builder for ParsedElement::Header
145#[derive(Debug, Default)]
146pub struct HeaderBuilder {
147    sender: Option<MessageSender>,
148    recipients: Vec<MessageRecipient>,
149    message_id: Option<Identifier>,
150    created_date_time: Option<String>,
151    version: Option<ERNVersion>,
152}
153
154impl HeaderBuilder {
155    pub fn new() -> Self {
156        Self::default()
157    }
158
159    pub fn sender(mut self, sender: MessageSender) -> Self {
160        self.sender = Some(sender);
161        self
162    }
163
164    pub fn add_recipient(mut self, recipient: MessageRecipient) -> Self {
165        self.recipients.push(recipient);
166        self
167    }
168
169    pub fn message_id(mut self, id: Identifier) -> Self {
170        self.message_id = Some(id);
171        self
172    }
173
174    pub fn created_date_time(mut self, datetime: String) -> Self {
175        self.created_date_time = Some(datetime);
176        self
177    }
178
179    pub fn version(mut self, version: ERNVersion) -> Self {
180        self.version = Some(version);
181        self
182    }
183
184    pub fn build(self) -> Result<ParsedElement, String> {
185        let sender = self.sender.ok_or("Missing sender")?;
186        let message_id = self.message_id.ok_or("Missing message ID")?;
187        let created_date_time = self.created_date_time.ok_or("Missing created date time")?;
188        let version = self.version.ok_or("Missing version")?;
189
190        Ok(ParsedElement::Header {
191            sender,
192            recipients: self.recipients,
193            message_id,
194            created_date_time,
195            version,
196        })
197    }
198}