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