Serial-ATA / lofty-rs

Audio metadata library
Apache License 2.0
176 stars 34 forks source link

ID3v2: Turn `Frame` into an enum #390

Closed Serial-ATA closed 2 months ago

Serial-ATA commented 2 months ago

This is a major change to Frame that merges the header contents into the frame type itself (ex. TextInformationFrame now holds its FrameId and FrameFlags). Previously, Frame was defined as:

struct Frame {
    id: FrameId<'a>,
    value: FrameValue,
    flags: FrameFlags,
}

Meaning that a comment would be stored as:

Frame {
    id: FrameId::Valid(Cow::Borrowed("COMM")),
    value: FrameValue::Comment(CommentFrame { .. }),
    flags: FrameFlags::default()
}

This design required us to then check both the value and id. So, if we wanted to find all comments we would have to do:

match frame {
    Frame { id, value: FrameValue::Comment(..), ..} if id.as_str() == "COMM"
}

With Frame now being an enum, each frame type is responsible for its ID and flags, meaning we can hide away the ID for frames that are well known:

// No longer need to specify the ID of "COMM" anywhere
let frame = Frame::Comment(CommentFrame::new(
    TextEncoding::UTF8,
    *b"XXX",
    String::new(),
    String::from("Foo comment")
));

And, we can easily find all comments without having to check IDs anymore:

// We know that all `CommentFrame`s are a "COMM" frame
match frame {
    Frame::Comment(comment_frame) => {},
}

For frames that need an ID specified, like TextInformationFrame, it is just specified in its constructor:

let frame = Frame::Text(TextInformationFrame::new(
    FrameId::Valid(Cow::Borrowed("TALB")),
    TextEncoding::UTF8,
    String::from("Foo album")
));