Cleanup; Make use of doc_cfg

This commit is contained in:
Serial 2022-02-04 00:59:20 -05:00
parent 4e3cf7a882
commit d13f01d215
No known key found for this signature in database
GPG key ID: DA95198DC17C4568
22 changed files with 273 additions and 230 deletions

View file

@ -54,4 +54,5 @@ name = "create_tag"
harness = false
[package.metadata.docs.rs]
all-features = true
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

58
src/ape/header.rs Normal file
View file

@ -0,0 +1,58 @@
use crate::error::{FileDecodingError, Result};
use crate::types::file::FileType;
use std::io::{Read, Seek, SeekFrom};
use std::ops::Neg;
use byteorder::{LittleEndian, ReadBytesExt};
#[derive(Copy, Clone)]
pub(crate) struct ApeHeader {
pub(crate) size: u32,
#[cfg(feature = "ape")]
pub(crate) item_count: u32,
}
pub(crate) fn read_ape_header<R>(data: &mut R, footer: bool) -> Result<ApeHeader>
where
R: Read + Seek,
{
let version = data.read_u32::<LittleEndian>()?;
let mut size = data.read_u32::<LittleEndian>()?;
if size < 32 {
// If the size is < 32, something went wrong during encoding
// The size includes the footer and all items
return Err(
FileDecodingError::new(FileType::APE, "APE tag has an invalid size (< 32)").into(),
);
}
#[cfg(feature = "ape")]
let item_count = data.read_u32::<LittleEndian>()?;
#[cfg(not(feature = "ape"))]
data.seek(SeekFrom::Current(4))?;
if footer {
// No point in reading the rest of the footer, just seek back to the end of the header
data.seek(SeekFrom::Current(i64::from(size - 12).neg()))?;
} else {
// There are 12 bytes remaining in the header
// Flags (4)
// Reserved (8)
data.seek(SeekFrom::Current(12))?;
}
// Version 1 doesn't include a header
if version == 2000 {
size += 32
}
Ok(ApeHeader {
size,
#[cfg(feature = "ape")]
item_count,
})
}

View file

@ -6,30 +6,36 @@
//! this tag will be read, but **cannot** be written. The only tags allowed by spec are `APEv1/2` and
//! `ID3v1`.
pub(crate) mod constants;
pub(crate) mod header;
mod properties;
mod read;
pub(crate) mod tag;
pub(crate) mod write;
pub use crate::ape::properties::ApeProperties;
#[cfg(feature = "ape")]
pub use {
crate::types::picture::APE_PICTURE_TYPES,
tag::{ape_tag::ApeTag, item::ApeItem},
};
use crate::error::Result;
#[cfg(feature = "id3v1")]
use crate::id3::v1::tag::Id3v1Tag;
#[cfg(feature = "id3v2")]
use crate::id3::v2::tag::Id3v2Tag;
use crate::tag_utils::tag_methods;
use crate::types::file::{AudioFile, FileType, TaggedFile};
use crate::types::properties::FileProperties;
use crate::types::tag::{Tag, TagType};
use std::io::{Read, Seek};
// Exports
crate::macros::feature_locked! {
#![cfg(feature = "ape")]
pub(crate) mod tag;
pub use tag::ape_tag::ApeTag;
pub use tag::item::ApeItem;
pub use crate::types::picture::APE_PICTURE_TYPES;
}
pub use properties::ApeProperties;
/// An APE file
pub struct ApeFile {
#[cfg(feature = "id3v1")]
@ -106,12 +112,14 @@ impl AudioFile for ApeFile {
}
impl ApeFile {
tag_methods! {
#[cfg(feature = "id3v2")];
crate::macros::tag_methods! {
#[cfg(feature = "id3v2")]
id3v2_tag, Id3v2Tag;
#[cfg(feature = "id3v1")];
#[cfg(feature = "id3v1")]
id3v1_tag, Id3v1Tag;
#[cfg(feature = "ape")];
#[cfg(feature = "ape")]
ape_tag, ApeTag
}
}

View file

@ -1,8 +1,8 @@
use super::constants::APE_PREAMBLE;
use super::header::read_ape_header;
#[cfg(feature = "ape")]
use super::tag::{ape_tag::ApeTag, read::read_ape_tag};
use super::{ApeFile, ApeProperties};
use crate::ape::tag::read_ape_header;
use crate::error::{FileDecodingError, Result};
#[cfg(feature = "id3v1")]
use crate::id3::v1::tag::Id3v1Tag;

View file

@ -278,8 +278,8 @@ impl<'a> Into<ApeTagRef<'a>> for &'a ApeTag {
mod tests {
use crate::ape::{ApeItem, ApeTag};
use crate::{ItemValue, Tag, TagIO, TagType};
use crate::ape::header::read_ape_header;
use crate::ape::tag::read_ape_header;
use std::io::Cursor;
#[test]

View file

@ -1,67 +1,4 @@
#[cfg(feature = "ape")]
pub(crate) mod ape_tag;
#[cfg(feature = "ape")]
pub(crate) mod item;
#[cfg(feature = "ape")]
pub(crate) mod read;
#[cfg(feature = "ape")]
mod write;
use crate::error::{FileDecodingError, Result};
use crate::types::file::FileType;
use std::io::{Read, Seek, SeekFrom};
use std::ops::Neg;
use byteorder::{LittleEndian, ReadBytesExt};
#[derive(Copy, Clone)]
pub(crate) struct ApeHeader {
pub(crate) size: u32,
#[cfg(feature = "ape")]
pub(crate) item_count: u32,
}
pub(crate) fn read_ape_header<R>(data: &mut R, footer: bool) -> Result<ApeHeader>
where
R: Read + Seek,
{
let version = data.read_u32::<LittleEndian>()?;
let mut size = data.read_u32::<LittleEndian>()?;
if size < 32 {
// If the size is < 32, something went wrong during encoding
// The size includes the footer and all items
return Err(
FileDecodingError::new(FileType::APE, "APE tag has an invalid size (< 32)").into(),
);
}
#[cfg(feature = "ape")]
let item_count = data.read_u32::<LittleEndian>()?;
#[cfg(not(feature = "ape"))]
data.seek(SeekFrom::Current(4))?;
if footer {
// No point in reading the rest of the footer, just seek back to the end of the header
data.seek(SeekFrom::Current(i64::from(size - 12).neg()))?;
} else {
// There are 12 bytes remaining in the header
// Flags (4)
// Reserved (8)
data.seek(SeekFrom::Current(12))?;
}
// Version 1 doesn't include a header
if version == 2000 {
size += 32
}
Ok(ApeHeader {
size,
#[cfg(feature = "ape")]
item_count,
})
}
mod write;

View file

@ -1,6 +1,6 @@
use super::ape_tag::ApeTag;
use super::item::ApeItem;
use super::ApeHeader;
use crate::ape::header::ApeHeader;
use crate::ape::constants::INVALID_KEYS;
use crate::error::{FileDecodingError, Result};
use crate::types::file::FileType;

View file

@ -6,11 +6,11 @@ use crate::id3::{find_id3v1, find_id3v2, find_lyrics3v2};
use crate::probe::Probe;
use crate::types::file::FileType;
use crate::types::item::ItemValueRef;
use crate::ape::header::read_ape_header;
use std::fs::File;
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
use crate::ape::tag::read_ape_header;
use byteorder::{LittleEndian, WriteBytesExt};
#[allow(clippy::shadow_unrelated)]

View file

@ -15,12 +15,15 @@
//! A track number of 0 will be treated as an empty field.
//! Additionally, there is no track total field.
pub(crate) mod constants;
#[cfg(feature = "id3v1")]
pub(crate) mod read;
#[cfg(feature = "id3v1")]
pub(crate) mod tag;
#[cfg(feature = "id3v1")]
pub(crate) mod write;
#[cfg(feature = "id3v1")]
pub use crate::id3::v1::{constants::GENRES, tag::Id3v1Tag};
crate::macros::feature_locked! {
#![cfg(feature = "id3v1")]
pub use constants::GENRES;
pub(crate) mod tag;
pub use tag::Id3v1Tag;
pub(crate) mod read;
pub(crate) mod write;
}

View file

@ -8,51 +8,52 @@
//! * [Frame]
mod flags;
#[cfg(feature = "id3v2")]
mod frame;
#[cfg(feature = "id3v2")]
mod items;
#[cfg(feature = "id3v2")]
pub(crate) mod read;
#[cfg(feature = "id3v2_restrictions")]
mod restrictions;
#[cfg(feature = "id3v2")]
pub(crate) mod tag;
pub(crate) mod util;
#[cfg(feature = "id3v2")]
pub(crate) mod write;
#[cfg(feature = "id3v2_restrictions")]
pub use restrictions::{
ImageSizeRestrictions, TagRestrictions, TagSizeRestrictions, TextSizeRestrictions,
};
#[cfg(feature = "id3v2")]
pub use {
flags::Id3v2TagFlags,
frame::{
content::EncodedTextFrame, content::LanguageFrame, id::FrameID, Frame, FrameFlags,
FrameValue,
},
items::{
encapsulated_object::{GEOBInformation, GeneralEncapsulatedObject},
sync_text::{SyncTextContentType, SyncTextInformation, SynchronizedText, TimestampFormat},
},
tag::Id3v2Tag,
util::{
text_utils::TextEncoding,
upgrade::{upgrade_v2, upgrade_v3},
},
};
#[cfg(not(feature = "id3v2"))]
use flags::Id3v2TagFlags;
use crate::error::{ErrorKind, Id3v2Error, Id3v2ErrorKind, LoftyError, Result};
use crate::macros::feature_locked;
use std::io::Read;
use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
feature_locked! {
#![cfg(feature = "id3v2")]
pub use flags::Id3v2TagFlags;
pub use util::text_utils::TextEncoding;
pub use util::upgrade::{upgrade_v2, upgrade_v3};
pub(crate) mod tag;
pub use tag::Id3v2Tag;
mod items;
pub use items::encapsulated_object::{GEOBInformation, GeneralEncapsulatedObject};
pub use items::sync_text::{SyncTextContentType, SyncTextInformation, SynchronizedText, TimestampFormat};
mod frame;
pub use frame::content::{EncodedTextFrame, LanguageFrame};
pub use frame::id::FrameID;
pub use frame::Frame;
pub use frame::FrameFlags;
pub use frame::FrameValue;
pub(crate) mod read;
pub(crate) mod write;
}
feature_locked! {
#![cfg(feature = "id3v2_restrictions")]
mod restrictions;
pub use restrictions::{
ImageSizeRestrictions, TagRestrictions, TagSizeRestrictions, TextSizeRestrictions,
};
}
#[cfg(not(feature = "id3v2"))]
use flags::Id3v2TagFlags;
#[derive(PartialEq, Debug, Clone, Copy)]
/// The ID3v2 version
pub enum Id3v2Version {

View file

@ -1,21 +1,23 @@
mod properties;
mod read;
#[cfg(feature = "aiff_text_chunks")]
pub(crate) mod tag;
pub(crate) mod write;
use crate::error::Result;
#[cfg(feature = "id3v2")]
use crate::id3::v2::tag::Id3v2Tag;
use crate::tag_utils::tag_methods;
use crate::types::file::{AudioFile, FileType, TaggedFile};
use crate::types::properties::FileProperties;
use crate::types::tag::{Tag, TagType};
#[cfg(feature = "aiff_text_chunks")]
use tag::AiffTextChunks;
use std::io::{Read, Seek};
crate::macros::feature_locked! {
#![cfg(feature = "aiff_text_chunks")]
pub(crate) mod tag;
use tag::AiffTextChunks;
}
/// An AIFF file
pub struct AiffFile {
#[cfg(feature = "aiff_text_chunks")]
@ -83,10 +85,11 @@ impl AudioFile for AiffFile {
}
impl AiffFile {
tag_methods! {
#[cfg(feature = "id3v2")];
crate::macros::tag_methods! {
#[cfg(feature = "id3v2")]
id3v2_tag, Id3v2Tag;
#[cfg(feature = "aiff_text_chunks")];
#[cfg(feature = "aiff_text_chunks")]
text_chunks, AiffTextChunks
}
}

View file

@ -3,10 +3,22 @@ pub(crate) mod aiff;
pub(crate) mod chunk;
pub(crate) mod wav;
use crate::macros::feature_locked;
// Exports
pub use aiff::AiffFile;
pub use wav::{WavFile, WavFormat, WavProperties};
#[cfg(feature = "aiff_text_chunks")]
pub use aiff::tag::{AiffTextChunks, Comment};
#[cfg(feature = "riff_info_list")]
pub use wav::tag::RiffInfoList;
feature_locked! {
#![cfg(feature = "aiff_text_chunks")]
pub use aiff::tag::AiffTextChunks;
pub use aiff::tag::Comment;
}
feature_locked! {
#![cfg(feature = "riff_info_list")]
pub use wav::tag::RiffInfoList;
}

View file

@ -1,23 +1,26 @@
mod properties;
mod read;
#[cfg(feature = "riff_info_list")]
pub(crate) mod tag;
pub(crate) mod write;
pub use crate::iff::wav::properties::{WavFormat, WavProperties};
use crate::error::Result;
#[cfg(feature = "id3v2")]
use crate::id3::v2::tag::Id3v2Tag;
use crate::tag_utils::tag_methods;
use crate::types::file::{AudioFile, FileType, TaggedFile};
use crate::types::properties::FileProperties;
use crate::types::tag::{Tag, TagType};
#[cfg(feature = "riff_info_list")]
use tag::RiffInfoList;
use std::io::{Read, Seek};
crate::macros::feature_locked! {
#![cfg(feature = "riff_info_list")]
pub(crate) mod tag;
use tag::RiffInfoList;
}
// Exports
pub use crate::iff::wav::properties::{WavFormat, WavProperties};
/// A WAV file
pub struct WavFile {
#[cfg(feature = "riff_info_list")]
@ -86,10 +89,11 @@ impl AudioFile for WavFile {
}
impl WavFile {
tag_methods! {
#[cfg(feature = "id3v2")];
crate::macros::tag_methods! {
#[cfg(feature = "id3v2")]
id3v2_tag, Id3v2Tag;
#[cfg(feature = "riff_info_list")];
#[cfg(feature = "riff_info_list")]
riff_info, RiffInfoList
}
}

View file

@ -151,11 +151,13 @@
clippy::tabs_in_doc_comments,
clippy::len_without_is_empty
)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
pub mod ape;
pub mod error;
pub mod id3;
pub mod iff;
pub(crate) mod macros;
pub mod mp3;
pub mod mp4;
pub mod ogg;

45
src/macros.rs Normal file
View file

@ -0,0 +1,45 @@
macro_rules! tag_methods {
(
$(
$(#[cfg($meta:meta)])?
$name:ident,
$ty:ty
);*
) => {
paste::paste! {
$(
$(#[cfg($meta)])?
#[doc = "Gets the [`" $ty "`] if it exists"]
pub fn $name(&self) -> Option<&$ty> {
self.$name.as_ref()
}
$(#[cfg($meta)])?
#[doc = "Gets a mutable reference to the [`" $ty "`] if it exists"]
pub fn [<$name _mut>](&mut self) -> Option<&mut $ty> {
self.$name.as_mut()
}
$(#[cfg($meta)])?
#[doc = "Removes the [`" $ty "`]"]
pub fn [<remove_ $name>](&mut self) {
self.$name = None
}
)*
}
}
}
macro_rules! feature_locked {
(
#![cfg($meta:meta)]
$($item:item)+
) => {
$(
#[cfg($meta)]
$item
)+
}
}
pub(crate) use {feature_locked, tag_methods};

View file

@ -15,7 +15,6 @@ use crate::error::Result;
use crate::id3::v1::tag::Id3v1Tag;
#[cfg(feature = "id3v2")]
use crate::id3::v2::tag::Id3v2Tag;
use crate::tag_utils::tag_methods;
use crate::types::file::{AudioFile, FileType, TaggedFile};
use crate::types::properties::FileProperties;
use crate::types::tag::{Tag, TagType};
@ -100,12 +99,14 @@ impl AudioFile for Mp3File {
}
impl Mp3File {
tag_methods! {
#[cfg(feature = "id3v2")];
crate::macros::tag_methods! {
#[cfg(feature = "id3v2")]
id3v2_tag, Id3v2Tag;
#[cfg(feature = "id3v1")];
#[cfg(feature = "id3v1")]
id3v1_tag, Id3v1Tag;
#[cfg(feature = "ape")];
#[cfg(feature = "ape")]
ape_tag, ApeTag
}
}

View file

@ -1,9 +1,9 @@
use super::header::{search_for_frame_sync, Header, XingHeader};
use super::{Mp3File, Mp3Properties};
use crate::ape::constants::APE_PREAMBLE;
use crate::ape::header::read_ape_header;
#[cfg(feature = "ape")]
use crate::ape::tag::read::read_ape_tag;
use crate::ape::tag::read_ape_header;
use crate::error::{FileDecodingError, Result};
#[cfg(feature = "id3v2")]
use crate::id3::v2::read::parse_id3v2;

View file

@ -4,29 +4,31 @@
//!
//! The only supported tag format is [`Ilst`].
mod atom_info;
#[cfg(feature = "mp4_ilst")]
pub(crate) mod ilst;
mod moov;
mod properties;
mod read;
mod trak;
pub use crate::mp4::properties::{Mp4Codec, Mp4Properties};
#[cfg(feature = "mp4_ilst")]
pub use crate::mp4::{
atom_info::AtomIdent,
ilst::{
atom::{Atom, AtomData},
Ilst,
},
};
use crate::tag_utils::tag_methods;
use crate::error::Result;
use crate::types::file::{AudioFile, FileType, TaggedFile};
use crate::{FileProperties, Result, TagType};
use crate::types::properties::FileProperties;
use crate::types::tag::TagType;
use std::io::{Read, Seek};
// Exports
crate::macros::feature_locked! {
#![cfg(feature = "mp4_ilst")]
pub(crate) mod ilst;
pub use atom_info::AtomIdent;
pub use ilst::atom::{Atom, AtomData};
pub use ilst::Ilst;
}
pub use crate::mp4::properties::{Mp4Codec, Mp4Properties};
/// An MP4 file
pub struct Mp4File {
/// The file format from ftyp's "major brand" (Ex. "M4A ")
@ -97,8 +99,8 @@ impl Mp4File {
}
impl Mp4File {
tag_methods! {
#[cfg(feature = "mp4_ilst")];
crate::macros::tag_methods! {
#[cfg(feature = "mp4_ilst")]
ilst, Ilst
}
}

View file

@ -7,7 +7,6 @@ pub(crate) mod write;
#[cfg(feature = "vorbis_comments")]
use super::tag::VorbisComments;
use crate::error::Result;
use crate::tag_utils::tag_methods;
use crate::types::file::{AudioFile, FileType, TaggedFile};
use crate::types::properties::FileProperties;
use crate::types::tag::TagType;
@ -73,8 +72,8 @@ impl AudioFile for FlacFile {
}
impl FlacFile {
tag_methods! {
#[cfg(feature = "vorbis_comments")];
crate::macros::tag_methods! {
#[cfg(feature = "vorbis_comments")]
vorbis_comments, VorbisComments
}
}

View file

@ -8,32 +8,33 @@ pub(crate) mod flac;
pub(crate) mod opus;
pub(crate) mod read;
pub(crate) mod speex;
#[cfg(feature = "vorbis_comments")]
pub(crate) mod tag;
pub(crate) mod vorbis;
#[cfg(feature = "vorbis_comments")]
pub(crate) mod write;
use crate::error::{FileDecodingError, Result};
use crate::types::file::FileType;
// Exports
#[cfg(feature = "vorbis_comments")]
pub use crate::ogg::tag::VorbisComments;
pub use crate::ogg::flac::FlacFile;
pub use crate::ogg::opus::properties::OpusProperties;
pub use crate::ogg::opus::OpusFile;
pub use crate::ogg::speex::properties::SpeexProperties;
pub use crate::ogg::speex::SpeexFile;
pub use crate::ogg::vorbis::properties::VorbisProperties;
pub use crate::ogg::vorbis::VorbisFile;
use std::io::{Read, Seek};
use ogg_pager::Page;
// Exports
crate::macros::feature_locked! {
#![cfg(feature = "vorbis_comments")]
pub(crate) mod write;
pub(crate) mod tag;
pub use tag::VorbisComments;
}
pub use flac::FlacFile;
pub use opus::properties::OpusProperties;
pub use opus::OpusFile;
pub use speex::properties::SpeexProperties;
pub use speex::SpeexFile;
pub use vorbis::properties::VorbisProperties;
pub use vorbis::VorbisFile;
pub(self) fn verify_signature(page: &Page, sig: &[u8]) -> Result<()> {
let sig_len = sig.len();

View file

@ -75,40 +75,6 @@ pub(crate) fn dump_tag<W: Write>(tag: &Tag, writer: &mut W) -> Result<()> {
}
}
macro_rules! tag_methods {
(
$(
$(#[$attr:meta])?;
$name:ident,
$ty:ty
);*
) => {
paste::paste! {
$(
$(#[$attr])?
#[doc = "Gets the [`" $ty "`] if it exists"]
pub fn $name(&self) -> Option<&$ty> {
self.$name.as_ref()
}
$(#[$attr])?
#[doc = "Gets a mutable reference to the [`" $ty "`] if it exists"]
pub fn [<$name _mut>](&mut self) -> Option<&mut $ty> {
self.$name.as_mut()
}
$(#[$attr])?
#[doc = "Removes the [`" $ty "`]"]
pub fn [<remove_ $name>](&mut self) {
self.$name = None
}
)*
}
}
}
pub(crate) use tag_methods;
#[cfg(test)]
// Used for tag conversion tests
pub(crate) mod test_utils {

View file

@ -110,7 +110,7 @@ impl MimeType {
}
}
/// The picture type
/// The picture type, according to ID3v2 APIC
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum PictureType {
@ -141,8 +141,8 @@ pub enum PictureType {
impl PictureType {
// ID3/OGG specific methods
/// Get a u8 from a `PictureType` according to ID3v2 APIC
#[cfg(any(feature = "id3v2", feature = "vorbis_comments"))]
/// Get a u8 from a `PictureType` according to ID3v2 APIC
pub fn as_u8(&self) -> u8 {
match self {
Self::Other => 0,
@ -170,8 +170,8 @@ impl PictureType {
}
}
/// Get a `PictureType` from a u8 according to ID3v2 APIC
#[cfg(any(feature = "id3v2", feature = "vorbis_comments"))]
/// Get a `PictureType` from a u8 according to ID3v2 APIC
pub fn from_u8(bytes: u8) -> Self {
match bytes {
0 => Self::Other,
@ -201,8 +201,8 @@ impl PictureType {
// APE specific methods
/// Get an APE item key from a `PictureType`
#[cfg(feature = "ape")]
/// Get an APE item key from a `PictureType`
pub fn as_ape_key(&self) -> Option<&str> {
match self {
Self::Other => Some("Cover Art (Other)"),
@ -230,8 +230,8 @@ impl PictureType {
}
}
/// Get a `PictureType` from an APE item key
#[cfg(feature = "ape")]
/// Get a `PictureType` from an APE item key
pub fn from_ape_key(key: &str) -> Self {
match key {
"Cover Art (Other)" => Self::Other,