ebml_iterable_specification/lib.rs
1//! This crate provides a core ebml specification that is used by the ebml-iterable crate.
2//!
3//! The related ebml-iterable-specification-derive crate can be used to simplify implementation of this spec.
4//!
5
6///
7/// Contains an empty specification for use with examples or very basic testing.
8///
9pub mod empty_spec;
10
11///
12/// Different data types defined in the EBML specification.
13///
14/// # Notes
15///
16/// This library made a concious decision to not work with "Date" elements from EBML due to lack of built-in support for dates in Rust. Specification implementations should treat Date elements as Binary so that consumers have the option of parsing the unaltered data using their library of choice, if needed.
17///
18
19// Possible future feature flag to enable Date functionality by having `chrono` as an optional dependency?
20#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
21pub enum TagDataType {
22 Master,
23 UnsignedInt,
24 Integer,
25 Utf8,
26 Binary,
27 Float,
28}
29
30#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
31pub enum PathPart {
32 Id(u64),
33 Global((Option<u64>,Option<u64>)),
34}
35
36///
37/// This trait, along with [`EbmlTag`], should be implemented to define a specification so that EBML can be parsed correctly. Typically implemented on an Enum of tag variants.
38///
39/// Any specification using EBML can take advantage of this library to parse or write binary data. As stated in the docs, [`TagWriter`](https://docs.rs/ebml-iterable/latest/ebml_iterable/struct.TagWriter.html) needs nothing special if you stick with the `write_raw` method, but [`TagIterator`](https://docs.rs/ebml-iterable/latest/ebml_iterable/struct.TagIterator.html) requires a struct implementing this trait. Custom specification implementations can refer to [webm-iterable](https://crates.io/crates/webm_iterable) as an example.
40///
41/// This trait and [`EbmlTag`] are typically implemented simultaneously. They are separate traits as they have primarily different uses - [`EbmlSpecification`] should be brought into scope when dealing with the specification as a whole, whereas [`EbmlTag`] should be brought into scope when dealing with specific tags.
42///
43
44pub trait EbmlSpecification<T: EbmlSpecification<T> + EbmlTag<T> + Clone> {
45 ///
46 /// Pulls the data type for a tag from the spec, based on the tag id.
47 ///
48 /// This function *must* return [`None`] if the input id is not in the specification. Implementors can reference [webm-iterable](https://crates.io/crates/webm_iterable) for an example.
49 ///
50 fn get_tag_data_type(id: u64) -> Option<TagDataType>;
51
52 ///
53 /// Gets the id of a specific tag variant.
54 ///
55 /// Default implementation uses the [`EbmlTag`] implementation. Implementors can reference [webm-iterable](https://crates.io/crates/webm_iterable) for an example.
56 ///
57 fn get_tag_id(item: &T) -> u64 {
58 item.get_id()
59 }
60
61 ///
62 /// Gets the schema path of a specific tag.
63 ///
64 /// This function is used to find the schema defined path of a tag. If the tag is a root element, this function should return an empty array.
65 ///
66 fn get_path_by_id(id: u64) -> &'static [PathPart];
67
68 ///
69 /// Gets the schema path of a specific tag variant.
70 ///
71 /// Default implementation uses [`Self::get_path_by_id`] after obtaining the tag id using the [`EbmlTag`] implementation.
72 ///
73 fn get_path_by_tag(item: &T) -> &'static [PathPart] {
74 Self::get_path_by_id(item.get_id())
75 }
76
77 ///
78 /// Creates an unsigned integer type tag from the spec.
79 ///
80 /// This function *must* return `None` if the input id is not in the specification or if the input id data type is not [`TagDataType::UnsignedInt`]. Implementors can reference [webm-iterable](https://crates.io/crates/webm_iterable) for an example.
81 ///
82 fn get_unsigned_int_tag(id: u64, data: u64) -> Option<T>;
83
84 ///
85 /// Creates a signed integer type tag from the spec.
86 ///
87 /// This function *must* return `None` if the input id is not in the specification or if the input id data type is not [`TagDataType::Integer`]. Implementors can reference [webm-iterable](https://crates.io/crates/webm_iterable) for an example.
88 ///
89 fn get_signed_int_tag(id: u64, data: i64) -> Option<T>;
90
91 ///
92 /// Creates a utf8 type tag from the spec.
93 ///
94 /// This function *must* return `None` if the input id is not in the specification or if the input id data type is not [`TagDataType::Utf8`]. Implementors can reference [webm-iterable](https://crates.io/crates/webm_iterable) for an example.
95 ///
96 fn get_utf8_tag(id: u64, data: String) -> Option<T>;
97
98 ///
99 /// Creates a binary type tag from the spec.
100 ///
101 /// This function *must* return `None` if the input id is not in the specification or if the input id data type is not [`TagDataType::Binary`]. Implementors can reference [webm-iterable](https://crates.io/crates/webm_iterable) for an example.
102 ///
103 fn get_binary_tag(id: u64, data: &[u8]) -> Option<T>;
104
105 ///
106 /// Creates a float type tag from the spec.
107 ///
108 /// This function *must* return `None` if the input id is not in the specification or if the input id data type is not [`TagDataType::Float`]. Implementors can reference [webm-iterable](https://crates.io/crates/webm_iterable) for an example.
109 ///
110 fn get_float_tag(id: u64, data: f64) -> Option<T>;
111
112 ///
113 /// Creates a master type tag from the spec.
114 ///
115 /// This function *must* return `None` if the input id is not in the specification or if the input id data type is not [`TagDataType::Master`]. Implementors can reference [webm-iterable](https://crates.io/crates/webm_iterable) for an example.
116 ///
117 fn get_master_tag(id: u64, data: Master<T>) -> Option<T>;
118
119 ///
120 /// Creates a tag that does not conform to the spec.
121 ///
122 /// This function should return a "RawTag" variant that contains the tag id and tag data. Tag data should only be retrievable as binary data. Implementors can reference [webm-iterable](https://crates.io/crates/webm_iterable) for an example.
123 ///
124 fn get_raw_tag(id: u64, data: &[u8]) -> T;
125
126}
127
128///
129/// This trait, along with [`EbmlSpecification`], should be implemented to define a specification so that EBML can be parsed correctly. Typically implemented on an Enum of tag variants.
130///
131/// Any specification using EBML can take advantage of this library to parse or write binary data. As stated in the docs, [`TagWriter`](https://docs.rs/ebml-iterable/latest/ebml_iterable/struct.TagWriter.html) needs nothing special if you stick with the `write_raw` method, but [`TagIterator`](https://docs.rs/ebml-iterable/latest/ebml_iterable/struct.TagIterator.html) requires a struct implementing this trait. Custom specification implementations can refer to [webm-iterable](https://crates.io/crates/webm_iterable) as an example.
132///
133/// This trait and [`EbmlSpecification`] are typically implemented simultaneously. They are separate traits as they have primarily different uses - [`EbmlSpecification`] should be brought into scope when dealing with the specification as a whole, whereas [`EbmlTag`] should be brought into scope when dealing with specific tags.
134///
135
136pub trait EbmlTag<T: Clone> {
137 ///
138 /// Gets the id of `self`.
139 ///
140 /// Implementors can reference [webm-iterable](https://crates.io/crates/webm_iterable) for an example.
141 ///
142 fn get_id(&self) -> u64;
143
144 ///
145 /// Gets a reference to the data contained in `self` as an unsigned integer.
146 ///
147 /// This function *must* return `None` if the associated data type of `self` is not [`TagDataType::UnsignedInt`]. Implementors can reference [webm-iterable](https://crates.io/crates/webm_iterable) for an example.
148 ///
149 fn as_unsigned_int(&self) -> Option<&u64>;
150
151 ///
152 /// Gets a reference to the data contained in `self` as an integer.
153 ///
154 /// This function *must* return `None` if the associated data type of `self` is not [`TagDataType::Integer`]. Implementors can reference [webm-iterable](https://crates.io/crates/webm_iterable) for an example.
155 ///
156 fn as_signed_int(&self) -> Option<&i64>;
157
158 ///
159 /// Gets a reference to the data contained in `self` as string slice.
160 ///
161 /// This function *must* return `None` if the associated data type of `self` is not [`TagDataType::Utf8`]. Implementors can reference [webm-iterable](https://crates.io/crates/webm_iterable) for an example.
162 ///
163 fn as_utf8(&self) -> Option<&str>;
164
165 ///
166 /// Gets a reference to the data contained in `self` as binary data.
167 ///
168 /// This function *must* return `None` if the associated data type of `self` is not [`TagDataType::Binary`]. Implementors can reference [webm-iterable](https://crates.io/crates/webm_iterable) for an example.
169 ///
170 fn as_binary(&self) -> Option<&[u8]>;
171
172 ///
173 /// Gets a reference to the data contained in `self` as float data.
174 ///
175 /// This function *must* return `None` if the associated data type of `self` is not [`TagDataType::Float`]. Implementors can reference [webm-iterable](https://crates.io/crates/webm_iterable) for an example.
176 ///
177 fn as_float(&self) -> Option<&f64>;
178
179 ///
180 /// Gets a reference to master data contained in `self`.
181 ///
182 /// This function *must* return `None` if the associated data type of `self` is not [`TagDataType::Master`]. Implementors can reference [webm-iterable](https://crates.io/crates/webm_iterable) for an example.
183 ///
184 fn as_master(&self) -> Option<&Master<T>>;
185}
186
187///
188/// An enum that defines different possible states of a [`TagDataType::Master`] tag.
189///
190/// A "master" tag is a type of tag that contains other tags within it. Because these tags are dynamically sized, the [`TagIterator`](https://docs.rs/ebml-iterable/latest/ebml_iterable/struct.TagIterator.html) emits these tags as [`Master::Start`] and [`Master::End`] variants by default so that the entire tag does not need to be buffered into memory all at once. The [`Master::Full`] variant is a complete "master" tag that includes all child tags within it.
191///
192#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
193pub enum Master<T: Clone> {
194
195 ///
196 /// Designates the start of a tag.
197 ///
198 Start,
199
200 ///
201 /// Designates the end of a tag.
202 ///
203 End,
204
205 ///
206 /// Designates a full tag. `Vec<T>` contains all child tags contained in this master tag.
207 ///
208 Full(Vec<T>),
209}
210
211impl<T: Clone> Master<T> {
212
213 ///
214 /// Convenience method to pull children from a master tag.
215 ///
216 /// # Panics
217 ///
218 /// Panics if `self` is not a `Full` variant.
219 ///
220 /// # Examples
221 ///
222 /// ```
223 /// # use ebml_iterable_specification::empty_spec::EmptySpec;
224 /// use ebml_iterable_specification::Master;
225 ///
226 /// let children = vec![EmptySpec::with_data(0x1253, &[1]), EmptySpec::with_data(0x1234, &[2])];
227 /// // Clone children because creating a Master consumes it
228 /// let tag = Master::Full(children.clone());
229 /// let retrieved_children = tag.get_children();
230 /// assert_eq!(retrieved_children, children);
231 /// ```
232 ///
233 pub fn get_children(self) -> Vec<T> {
234 match self {
235 Master::Full(data) => data,
236 Master::Start => panic!("`get_children` called on Master::Start variant"),
237 Master::End => panic!("`get_children` called on Master::End variant"),
238 }
239 }
240}