Skip to content

Commit

Permalink
Replace 'HasArtist' trait with 'AsRef' impls and add 'From' impls for…
Browse files Browse the repository at this point in the history
… aspects
  • Loading branch information
fsktom committed Jul 25, 2023
1 parent f3a12b4 commit 9b2d550
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 18 deletions.
140 changes: 124 additions & 16 deletions src/aspect.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,35 @@
//! Module containing representations of songs, albums, artists and their traits
//!
//! If you want to make a function that accepts either a [`Song`], [`Album`] or [`Artist`] struct,
//! use the [`Music`] trait. It's got methods for comparing with a [`SongEntry`].
//! ```
//! use endsong::prelude::*;
//! fn foo<Asp: Music>(asp: &Asp, entry: &SongEntry) -> bool {
//! asp.is_entry(entry)
//! }
//!
//! ```
//!
//! If you want to make a function that extracts the artist from either of them, use the [`AsRef<Artist>`] trait.
//! ```
//! use endsong::prelude::*;
//! fn foo<Asp: AsRef<Artist>>(has_art: &Asp) {
//! let artist: &Artist = has_art.as_ref();
//! // do stuff with artist
//! }
//! ```
//!
//! If you want to make a function that extracts the album from [`Album`] or [`Song`], use the [`AsRef<Album>`] trait.
//! ```
//! use endsong::prelude::*;
//! fn foo<Asp: AsRef<Album>>(has_alb: &Asp) {
//! let album: &Album = has_alb.as_ref();
//! // do stuff with album
//! }
//! ```
//!
//! You can also freely create insances of e.g. [`Artist`] and [`Album`] from [`Song`] using its [`From`] impls.
//! See the specific struct [`From`] and [`AsRef`] impls for more info.
use std::cmp::Ordering;
use std::fmt::Display;
Expand All @@ -21,12 +52,6 @@ pub trait Music: Display + Clone + Eq + Ord {
/// Trait used to accept only [`Artist`] and [`Album`]
pub trait HasSongs: Music {}

/// Trait used to accept only [`Album`] and [`Song`]
pub trait HasArtist: Music {
/// Returns a reference to the corresponding [`Artist`]
fn artist(&self) -> &Artist;
}

/// Struct for representing an artist
#[derive(PartialEq, Eq, Hash, Debug, Clone, PartialOrd, Ord)]
pub struct Artist {
Expand All @@ -47,11 +72,49 @@ impl Display for Artist {
write!(f, "{}", self.name)
}
}
impl From<&Artist> for Artist {
/// Clones the artist
fn from(artist: &Artist) -> Self {
artist.clone()
}
}
impl From<Album> for Artist {
/// Consumes `alb` and returns its artist
fn from(alb: Album) -> Self {
alb.artist
}
}
impl From<&Album> for Artist {
/// Clones the artist of `alb`
fn from(alb: &Album) -> Self {
alb.artist.clone()
}
}
impl From<Song> for Artist {
/// Consumes `son` and returns its artist
fn from(son: Song) -> Self {
son.album.artist
}
}
impl From<&Song> for Artist {
/// Clones the artist of `son`
fn from(son: &Song) -> Self {
son.album.artist.clone()
}
}
impl From<&SongEntry> for Artist {
/// Creates an instance of Artist from a ref to [`SongEntry`]
///
/// Clones the artist name from `entry`
fn from(entry: &SongEntry) -> Self {
Artist::new(&entry.artist)
}
}
impl AsRef<Artist> for Artist {
fn as_ref(&self) -> &Artist {
self
}
}
impl Music for Artist {
fn is_entry(&self, entry: &SongEntry) -> bool {
entry.artist == self.name
Expand Down Expand Up @@ -105,11 +168,42 @@ impl Ord for Album {
}
}
}
impl From<&Album> for Album {
/// Clones the album
fn from(album: &Album) -> Self {
album.clone()
}
}
impl From<Song> for Album {
/// Consumes `son` and returns its album
fn from(son: Song) -> Self {
son.album
}
}
impl From<&Song> for Album {
/// Clones the album of `son`
fn from(son: &Song) -> Self {
son.album.clone()
}
}
impl From<&SongEntry> for Album {
/// Creates an instance of Album from a ref to [`SongEntry`]
///
/// Clones the album and artist name from `entry`
fn from(entry: &SongEntry) -> Self {
Album::new(&entry.album, &entry.artist)
}
}
impl AsRef<Album> for Album {
fn as_ref(&self) -> &Album {
self
}
}
impl AsRef<Artist> for Album {
fn as_ref(&self) -> &Artist {
&self.artist
}
}
impl Music for Album {
fn is_entry(&self, entry: &SongEntry) -> bool {
entry.artist == self.artist.name && entry.album == self.name
Expand All @@ -119,11 +213,6 @@ impl Music for Album {
}
}
impl HasSongs for Album {}
impl HasArtist for Album {
fn artist(&self) -> &Artist {
&self.artist
}
}

/// Struct for representing a song
// to allow for custom HashMap key
Expand Down Expand Up @@ -184,11 +273,35 @@ impl Ord for Song {
}
}
}
impl From<&Song> for Song {
/// Clones the song
fn from(song: &Song) -> Self {
song.clone()
}
}
impl From<&SongEntry> for Song {
/// Creates an instance of Song from a ref to [`SongEntry`]
///
/// Clones the song, album and artist name from `entry`
fn from(entry: &SongEntry) -> Self {
Song::new(&entry.track, &entry.album, &entry.artist)
}
}
impl AsRef<Song> for Song {
fn as_ref(&self) -> &Song {
self
}
}
impl AsRef<Artist> for Song {
fn as_ref(&self) -> &Artist {
&self.album.artist
}
}
impl AsRef<Album> for Song {
fn as_ref(&self) -> &Album {
&self.album
}
}
impl Music for Song {
fn is_entry(&self, entry: &SongEntry) -> bool {
entry.artist == self.album.artist.name
Expand All @@ -201,11 +314,6 @@ impl Music for Song {
&& entry.track.to_lowercase() == self.name
}
}
impl HasArtist for Song {
fn artist(&self) -> &Artist {
&self.album.artist
}
}

#[cfg(test)]
mod tests {
Expand Down
3 changes: 1 addition & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@ pub mod prelude {

pub use crate::entry::{SongEntries, SongEntry};

pub use crate::aspect::Music;
pub use crate::aspect::{Album, Artist, Song};
// traits for dealing with Album, Artist and Song
pub use crate::aspect::{HasArtist, HasSongs, Music};

pub use crate::LOCATION_TZ;

Expand Down

0 comments on commit 9b2d550

Please sign in to comment.