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
|
||||
//! parameters and struct members now take `In`s instead of `bool`s.
|
||||
//! `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 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
|
||||
/// ```
|
||||
/// use exif::{Context, Tag};
|
||||
/// assert_eq!(Tag::DateTime.context(), Context::Tiff);
|
||||
/// assert_eq!(Tag::ExposureTime.context(), Context::Exif);
|
||||
/// assert_eq!(Tag::DateTime.context(), Context::TIFF);
|
||||
/// assert_eq!(Tag::ExposureTime.context(), Context::EXIF);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn context(self) -> Context {
|
||||
|
@ -102,22 +102,75 @@ impl fmt::Display for Tag {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match get_tag_info(*self) {
|
||||
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)]
|
||||
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, // 0th/1st IFD
|
||||
TIFF = 1, "TIFF"; // 0th/1st IFD (toplevel)
|
||||
/// Exif attributes.
|
||||
Exif, // 0th/1st IFD -- Exif IFD
|
||||
EXIF = 2, "Exif"; // -- Exif IFD
|
||||
/// GPS attributes.
|
||||
Gps, // 0th/1st IFD -- GPS IFD
|
||||
GPS = 3, "GPS"; // -- GPS IFD
|
||||
/// 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)]
|
||||
|
@ -215,7 +268,7 @@ macro_rules! generate_well_known_tag_constants {
|
|||
// the Exif field names: camel cases and all-capital acronyms.
|
||||
generate_well_known_tag_constants!(
|
||||
// Exif-specific IFDs [EXIF23 4.6.3].
|
||||
|Context::Tiff|
|
||||
|Context::TIFF|
|
||||
|
||||
/// A pointer to the Exif IFD. This is used for the internal structure
|
||||
/// of Exif data and will not be returned to the user.
|
||||
|
@ -228,7 +281,7 @@ generate_well_known_tag_constants!(
|
|||
unit![],
|
||||
"GPS Info IFD pointer"),
|
||||
|
||||
|Context::Exif|
|
||||
|Context::EXIF|
|
||||
|
||||
/// A pointer to the interoperability IFD. This is used for the internal
|
||||
/// 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,
|
||||
// 4.6.8 Table 17, and 4.6.8 Table 21].
|
||||
|Context::Tiff|
|
||||
|Context::TIFF|
|
||||
|
||||
(ImageWidth, 0x100, DefaultValue::None, d_default,
|
||||
unit!["pixels"],
|
||||
|
@ -340,7 +393,7 @@ generate_well_known_tag_constants!(
|
|||
"Copyright holder"),
|
||||
|
||||
// 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,
|
||||
unit!["s"],
|
||||
|
@ -582,7 +635,7 @@ generate_well_known_tag_constants!(
|
|||
"Gamma"),
|
||||
|
||||
// GPS attributes [EXIF23 4.6.6 Table 15 and 4.6.8 Table 19].
|
||||
|Context::Gps|
|
||||
|Context::GPS|
|
||||
|
||||
// Depends on the Exif version.
|
||||
(GPSVersionID, 0x0, DefaultValue::ContextDependent, d_gpsver,
|
||||
|
@ -683,7 +736,7 @@ generate_well_known_tag_constants!(
|
|||
"Horizontal positioning error"),
|
||||
|
||||
// Interoperability attributes [EXIF23 4.6.7 Table 16 and 4.6.8 Table 20].
|
||||
|Context::Interop|
|
||||
|Context::INTEROP|
|
||||
|
||||
(InteroperabilityIndex, 0x1, DefaultValue::None, d_default,
|
||||
unit![],
|
||||
|
@ -1456,12 +1509,12 @@ mod tests {
|
|||
#[test]
|
||||
fn tag_constant_in_pattern() {
|
||||
// Destructuring, which will always work.
|
||||
match Tag(Context::Tiff, 0x132) {
|
||||
Tag(Context::Tiff, 0x132) => {},
|
||||
match Tag(Context::TIFF, 0x132) {
|
||||
Tag(Context::TIFF, 0x132) => {},
|
||||
_ => panic!("failed to match Tag"),
|
||||
}
|
||||
// Matching against a constant. Test if this compiles.
|
||||
match Tag(Context::Tiff, 0x132) {
|
||||
match Tag(Context::TIFF, 0x132) {
|
||||
Tag::DateTime => {},
|
||||
_ => panic!("failed to match Tag"),
|
||||
}
|
||||
|
@ -1498,11 +1551,11 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
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!("{: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!("{: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"));
|
||||
}
|
||||
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);
|
||||
}
|
||||
Ok(fields)
|
||||
|
@ -168,11 +168,11 @@ fn parse_ifd<'a, E>(fields: &mut Vec<Field<'a>>, data: &'a [u8],
|
|||
let tag = Tag(ctx, tag);
|
||||
match tag {
|
||||
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>(
|
||||
fields, data, &val, Context::Gps, ifd_num)?,
|
||||
fields, data, &val, Context::GPS, ifd_num)?,
|
||||
Tag::InteropIFDPointer => parse_child_ifd::<E>(
|
||||
fields, data, &val, Context::Interop, ifd_num)?,
|
||||
fields, data, &val, Context::INTEROP, ifd_num)?,
|
||||
_ => fields.push(Field {
|
||||
tag: tag, ifd_num: In(ifd_num), value: val }),
|
||||
}
|
||||
|
|
|
@ -130,10 +130,11 @@ impl<'a> Writer<'a> {
|
|||
Field { tag: Tag(ctx, _), ifd_num, .. } => {
|
||||
let ifd = self.pick_ifd(ifd_num);
|
||||
match ctx {
|
||||
Context::Tiff => ifd.tiff_fields.push(field),
|
||||
Context::Exif => ifd.exif_fields.push(field),
|
||||
Context::Gps => ifd.gps_fields.push(field),
|
||||
Context::Interop => ifd.interop_fields.push(field),
|
||||
Context::TIFF => ifd.tiff_fields.push(field),
|
||||
Context::EXIF => ifd.exif_fields.push(field),
|
||||
Context::GPS => ifd.gps_fields.push(field),
|
||||
Context::INTEROP => ifd.interop_fields.push(field),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue