Change the type of Context from enum to struct.
This commit is contained in:
parent
b584930a78
commit
f81d2f6e6a
|
@ -54,6 +54,9 @@
|
||||||
//! images, which were distinguished by `bool` previously. Function
|
//! images, which were distinguished by `bool` previously. Function
|
||||||
//! parameters and struct members now take `In`s instead of `bool`s.
|
//! parameters and struct members now take `In`s instead of `bool`s.
|
||||||
//! `Field::thumbnail` was renamed to `Field::ifd_num` accordingly.
|
//! `Field::thumbnail` was renamed to `Field::ifd_num` accordingly.
|
||||||
|
//! * The type of `Context` was changed from enum to struct. The variants
|
||||||
|
//! (e.g., `Context::Tiff`) were changed to associated constants and
|
||||||
|
//! they are now spelled in all uppercase (e.g., `Context::TIFF`).
|
||||||
|
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
pub use jpeg::get_exif_attr as get_exif_attr_from_jpeg;
|
pub use jpeg::get_exif_attr as get_exif_attr_from_jpeg;
|
||||||
|
|
93
src/tag.rs
93
src/tag.rs
|
@ -60,8 +60,8 @@ impl Tag {
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// use exif::{Context, Tag};
|
/// use exif::{Context, Tag};
|
||||||
/// assert_eq!(Tag::DateTime.context(), Context::Tiff);
|
/// assert_eq!(Tag::DateTime.context(), Context::TIFF);
|
||||||
/// assert_eq!(Tag::ExposureTime.context(), Context::Exif);
|
/// assert_eq!(Tag::ExposureTime.context(), Context::EXIF);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn context(self) -> Context {
|
pub fn context(self) -> Context {
|
||||||
|
@ -102,22 +102,75 @@ impl fmt::Display for Tag {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match get_tag_info(*self) {
|
match get_tag_info(*self) {
|
||||||
Some(ti) => f.pad(ti.name),
|
Some(ti) => f.pad(ti.name),
|
||||||
None => f.pad(&format!("{:?}", self)),
|
None => f.pad(&format!("Tag({}, {})", self.0, self.1)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An enum that indicates how a tag number is interpreted.
|
/// A type that indicates how a tag number is interpreted.
|
||||||
|
// This type is not an enum to keep API compatibilities when
|
||||||
|
// new contexts are introduced.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Context {
|
pub struct Context(std::num::NonZeroU16);
|
||||||
|
|
||||||
|
macro_rules! generate_context {
|
||||||
|
(
|
||||||
|
$(
|
||||||
|
// Copy the doc attribute to the actual definition.
|
||||||
|
$( #[$attr:meta] )*
|
||||||
|
$name: ident = $num: expr, $disp: expr;
|
||||||
|
)+
|
||||||
|
) => (
|
||||||
|
impl Context {
|
||||||
|
$(
|
||||||
|
$( #[$attr] )*
|
||||||
|
pub const $name: Self = Self(
|
||||||
|
unsafe { std::num::NonZeroU16::new_unchecked($num) });
|
||||||
|
)+
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_context(ctx: &Context, f: &mut fmt::Formatter)
|
||||||
|
-> fmt::Result {
|
||||||
|
let name = match ctx.0.get() {
|
||||||
|
$( $num => $disp, )+
|
||||||
|
_ => return fmt::Debug::fmt(ctx, f),
|
||||||
|
};
|
||||||
|
f.write_str(name)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_context! {
|
||||||
/// TIFF attributes defined in the TIFF Rev. 6.0 specification.
|
/// TIFF attributes defined in the TIFF Rev. 6.0 specification.
|
||||||
Tiff, // 0th/1st IFD
|
TIFF = 1, "TIFF"; // 0th/1st IFD (toplevel)
|
||||||
/// Exif attributes.
|
/// Exif attributes.
|
||||||
Exif, // 0th/1st IFD -- Exif IFD
|
EXIF = 2, "Exif"; // -- Exif IFD
|
||||||
/// GPS attributes.
|
/// GPS attributes.
|
||||||
Gps, // 0th/1st IFD -- GPS IFD
|
GPS = 3, "GPS"; // -- GPS IFD
|
||||||
/// Interoperability attributes.
|
/// Interoperability attributes.
|
||||||
Interop, // 0th/1st IFD -- Exif IFD -- Interoperability IFD
|
INTEROP = 4, "Interop"; // -- Exif IFD -- Interoperability IFD
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Context {
|
||||||
|
// Compatibility with 0.3.x.
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
#[deprecated(since = "0.4.0", note = "use Context::TIFF instead")]
|
||||||
|
pub const Tiff: Self = Self::TIFF;
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
#[deprecated(since = "0.4.0", note = "use Context::EXIF instead")]
|
||||||
|
pub const Exif: Self = Self::EXIF;
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
#[deprecated(since = "0.4.0", note = "use Context::GPS instead")]
|
||||||
|
pub const Gps: Self = Self::GPS;
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
#[deprecated(since = "0.4.0", note = "use Context::INTEROP instead")]
|
||||||
|
pub const Interop: Self = Self::INTEROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Context {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
display_context(self, f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -215,7 +268,7 @@ macro_rules! generate_well_known_tag_constants {
|
||||||
// the Exif field names: camel cases and all-capital acronyms.
|
// the Exif field names: camel cases and all-capital acronyms.
|
||||||
generate_well_known_tag_constants!(
|
generate_well_known_tag_constants!(
|
||||||
// Exif-specific IFDs [EXIF23 4.6.3].
|
// Exif-specific IFDs [EXIF23 4.6.3].
|
||||||
|Context::Tiff|
|
|Context::TIFF|
|
||||||
|
|
||||||
/// A pointer to the Exif IFD. This is used for the internal structure
|
/// A pointer to the Exif IFD. This is used for the internal structure
|
||||||
/// of Exif data and will not be returned to the user.
|
/// of Exif data and will not be returned to the user.
|
||||||
|
@ -228,7 +281,7 @@ generate_well_known_tag_constants!(
|
||||||
unit![],
|
unit![],
|
||||||
"GPS Info IFD pointer"),
|
"GPS Info IFD pointer"),
|
||||||
|
|
||||||
|Context::Exif|
|
|Context::EXIF|
|
||||||
|
|
||||||
/// A pointer to the interoperability IFD. This is used for the internal
|
/// A pointer to the interoperability IFD. This is used for the internal
|
||||||
/// structure of Exif data and will not be returned to the user.
|
/// structure of Exif data and will not be returned to the user.
|
||||||
|
@ -238,7 +291,7 @@ generate_well_known_tag_constants!(
|
||||||
|
|
||||||
// TIFF primary and thumbnail attributes [EXIF23 4.6.4 Table 4,
|
// TIFF primary and thumbnail attributes [EXIF23 4.6.4 Table 4,
|
||||||
// 4.6.8 Table 17, and 4.6.8 Table 21].
|
// 4.6.8 Table 17, and 4.6.8 Table 21].
|
||||||
|Context::Tiff|
|
|Context::TIFF|
|
||||||
|
|
||||||
(ImageWidth, 0x100, DefaultValue::None, d_default,
|
(ImageWidth, 0x100, DefaultValue::None, d_default,
|
||||||
unit!["pixels"],
|
unit!["pixels"],
|
||||||
|
@ -340,7 +393,7 @@ generate_well_known_tag_constants!(
|
||||||
"Copyright holder"),
|
"Copyright holder"),
|
||||||
|
|
||||||
// Exif IFD attributes [EXIF23 4.6.5 Table 7 and 4.6.8 Table 18].
|
// Exif IFD attributes [EXIF23 4.6.5 Table 7 and 4.6.8 Table 18].
|
||||||
|Context::Exif|
|
|Context::EXIF|
|
||||||
|
|
||||||
(ExposureTime, 0x829a, DefaultValue::None, d_exptime,
|
(ExposureTime, 0x829a, DefaultValue::None, d_exptime,
|
||||||
unit!["s"],
|
unit!["s"],
|
||||||
|
@ -582,7 +635,7 @@ generate_well_known_tag_constants!(
|
||||||
"Gamma"),
|
"Gamma"),
|
||||||
|
|
||||||
// GPS attributes [EXIF23 4.6.6 Table 15 and 4.6.8 Table 19].
|
// GPS attributes [EXIF23 4.6.6 Table 15 and 4.6.8 Table 19].
|
||||||
|Context::Gps|
|
|Context::GPS|
|
||||||
|
|
||||||
// Depends on the Exif version.
|
// Depends on the Exif version.
|
||||||
(GPSVersionID, 0x0, DefaultValue::ContextDependent, d_gpsver,
|
(GPSVersionID, 0x0, DefaultValue::ContextDependent, d_gpsver,
|
||||||
|
@ -683,7 +736,7 @@ generate_well_known_tag_constants!(
|
||||||
"Horizontal positioning error"),
|
"Horizontal positioning error"),
|
||||||
|
|
||||||
// Interoperability attributes [EXIF23 4.6.7 Table 16 and 4.6.8 Table 20].
|
// Interoperability attributes [EXIF23 4.6.7 Table 16 and 4.6.8 Table 20].
|
||||||
|Context::Interop|
|
|Context::INTEROP|
|
||||||
|
|
||||||
(InteroperabilityIndex, 0x1, DefaultValue::None, d_default,
|
(InteroperabilityIndex, 0x1, DefaultValue::None, d_default,
|
||||||
unit![],
|
unit![],
|
||||||
|
@ -1456,12 +1509,12 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn tag_constant_in_pattern() {
|
fn tag_constant_in_pattern() {
|
||||||
// Destructuring, which will always work.
|
// Destructuring, which will always work.
|
||||||
match Tag(Context::Tiff, 0x132) {
|
match Tag(Context::TIFF, 0x132) {
|
||||||
Tag(Context::Tiff, 0x132) => {},
|
Tag(Context::TIFF, 0x132) => {},
|
||||||
_ => panic!("failed to match Tag"),
|
_ => panic!("failed to match Tag"),
|
||||||
}
|
}
|
||||||
// Matching against a constant. Test if this compiles.
|
// Matching against a constant. Test if this compiles.
|
||||||
match Tag(Context::Tiff, 0x132) {
|
match Tag(Context::TIFF, 0x132) {
|
||||||
Tag::DateTime => {},
|
Tag::DateTime => {},
|
||||||
_ => panic!("failed to match Tag"),
|
_ => panic!("failed to match Tag"),
|
||||||
}
|
}
|
||||||
|
@ -1498,11 +1551,11 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tag_fmt_display() {
|
fn tag_fmt_display() {
|
||||||
let tag1 = Tag(Context::Tiff, 0x132);
|
let tag1 = Tag(Context::TIFF, 0x132);
|
||||||
assert_eq!(format!("{:15}", tag1), "DateTime ");
|
assert_eq!(format!("{:15}", tag1), "DateTime ");
|
||||||
assert_eq!(format!("{:>15}", tag1), " DateTime");
|
assert_eq!(format!("{:>15}", tag1), " DateTime");
|
||||||
assert_eq!(format!("{:5.6}", tag1), "DateTi");
|
assert_eq!(format!("{:5.6}", tag1), "DateTi");
|
||||||
let tag2 = Tag(Context::Exif, 0);
|
let tag2 = Tag(Context::EXIF, 0);
|
||||||
assert_eq!(format!("{:15}", tag2), "Tag(Exif, 0) ");
|
assert_eq!(format!("{:15}", tag2), "Tag(Exif, 0) ");
|
||||||
assert_eq!(format!("{:>15}", tag2), " Tag(Exif, 0)");
|
assert_eq!(format!("{:>15}", tag2), " Tag(Exif, 0)");
|
||||||
assert_eq!(format!("{:5.6}", tag2), "Tag(Ex");
|
assert_eq!(format!("{:5.6}", tag2), "Tag(Ex");
|
||||||
|
|
|
@ -122,7 +122,7 @@ fn parse_exif_sub<E>(data: &[u8])
|
||||||
return Err(Error::InvalidFormat("Limit the IFD count to 8"));
|
return Err(Error::InvalidFormat("Limit the IFD count to 8"));
|
||||||
}
|
}
|
||||||
ifd_offset = parse_ifd::<E>(
|
ifd_offset = parse_ifd::<E>(
|
||||||
&mut fields, data, ifd_offset, Context::Tiff, ifd_num)?;
|
&mut fields, data, ifd_offset, Context::TIFF, ifd_num)?;
|
||||||
ifd_num_ck = ifd_num.checked_add(1);
|
ifd_num_ck = ifd_num.checked_add(1);
|
||||||
}
|
}
|
||||||
Ok(fields)
|
Ok(fields)
|
||||||
|
@ -168,11 +168,11 @@ fn parse_ifd<'a, E>(fields: &mut Vec<Field<'a>>, data: &'a [u8],
|
||||||
let tag = Tag(ctx, tag);
|
let tag = Tag(ctx, tag);
|
||||||
match tag {
|
match tag {
|
||||||
Tag::ExifIFDPointer => parse_child_ifd::<E>(
|
Tag::ExifIFDPointer => parse_child_ifd::<E>(
|
||||||
fields, data, &val, Context::Exif, ifd_num)?,
|
fields, data, &val, Context::EXIF, ifd_num)?,
|
||||||
Tag::GPSInfoIFDPointer => parse_child_ifd::<E>(
|
Tag::GPSInfoIFDPointer => parse_child_ifd::<E>(
|
||||||
fields, data, &val, Context::Gps, ifd_num)?,
|
fields, data, &val, Context::GPS, ifd_num)?,
|
||||||
Tag::InteropIFDPointer => parse_child_ifd::<E>(
|
Tag::InteropIFDPointer => parse_child_ifd::<E>(
|
||||||
fields, data, &val, Context::Interop, ifd_num)?,
|
fields, data, &val, Context::INTEROP, ifd_num)?,
|
||||||
_ => fields.push(Field {
|
_ => fields.push(Field {
|
||||||
tag: tag, ifd_num: In(ifd_num), value: val }),
|
tag: tag, ifd_num: In(ifd_num), value: val }),
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,10 +130,11 @@ impl<'a> Writer<'a> {
|
||||||
Field { tag: Tag(ctx, _), ifd_num, .. } => {
|
Field { tag: Tag(ctx, _), ifd_num, .. } => {
|
||||||
let ifd = self.pick_ifd(ifd_num);
|
let ifd = self.pick_ifd(ifd_num);
|
||||||
match ctx {
|
match ctx {
|
||||||
Context::Tiff => ifd.tiff_fields.push(field),
|
Context::TIFF => ifd.tiff_fields.push(field),
|
||||||
Context::Exif => ifd.exif_fields.push(field),
|
Context::EXIF => ifd.exif_fields.push(field),
|
||||||
Context::Gps => ifd.gps_fields.push(field),
|
Context::GPS => ifd.gps_fields.push(field),
|
||||||
Context::Interop => ifd.interop_fields.push(field),
|
Context::INTEROP => ifd.interop_fields.push(field),
|
||||||
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue