1use 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#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
48pub struct Definitions {
49 #[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}