Remove lofty-attr

This commit is contained in:
Serial 2021-08-18 18:46:07 -04:00
parent 419f8457a3
commit b510179372
3 changed files with 1 additions and 335 deletions

View file

@ -1,7 +1,7 @@
[package]
name = "lofty"
version = "0.3.0"
authors = ["Serial <69764315+Serial-ATA@users.noreply.github.com>", "Tianyi <ShiTianyi2001@outlook.com>"]
authors = ["Serial <69764315+Serial-ATA@users.noreply.github.com>"]
edition = "2018"
license = "MIT OR Apache-2.0"
description = "Unified IO for different types of audio metadata"
@ -27,8 +27,6 @@ base64 = "0.13.0"
byteorder = "1.4.3"
cfg-if = "1.0.0"
lofty_attr = "0.1.9"
[features]
default = ["all_tags"]
format-mp4 = ["mp4ameta"]

View file

@ -1,18 +0,0 @@
[package]
name = "lofty_attr"
version = "0.1.9"
authors = ["Serial <69764315+Serial-ATA@users.noreply.github.com>"]
description = "Macros for Lofty tag struct creation"
license = "MIT OR Apache-2.0"
repository = "https://github.com/Serial-ATA/lofty-rs"
edition = "2018"
[dependencies]
quote = "1.0.9"
[dependencies.syn]
version = "1.0.74"
features = ["derive"]
[lib]
proc-macro = true

View file

@ -1,314 +0,0 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Error, Fields, Meta};
#[proc_macro_derive(LoftyTag, attributes(expected))]
#[allow(clippy::too_many_lines)]
pub fn impl_tag(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let data = match input.data {
Data::Struct(data) => data,
_ => {
return Error::new(name.span(), "LoftyTag is only applicable to structs")
.into_compile_error()
.into()
},
};
let fields = match data.fields {
Fields::Named(fields) => fields.named,
_ => {
return Error::new(name.span(), format!("`{}` has no named fields", name))
.into_compile_error()
.into()
},
};
let inner_ident = "inner".to_string();
let format_ident = "_format".to_string();
let mut inner_ty = None;
let mut tag_type = None;
for field in fields.iter() {
let ident = field.ident.as_ref().unwrap().to_string();
if ident == inner_ident {
inner_ty = Some(field.ty.clone())
}
if ident == format_ident {
let expected_attr = field
.attrs
.iter()
.find(|a| a.path.is_ident("expected"))
.expect(&*format!(
"`{}`'s `_format` field has no `expected` attribute",
name
));
if let Ok(Meta::List(list)) = expected_attr.parse_meta() {
tag_type = Some(list.nested)
}
}
}
let inner = inner_ty.expect(&*format!("`{}` has no `inner` field", name));
let tag_type = tag_type.expect(&*format!("`{}` has no `_format` field", name));
TokenStream::from(quote! {
impl #name {
/// Creates a new default tag
pub fn new() -> Self {
Self {
inner: #inner::default(),
properties: FileProperties::default(),
_format: #tag_type
}
}
}
use std::any::Any;
impl ToAnyTag for #name {
fn to_anytag(&self) -> AnyTag<'_> {
self.into()
}
}
impl ToAny for #name {
fn to_any(&self) -> &dyn Any {
self
}
fn to_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl AudioTag for #name {}
// From wrapper to inner (same type)
impl From<#name> for #inner {
fn from(inp: #name) -> Self {
inp.inner
}
}
// From inner to wrapper (same type)
impl From<#inner> for #name {
fn from(inp: #inner) -> Self {
Self {
inner: inp,
properties: FileProperties::default(),
_format: #tag_type
}
}
}
impl<'a> From<&'a #name> for AnyTag<'a> {
fn from(inp: &'a #name) -> Self {
Self {
title: inp.title(),
artist: inp.artist(),
year: inp.year().map(|y| y as i32),
album: Album::new(
inp.album_title(),
inp.album_artist(),
inp.album_covers(),
),
track_number: inp.track_number(),
total_tracks: inp.total_tracks(),
disc_number: inp.disc_number(),
total_discs: inp.total_discs(),
comments: None, // TODO
date: inp.date(),
}
}
}
impl<'a> From<AnyTag<'a>> for #name {
fn from(inp: AnyTag<'a>) -> Self {
let mut tag = #name::new();
if let Some(v) = inp.title() {
tag.set_title(v)
}
if let Some(v) = inp.artist() {
tag.set_artist(&v)
}
if let Some(v) = inp.year {
tag.set_year(v)
}
if let Some(v) = inp.track_number() {
tag.set_track_number(v)
}
if let Some(v) = inp.total_tracks() {
tag.set_total_tracks(v)
}
if let Some(v) = inp.disc_number() {
tag.set_disc_number(v)
}
if let Some(v) = inp.total_discs() {
tag.set_total_discs(v)
}
let album = inp.album();
if let Some(v) = album.title {
tag.set_album_title(v)
}
if let Some(v) = album.artist {
tag.set_album_artist(v)
}
if let Some(v) = album.covers.0 {
tag.set_front_cover(v)
}
if let Some(v) = album.covers.1 {
tag.set_back_cover(v)
}
tag
}
}
// From dyn AudioTag to wrapper (any type)
impl From<Box<dyn AudioTag>> for #name {
fn from(inp: Box<dyn AudioTag>) -> Self {
let mut inp = inp;
if let Some(t_refmut) = inp.to_any_mut().downcast_mut::<#name>() {
let t = std::mem::replace(t_refmut, #name::new()); // TODO: can we avoid creating the dummy tag?
t
} else {
let mut t = inp.to_dyn_tag(#tag_type);
let t_refmut = t.to_any_mut().downcast_mut::<#name>().unwrap();
let t = std::mem::replace(t_refmut, #name::new());
t
}
}
}
// From dyn AudioTag to inner (any type)
impl From<Box<dyn AudioTag>> for #inner {
fn from(inp: Box<dyn AudioTag>) -> Self {
let t: #name = inp.into();
t.into()
}
}
})
}
#[proc_macro]
pub fn str_accessor(input: TokenStream) -> TokenStream {
let input_str = input.to_string();
let name = input_str.replace("_", " ");
format!(
"/// Returns the {display}
fn {ident}(&self) -> Option<&str> {{
None
}}
/// Sets the {display}
fn set_{ident}(&mut self, _{ident}: &str) {{}}
/// Removes the {display}
fn remove_{ident}(&mut self) {{}}
",
ident = input_str,
display = name,
)
.parse()
.expect("Unable to parse str accessor:")
}
#[proc_macro]
pub fn u16_accessor(input: TokenStream) -> TokenStream {
let input_str = input.to_string();
let name = input_str.replace("_", " ");
format!(
"/// Returns the {display}
fn {ident}(&self) -> Option<u16> {{
None
}}
/// Sets the {display}
fn set_{ident}(&mut self, _{ident}: u16) {{}}
/// Removes the {display}
fn remove_{ident}(&mut self) {{}}
",
ident = input_str,
display = name,
)
.parse()
.expect("Unable to parse u16 accessor:")
}
#[proc_macro]
pub fn u32_accessor(input: TokenStream) -> TokenStream {
let input_str = input.to_string();
let name = input_str.replace("_", " ");
format!(
"/// Returns the {display}
fn {ident}(&self) -> Option<u32> {{
None
}}
/// Sets the {display}
fn set_{ident}(&mut self, _{ident}: u32) {{}}
/// Removes the {display}
fn remove_{ident}(&mut self) {{}}
",
ident = input_str,
display = name,
)
.parse()
.expect("Unable to parse u32 accessor:")
}
#[proc_macro]
pub fn i32_accessor(input: TokenStream) -> TokenStream {
let input_str = input.to_string();
let name = input_str.replace("_", " ");
format!(
"/// Returns the {display}
fn {ident}(&self) -> Option<i32> {{
None
}}
/// Sets the {display}
fn set_{ident}(&mut self, _{ident}: i32) {{}}
/// Removes the {display}
fn remove_{ident}(&mut self) {{}}
",
ident = input_str,
display = name,
)
.parse()
.expect("Unable to parse i32 accessor:")
}
/// Used to create simple tag methods for getting/setting/removing based on a key
#[proc_macro]
pub fn get_set_methods(input: TokenStream) -> TokenStream {
let input = input.to_string();
let mut input_split = input.split(',');
let name = input_split.next().expect("No identifier provided");
let key = input_split.next().expect("No key provided");
format!(
"fn {ident}(&self) -> Option<&str> {{
self.get_value({key})
}}
fn set_{ident}(&mut self, {ident}: &str) {{
self.set_value({key}, {ident})
}}
fn remove_{ident}(&mut self) {{
self.remove_key({key})
}}",
ident = name,
key = key
)
.parse()
.expect("Unable to parse getters/setters:")
}