votable/
definitions.rs

1//! Struct dedicated to the `DEFINITIONS` tag.
2use std::{
3  io::{BufRead, Write},
4  str,
5};
6
7use paste::paste;
8use quick_xml::{events::Event, Reader, Writer};
9
10use super::{
11  coosys::CooSys,
12  error::VOTableError,
13  param::Param,
14  utils::{discard_comment, discard_event, unexpected_attr_warn},
15  HasSubElements, HasSubElems, QuickXmlReadWrite, TableDataContent, VOTableElement, VOTableVisitor,
16};
17
18#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
19#[serde(tag = "def_type")]
20pub enum DefinitionsElem {
21  CooSys(Box<CooSys>),
22  Param(Box<Param>),
23}
24
25impl DefinitionsElem {
26  fn write<W: Write>(&mut self, writer: &mut Writer<W>) -> Result<(), VOTableError> {
27    match self {
28      DefinitionsElem::CooSys(elem) => elem.write(writer, &()),
29      DefinitionsElem::Param(elem) => elem.write(writer, &()),
30    }
31  }
32  pub fn visit<C, V>(&mut self, visitor: &mut V) -> Result<(), V::E>
33  where
34    C: TableDataContent,
35    V: VOTableVisitor<C>,
36  {
37    match self {
38      DefinitionsElem::CooSys(e) => e.visit(visitor),
39      DefinitionsElem::Param(e) => e.visit(visitor),
40    }
41  }
42}
43
44/// Struct corresponding to the `DEFINITION` XML tag.
45/// Deprecated since VOTable 1.1, see
46/// [IVOA doc](https://www.ivoa.net/documents/VOTable/20040811/REC-VOTable-1.1-20040811.html#ToC19)
47#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
48pub struct Definitions {
49  // no attributes
50  // sub-elems
51  #[serde(default, skip_serializing_if = "Vec::is_empty")]
52  pub elems: Vec<DefinitionsElem>,
53}
54
55impl Default for Definitions {
56  fn default() -> Self {
57    Definitions::new()
58  }
59}
60
61impl Definitions {
62  pub fn new() -> Self {
63    Self {
64      elems: Default::default(),
65    }
66  }
67
68  impl_builder_push_boxed_elem!(Param, DefinitionsElem);
69  impl_builder_push_boxed_elem!(CooSys, DefinitionsElem);
70
71  pub fn visit<C, V>(&mut self, visitor: &mut V) -> Result<(), V::E>
72  where
73    C: TableDataContent,
74    V: VOTableVisitor<C>,
75  {
76    visitor.visit_definitions_start(self)?;
77    for e in &mut self.elems {
78      e.visit(visitor)?;
79    }
80    visitor.visit_definitions_ended(self)
81  }
82}
83
84impl VOTableElement for Definitions {
85  const TAG: &'static str = "DEFINITIONS";
86
87  type MarkerType = HasSubElems;
88
89  fn from_attrs<K, V, I>(attrs: I) -> Result<Self, VOTableError>
90  where
91    K: AsRef<str> + Into<String>,
92    V: AsRef<str> + Into<String>,
93    I: Iterator<Item = (K, V)>,
94  {
95    Self::new().set_attrs(attrs)
96  }
97
98  fn set_attrs_by_ref<K, V, I>(&mut self, attrs: I) -> Result<(), VOTableError>
99  where
100    K: AsRef<str> + Into<String>,
101    V: AsRef<str> + Into<String>,
102    I: Iterator<Item = (K, V)>,
103  {
104    for (k, _) in attrs {
105      unexpected_attr_warn(k.as_ref(), Self::TAG);
106    }
107    Ok(())
108  }
109
110  fn for_each_attribute<F>(&self, _f: F)
111  where
112    F: FnMut(&str, &str),
113  {
114  }
115}
116
117impl HasSubElements for Definitions {
118  type Context = ();
119
120  fn has_no_sub_elements(&self) -> bool {
121    self.elems.is_empty()
122  }
123
124  fn read_sub_elements_by_ref<R: BufRead>(
125    &mut self,
126    mut reader: &mut Reader<R>,
127    mut reader_buff: &mut Vec<u8>,
128    _context: &Self::Context,
129  ) -> Result<(), VOTableError> {
130    loop {
131      let mut event = reader.read_event(reader_buff).map_err(VOTableError::Read)?;
132      match &mut event {
133        Event::Start(e) => match e.local_name() {
134          CooSys::TAG_BYTES => push_from_event_start!(self, CooSys, reader, reader_buff, e),
135          Param::TAG_BYTES => push_from_event_start!(self, Param, reader, reader_buff, e),
136          _ => {
137            return Err(VOTableError::UnexpectedStartTag(
138              e.local_name().to_vec(),
139              Self::TAG,
140            ))
141          }
142        },
143        Event::Empty(e) => match e.local_name() {
144          CooSys::TAG_BYTES => push_from_event_empty!(self, CooSys, e),
145          Param::TAG_BYTES => push_from_event_empty!(self, Param, e),
146          _ => {
147            return Err(VOTableError::UnexpectedEmptyTag(
148              e.local_name().to_vec(),
149              Self::TAG,
150            ))
151          }
152        },
153        Event::End(e) if e.local_name() == Self::TAG_BYTES => return Ok(()),
154        Event::Eof => return Err(VOTableError::PrematureEOF(Self::TAG)),
155        Event::Comment(e) => discard_comment(e, reader, Self::TAG),
156        _ => discard_event(event, Self::TAG),
157      }
158    }
159  }
160
161  fn write_sub_elements_by_ref<W: Write>(
162    &mut self,
163    writer: &mut Writer<W>,
164    _context: &Self::Context,
165  ) -> Result<(), VOTableError> {
166    write_elem_vec_no_context!(self, elems, writer);
167    Ok(())
168  }
169}