use crate::{
profile::{RawProfile, TagSetter},
tag::TagSignature,
};
pub trait TagDataKind {
type Data: Default;
fn as_ref(td: &crate::tag::tagdata::TagData) -> Option<&Self::Data>;
fn as_mut(td: &mut crate::tag::tagdata::TagData) -> Option<&mut Self::Data>;
fn wrap(data: Self::Data) -> crate::tag::tagdata::TagData;
}
macro_rules! tag_kind {
($kind:ident, $variant:ident, $data:path) => {
#[derive(Debug, Clone, Copy, Default)]
pub struct $kind;
impl TagDataKind for $kind {
type Data = $data;
fn as_ref(td: &crate::tag::tagdata::TagData) -> Option<&Self::Data> {
if let crate::tag::tagdata::TagData::$variant(c) = td {
Some(c)
} else {
None
}
}
fn as_mut(td: &mut crate::tag::tagdata::TagData) -> Option<&mut Self::Data> {
if let crate::tag::tagdata::TagData::$variant(c) = td {
Some(c)
} else {
None
}
}
fn wrap(data: Self::Data) -> crate::tag::tagdata::TagData {
crate::tag::tagdata::TagData::$variant(data)
}
}
};
}
tag_kind!(CurveKind, Curve, crate::tag::tagdata::CurveData);
tag_kind!(
ParametricCurveKind,
ParametricCurve,
crate::tag::tagdata::ParametricCurveData
);
tag_kind!(SignatureKind, Signature, crate::tag::tagdata::SignatureData);
tag_kind!(XYZArrayKind, XYZArray, crate::tag::tagdata::XYZArrayData);
tag_kind!(
TextDescriptionKind,
TextDescription,
crate::tag::tagdata::TextDescriptionData
);
tag_kind!(TextKind, Text, crate::tag::tagdata::TextData);
tag_kind!(
IsS15Fixed16ArrayKind,
S15Fixed16Array,
crate::tag::tagdata::S15Fixed16ArrayData
);
tag_kind!(RawKind, Raw, crate::tag::tagdata::RawData);
tag_kind!(DictKind, Dict, crate::tag::tagdata::DictData);
tag_kind!(
MultiLocalizedUnicodeKind,
MultiLocalizedUnicode,
crate::tag::tagdata::MultiLocalizedUnicodeData
);
tag_kind!(
MakeAndModelKind,
MakeAndModel,
crate::tag::tagdata::MakeAndModelData
);
macro_rules! tag_accessors {
($lower:ident, $lower_mut:ident, $ensure_mut:ident, $variant:ident, $data:path, $kind:ident) => {
pub fn $lower<S: Into<TagSignature>>(&self, tag: S) -> Option<&$data> {
self.tag_data(tag).and_then(|td| {
if let crate::tag::tagdata::TagData::$variant(c) = td {
Some(c)
} else {
None
}
})
}
pub fn $lower_mut<S: Into<TagSignature>>(&mut self, tag: S) -> Option<&mut $data> {
self.tag_data_mut(tag).and_then(|td| {
if let crate::tag::tagdata::TagData::$variant(c) = td {
Some(c)
} else {
None
}
})
}
pub fn $ensure_mut<S: Into<TagSignature> + Copy>(&mut self, tag: S) -> &mut $data {
self.ensure_tag_mut::<$kind, _>(tag)
}
};
}
impl RawProfile {
pub fn with_tag<S>(self, tag: S) -> TagSetter<RawProfile, S>
where
S: Into<TagSignature> + Copy,
{
TagSetter::new(self, tag)
}
pub fn tag_data<S: Into<TagSignature>>(&self, tag: S) -> Option<&crate::tag::tagdata::TagData> {
let sig = tag.into();
self.tags.get(&sig).map(|rec| rec.tag.data())
}
pub fn tag_data_mut<S: Into<TagSignature>>(
&mut self,
tag: S,
) -> Option<&mut crate::tag::tagdata::TagData> {
let sig = tag.into();
self.tags.get_mut(&sig).map(|rec| rec.tag.data_mut())
}
pub fn ensure_tag_mut<K, S>(&mut self, tag: S) -> &mut K::Data
where
K: TagDataKind,
S: Into<TagSignature> + Copy,
{
let sig = tag.into();
let rec = match self.tags.entry(sig) {
indexmap::map::Entry::Occupied(o) => o.into_mut(),
indexmap::map::Entry::Vacant(v) => {
let tag = crate::tag::Tag::new(sig.to_u32(), K::wrap(Default::default()));
v.insert(crate::profile::ProfileTagRecord::new(0, 0, tag))
}
};
if K::as_ref(rec.tag.data()).is_none() {
rec.tag = crate::tag::Tag::new(sig.to_u32(), K::wrap(Default::default()));
}
K::as_mut(rec.tag.data_mut()).expect("ensured kind must be present")
}
tag_accessors!(
curve,
curve_mut,
ensure_curve_mut,
Curve,
crate::tag::tagdata::CurveData,
CurveKind
);
tag_accessors!(
parametric_curve,
parametric_curve_mut,
ensure_parametric_curve_mut,
ParametricCurve,
crate::tag::tagdata::ParametricCurveData,
ParametricCurveKind
);
tag_accessors!(
signature,
signature_mut,
ensure_signature_mut,
Signature,
crate::tag::tagdata::SignatureData,
SignatureKind
);
tag_accessors!(
xyz_array,
xyz_array_mut,
ensure_xyz_array_mut,
XYZArray,
crate::tag::tagdata::XYZArrayData,
XYZArrayKind
);
tag_accessors!(
text_description,
text_description_mut,
ensure_text_description_mut,
TextDescription,
crate::tag::tagdata::TextDescriptionData,
TextDescriptionKind
);
tag_accessors!(
text,
text_mut,
ensure_text_mut,
Text,
crate::tag::tagdata::TextData,
TextKind
);
tag_accessors!(
s15_fixed_16_array,
s15_fixed_16_array_mut,
ensure_s15_fixed_16_array_mut,
S15Fixed16Array,
crate::tag::tagdata::S15Fixed16ArrayData,
IsS15Fixed16ArrayKind
);
tag_accessors!(
raw,
raw_mut,
ensure_raw_mut,
Raw,
crate::tag::tagdata::RawData,
RawKind
);
tag_accessors!(
multi_localized_unicode,
multi_localized_unicode_mut,
ensure_multi_localized_unicode_mut,
MultiLocalizedUnicode,
crate::tag::tagdata::MultiLocalizedUnicodeData,
MultiLocalizedUnicodeKind
);
tag_accessors!(
dict,
dict_mut,
ensure_dict_mut,
Dict,
crate::tag::tagdata::DictData,
DictKind
);
tag_accessors!(
make_and_model,
make_and_model_mut,
ensure_make_and_model_mut,
MakeAndModel,
crate::tag::tagdata::MakeAndModelData,
MakeAndModelKind
);
}