1use std::fmt;
2use xml::name::OwnedName;
3
4#[derive(Clone, PartialEq, Eq, Hash, fmt_derive::Debug)]
5pub enum PrintSchemaDocument {
7 PrintCapabilities(PrintCapabilitiesDocument),
9 PrintTicket(PrintTicketDocument),
11}
12
13#[derive(Clone, PartialEq, Eq, Hash, fmt_derive::Debug)]
14pub struct PrintCapabilitiesDocument {
16 pub properties: Vec<Property>,
18 pub parameter_defs: Vec<ParameterDef>,
20 pub features: Vec<PrintFeature>,
22}
23
24#[derive(Clone, PartialEq, Eq, Hash, fmt_derive::Debug)]
25pub struct PrintTicketDocument {
27 pub properties: Vec<Property>,
29 pub parameter_inits: Vec<ParameterInit>,
31 pub features: Vec<PrintFeature>,
33}
34
35#[derive(Clone, PartialEq, Eq, Hash, fmt_derive::Debug)]
36pub struct PrintFeature {
38 #[fmt("{}", self.name)]
40 pub name: OwnedName,
41 pub properties: Vec<Property>,
43 pub options: Vec<PrintFeatureOption>,
45 pub features: Vec<PrintFeature>,
47}
48
49#[derive(Clone, PartialEq, Eq, Hash, fmt_derive::Debug)]
50pub struct ParameterInit {
52 #[fmt("{}", self.name)]
54 pub name: OwnedName,
55 #[fmt("{:?}", self.value)]
57 pub value: PropertyValue,
58}
59
60#[derive(Clone, PartialEq, Eq, Hash, fmt_derive::Debug)]
61pub struct ParameterDef {
63 #[fmt("{}", self.name)]
65 pub name: OwnedName,
66 pub properties: Vec<Property>,
68}
69
70#[derive(Clone, PartialEq, Eq, Hash, fmt_derive::Debug)]
71pub struct PrintFeatureOption {
73 #[fmt("{}", self.name.as_ref().map(|x| x.to_string()).unwrap_or("<unnamed>".to_string()))]
75 pub name: Option<OwnedName>,
76 pub scored_properties: Vec<ScoredProperty>,
78 pub properties: Vec<Property>,
80}
81
82#[derive(Clone, PartialEq, Eq, Hash, fmt_derive::Debug)]
83pub struct ScoredProperty {
87 #[fmt("{}", self.name.as_ref().map(|x| x.to_string()).unwrap_or("<unnamed>".to_string()))]
89 pub name: Option<OwnedName>,
90 #[fmt("{}", self.parameter_ref.as_ref().map(|x| x.to_string()).unwrap_or("<unnamed>".to_string()))]
92 pub parameter_ref: Option<OwnedName>,
93 #[fmt("{}", self.value.as_ref().map(|x| format!("{:?}", x)).unwrap_or("<none>".to_string()))]
95 pub value: Option<PropertyValue>,
96 pub scored_properties: Vec<ScoredProperty>,
98 pub properties: Vec<Property>,
100}
101
102#[derive(Clone, PartialEq, Eq, Hash, fmt_derive::Debug)]
103pub struct Property {
105 #[fmt("{}", self.name)]
107 pub name: OwnedName,
108 #[fmt("{}", self.value.as_ref().map(|x| format!("{:?}", x)).unwrap_or("<none>".to_string()))]
110 pub value: Option<PropertyValue>,
111 pub properties: Vec<Property>,
113}
114
115#[derive(Clone, PartialEq, Eq, Hash)]
116pub enum PropertyValue {
118 String(String),
120 Integer(i32),
122 QName(OwnedName),
124 Unknown(OwnedName, String),
126}
127
128impl fmt::Debug for PropertyValue {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 match self {
131 PropertyValue::String(s) => write!(f, "String({:?})", s),
132 PropertyValue::Integer(i) => write!(f, "Integer({})", i),
133 PropertyValue::QName(q) => write!(f, "QName({})", q),
134 PropertyValue::Unknown(n, s) => write!(f, "Unknown({}, {:?})", n, s),
135 }
136 }
137}
138
139impl ParameterDef {
140 pub fn default_value(&self) -> Option<&PropertyValue> {
142 self.properties
143 .iter()
144 .find(|x| {
145 x.name.local_name == "DefaultValue" && x.name.namespace_ref() == Some(super::NS_PSF)
146 })
147 .and_then(|x| x.value.as_ref())
148 }
149}
150
151impl PropertyValue {
152 pub fn xsi_type(&self) -> OwnedName {
154 match self {
155 PropertyValue::String(_) => OwnedName::qualified("string", super::NS_XSD, Some("xsd")),
156 PropertyValue::Integer(_) => {
157 OwnedName::qualified("integer", super::NS_XSD, Some("xsd"))
158 }
159 PropertyValue::QName(_) => OwnedName::qualified("QName", super::NS_XSD, Some("xsd")),
160 PropertyValue::Unknown(n, _) => n.clone(),
161 }
162 }
163 pub fn string(&self) -> Option<&str> {
165 match self {
166 PropertyValue::String(s) => Some(s),
167 _ => None,
168 }
169 }
170 pub fn integer(&self) -> Option<i32> {
172 match self {
173 PropertyValue::Integer(i) => Some(*i),
174 _ => None,
175 }
176 }
177 pub fn qualified_name(&self) -> Option<&OwnedName> {
179 match self {
180 PropertyValue::QName(q) => Some(q),
181 _ => None,
182 }
183 }
184}
185
186impl PrintFeatureOption {
187 pub fn parameters_dependent(&self) -> Vec<OwnedName> {
189 let mut result = vec![];
190 for scored_property in &self.scored_properties {
191 result.extend(scored_property.parameters_dependent());
192 }
193 result
194 }
195}
196
197impl ScoredProperty {
198 pub fn parameters_dependent(&self) -> Vec<OwnedName> {
200 let mut result = vec![];
201 if let Some(ref parameter_ref) = self.parameter_ref {
202 result.push(parameter_ref.clone());
203 }
204 for scored_property in &self.scored_properties {
205 result.extend(scored_property.parameters_dependent());
206 }
207 result
208 }
209
210 pub fn value_with<'a>(&'a self, parameters: &'a [ParameterInit]) -> Option<&'a PropertyValue> {
212 if let Some(ref parameter_ref) = self.parameter_ref {
213 parameters
214 .iter()
215 .find(|x| x.name == *parameter_ref)
216 .map(|x| &x.value)
217 } else {
218 self.value.as_ref()
219 }
220 }
221}
222
223impl From<PrintTicketDocument> for PrintSchemaDocument {
224 fn from(value: PrintTicketDocument) -> Self {
225 PrintSchemaDocument::PrintTicket(value)
226 }
227}
228
229impl From<PrintCapabilitiesDocument> for PrintSchemaDocument {
230 fn from(value: PrintCapabilitiesDocument) -> Self {
231 PrintSchemaDocument::PrintCapabilities(value)
232 }
233}
234
235pub trait WithScoredProperties {
237 fn scored_properties(&self) -> &[ScoredProperty];
239
240 fn get_scored_property(&self, name: &str, namespace: Option<&str>) -> Option<&ScoredProperty> {
242 self.scored_properties().iter().find(|x| {
243 x.name.as_ref().map_or(false, |x| {
244 x.local_name == name && x.namespace_ref() == namespace
245 })
246 })
247 }
248}
249
250impl WithScoredProperties for PrintFeatureOption {
251 fn scored_properties(&self) -> &[ScoredProperty] {
252 &self.scored_properties
253 }
254}
255
256impl WithScoredProperties for ScoredProperty {
257 fn scored_properties(&self) -> &[ScoredProperty] {
258 &self.scored_properties
259 }
260}
261
262pub trait WithProperties {
264 fn properties(&self) -> &[Property];
266
267 fn get_property(&self, name: &str, namespace: Option<&str>) -> Option<&Property> {
269 self.properties()
270 .iter()
271 .find(|x| x.name.local_name == name && x.name.namespace_ref() == namespace)
272 }
273}
274
275impl WithProperties for PrintSchemaDocument {
276 fn properties(&self) -> &[Property] {
277 match self {
278 PrintSchemaDocument::PrintCapabilities(x) => x.properties(),
279 PrintSchemaDocument::PrintTicket(x) => x.properties(),
280 }
281 }
282}
283
284impl WithProperties for PrintCapabilitiesDocument {
285 fn properties(&self) -> &[Property] {
286 &self.properties
287 }
288}
289
290impl WithProperties for PrintTicketDocument {
291 fn properties(&self) -> &[Property] {
292 &self.properties
293 }
294}
295
296impl WithProperties for ParameterDef {
297 fn properties(&self) -> &[Property] {
298 &self.properties
299 }
300}
301
302impl WithProperties for PrintFeature {
303 fn properties(&self) -> &[Property] {
304 &self.properties
305 }
306}
307
308impl WithProperties for PrintFeatureOption {
309 fn properties(&self) -> &[Property] {
310 &self.properties
311 }
312}
313
314impl WithProperties for ScoredProperty {
315 fn properties(&self) -> &[Property] {
316 &self.properties
317 }
318}
319
320impl WithProperties for Property {
321 fn properties(&self) -> &[Property] {
322 &self.properties
323 }
324}
325
326#[cfg(test)]
327mod tests {
328 use super::{
329 PrintCapabilitiesDocument, PrintSchemaDocument, PrintTicketDocument, Property,
330 PropertyValue, WithProperties,
331 };
332 use xml::name::OwnedName;
333
334 fn new_test_properties() -> Vec<Property> {
335 vec![
336 Property {
337 name: OwnedName::local("Property1"),
338 value: Some(PropertyValue::String("Value1".to_string())),
339 properties: vec![],
340 },
341 Property {
342 name: OwnedName::qualified("Property2", "http://test.namespace/", Some("test")),
343 value: Some(PropertyValue::Integer(2)),
344 properties: vec![],
345 },
346 ]
347 }
348
349 fn check_test_properties(w: &impl WithProperties) {
350 assert_eq!(w.properties().len(), 2);
351
352 assert_eq!(
354 w.get_property("Property1", None)
355 .and_then(|p| p.value.as_ref())
356 .and_then(|v| v.string()),
357 Some("Value1")
358 );
359 assert_eq!(
360 w.get_property("Property2", Some("http://test.namespace/"))
361 .and_then(|p| p.value.as_ref())
362 .and_then(|v| v.integer()),
363 Some(2)
364 );
365
366 assert!(w
368 .get_property("Property1", Some("http://wrong.namespace/"))
369 .is_none());
370 assert!(w
371 .get_property("Property2", Some("http://wrong.namespace/"))
372 .is_none());
373 assert!(w.get_property("Property2", None).is_none());
374
375 assert!(w.get_property("PROPERTY_NOT_EXIST", None).is_none());
377 }
378
379 #[test]
380 fn get_properties_from_ticket() {
381 let document1: PrintSchemaDocument = PrintTicketDocument {
382 properties: new_test_properties(),
383 parameter_inits: vec![],
384 features: vec![],
385 }
386 .into();
387 check_test_properties(&document1);
388 }
389
390 #[test]
391 fn get_properties_from_capabilities() {
392 let document1: PrintSchemaDocument = PrintCapabilitiesDocument {
393 properties: new_test_properties(),
394 parameter_defs: vec![],
395 features: vec![],
396 }
397 .into();
398 check_test_properties(&document1);
399 }
400
401 #[test]
402 fn get_properties_from_parameter_def() {
403 let parameter_def = super::ParameterDef {
404 name: OwnedName::local("Test"),
405 properties: new_test_properties(),
406 };
407 check_test_properties(¶meter_def);
408 }
409
410 #[test]
411 fn get_properties_from_option() {
412 let option = super::PrintFeatureOption {
413 name: None,
414 scored_properties: vec![],
415 properties: new_test_properties(),
416 };
417 check_test_properties(&option);
418 }
419
420 #[test]
421 fn get_properties_from_feature() {
422 let feature = super::PrintFeature {
423 name: OwnedName::local("Test"),
424 properties: new_test_properties(),
425 options: vec![],
426 features: vec![],
427 };
428 check_test_properties(&feature);
429 }
430
431 #[test]
432 fn get_properties_from_scored_property() {
433 let scored_property = super::ScoredProperty {
434 name: None,
435 parameter_ref: None,
436 value: None,
437 scored_properties: vec![],
438 properties: new_test_properties(),
439 };
440 check_test_properties(&scored_property);
441 }
442
443 #[test]
444 fn get_properties_from_property() {
445 let property = Property {
446 name: OwnedName::local("Test"),
447 value: None,
448 properties: new_test_properties(),
449 };
450 check_test_properties(&property);
451 }
452}