API design for media file tagging library

I'm building a music file metadata tagging library (dealing with things like Vorbis and ID3 tags). Most of the parsers and writers are finished, and I can deal with each format individually. For individual formats, their specific constraints more or less dictate the APIs for interacting with them.

However, one of the goals I want this library to achieve is to offer a degree of abstraction over file formats, and I'm unsure as to the best way to design an API for this.

The first obvious choice would be a simple enum-based API, where individual tags are represented by variants of an enum with a getter and setter method on the to-be-tagged file. The downside of this approach is that it is very static, forcing the values of all tags to be represented by the same type and forcing a single fixed set of tag definitions, disallowing the user from supplying their own or using a different set of tag mappings (which is often necessary, as there are few standards).

My current approach currently looks like this:

// Implemented on individual tags like `struct Artist;`
trait Tag {
    type Value;

    fn get(self, src: &TaggedObject) -> Option<Value>;
    fn set(self, src: &mut TaggedObject, value: Self::Value);

impl TaggedObject {
    fn get<T: Tag>(&self, tag: T) -> Tag::Value {

The only downside of this approach that I can think of is that enumerating tags becomes more difficult (i.e. you can't directly have a Vec<Tag>), are there any other major downsides to this approach, or is there a better way I haven't thought of?

I think enums are the most natural type to represent tags. If you want to make it extensible how about just passing a specific enum as a generic type parameter? I think this should work well since you probably don't want to mix tags from different formats.

I do want to mix tags from different formats, if I understand you correctly. For example I have an Artist tag that maps to the ARTIST vorbis comment field in Vorbis files (FLAC, Ogg audio, etc.) and to the TPE1 frame in MP3 files.

In the meantime since publishing this post I did implement a basic version of the library using the above structure, and I am pretty happy with it for now.

Ah, nevermind my previous post, I misunderstood what kind of abstraction you were talking about.
What purpose does the Artist struct serve with your approach?

An alternative approach that comes to mind is having the file formats implement tags as traits e.g:

trait Artist {
    fn set_artist(&mut self, artist: String);
    fn get_artist(&self) -> String;

Something else that crosses my mind is that some metadata formats allow one file to have multiple tags of one type (e.g. EXIF), I don't know if that also applies to music metadata formats. If one music file format can only have one tag of a type and another can have multiple of the equivalent type that would probably make it more difficult for you to provide an appropriate abstraction.

I assume that tag values have a maximum size which probably also varies between formats. So I guess it might happen that setting one value succeeds for one format while it could fail for another? Also something you probably want to think about.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.