mirror of
https://github.com/Serial-ATA/lofty-rs
synced 2024-12-13 22:22:31 +00:00
Remove lofty-attr
This commit is contained in:
parent
419f8457a3
commit
b510179372
3 changed files with 1 additions and 335 deletions
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "lofty"
|
name = "lofty"
|
||||||
version = "0.3.0"
|
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"
|
edition = "2018"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
description = "Unified IO for different types of audio metadata"
|
description = "Unified IO for different types of audio metadata"
|
||||||
|
@ -27,8 +27,6 @@ base64 = "0.13.0"
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
cfg-if = "1.0.0"
|
cfg-if = "1.0.0"
|
||||||
|
|
||||||
lofty_attr = "0.1.9"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["all_tags"]
|
default = ["all_tags"]
|
||||||
format-mp4 = ["mp4ameta"]
|
format-mp4 = ["mp4ameta"]
|
||||||
|
|
|
@ -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
|
|
|
@ -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:")
|
|
||||||
}
|
|
Loading…
Reference in a new issue