it worked! From dyn Tag into any concrete tag without cloning

This commit is contained in:
Tianyi 2020-10-29 13:26:35 +00:00
parent e218f6c47d
commit aa945ae7b6
29 changed files with 150 additions and 123 deletions

64
.github/workflow/main.yml vendored Normal file
View file

@ -0,0 +1,64 @@
on: [push, pull_request]
name: Continuous integration
jobs:
check:
name: Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- uses: actions-rs/cargo@v1
with:
command: check
test:
name: Test Suite
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- uses: actions-rs/cargo@v1
with:
command: test
fmt:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- run: rustup component add rustfmt
- uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- run: rustup component add clippy
- uses: actions-rs/cargo@v1
with:
command: clippy
args: -- -D warnings

View file

@ -1,3 +1,11 @@
## [0.2.718] 2020-10-27
- downcasting
## [0.2.71] 2020-10-27
- Remove use of `Cow`
## [0.2.5] 2020-10-27
- Naive implementation of config

View file

@ -1,6 +1,6 @@
[package]
name = "audiotags"
version = "0.2.71"
version = "0.2.718"
authors = ["Tianyi <ShiTianyi2001@outlook.com>"]
edition = "2018"
description = "Unified IO for different types of audio metadata"
@ -14,4 +14,4 @@ id3 = "0.5.1"
mp4ameta = "0.6"
metaflac = "0.2"
thiserror = "1.0.21"
audiotags-dev-macro = {path = "./audiotags-dev-macro", version = "0.1.2"}
audiotags-dev-macro = {path = "./audiotags-dev-macro", version = "0.1"}

Binary file not shown.

View file

@ -1,6 +1,6 @@
[package]
name = "audiotags-dev-macro"
version = "0.1.2"
version = "0.1.3"
authors = ["Tianyi <ShiTianyi2001@outlook.com>"]
edition = "2018"
description = "macros used during the development of audiotags"

View file

@ -14,7 +14,7 @@ macro_rules! impl_audiotag_config {
#[macro_export]
macro_rules! impl_tag {
($tag:ident , $inner:ident) => {
($tag:ident , $inner:ident, $tag_type:expr) => {
#[derive(Default)]
pub struct $tag {
inner: $inner,
@ -33,13 +33,24 @@ macro_rules! impl_tag {
}
impl_audiotag_config!($tag);
use std::any::Any;
impl IntoAnyTag for $tag {
fn into_anytag(&self) -> AnyTag<'_> {
self.into()
}
fn into_any(&self) -> &dyn std::any::Any {
fn into_any(&self) -> &dyn Any {
self
}
fn into_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl $tag {
pub(crate) fn into_any_owned(self) -> Box<dyn Any> {
Box::new(self)
}
}
impl AudioTag for $tag {}
@ -61,23 +72,45 @@ macro_rules! impl_tag {
// downcasting
impl<'a> std::convert::TryFrom<&'a Box<dyn AudioTag>> for &'a $tag {
type Error = crate::Error;
fn try_from(inp: &'a Box<dyn AudioTag>) -> crate::Result<Self> {
inp.into_any()
.downcast_ref::<$tag>()
.ok_or(crate::Error::DowncastError)
// impl<'a> std::convert::TryFrom<&'a Box<dyn AudioTag>> for &'a $tag {
// type Error = crate::Error;
// fn try_from(inp: &'a Box<dyn AudioTag>) -> crate::Result<Self> {
// inp.into_any()
// .downcast_ref::<$tag>()
// .ok_or(crate::Error::DowncastError)
// }
// }
impl From<Box<dyn AudioTag>> for $tag {
fn from(inp: Box<dyn AudioTag>) -> Self {
let mut inp = inp;
if let Some(t_refmut) = inp.into_any_mut().downcast_mut::<$tag>() {
let t = std::mem::replace(t_refmut, $tag::new()); // TODO: can we avoid creating the dummy tag?
t
} else {
let mut t = inp.into_tag($tag_type);
let t_refmut = t.into_any_mut().downcast_mut::<$tag>().unwrap();
let t = std::mem::replace(t_refmut, $tag::new());
t
}
}
}
impl std::convert::TryFrom<Box<dyn AudioTag>> for $inner {
type Error = crate::Error;
fn try_from(inp: Box<dyn AudioTag>) -> crate::Result<Self> {
let t: &$tag = inp
.into_any()
.downcast_ref::<$tag>()
.ok_or(crate::Error::DowncastError)?;
Ok(t.into())
// impl std::convert::TryFrom<Box<dyn AudioTag>> for $inner {
// type Error = crate::Error;
// fn try_from(inp: Box<dyn AudioTag>) -> crate::Result<Self> {
// let t: &$tag = inp
// .into_any()
// .downcast_ref::<$tag>()
// .ok_or(crate::Error::DowncastError)?;
// Ok(t.into())
// }
// }
impl std::convert::From<Box<dyn AudioTag>> for $inner {
fn from(inp: Box<dyn AudioTag>) -> Self {
let t: $tag = inp.into();
(&t).into()
}
}
};

Binary file not shown.

View file

@ -1,6 +1,7 @@
book_filename: "audiotags"
rmd_files: ["index.Rmd", "simple.Rmd", "convert.Rmd", "anytag.Rmd", "downcast.Rmd"]
output_dir: "../docs"
delete_merged_file: true
language:
ui:
chapter_name: "Chapter "
# language:
# ui:
# chapter_name: "Chapter "

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

View file

@ -21,7 +21,7 @@ fn main() {
.expect("Fail to read!");
assert_eq!(id3tag_reload.title(), Some("title from metaflac::Tag"));
let mut id3tag_inner: id3::Tag = id3tag_reload.try_into().unwrap();
let mut id3tag_inner: id3::Tag = id3tag_reload.into();
// this would fail if `id3tag_reload` isn't really a id3 tag.
let timestamp = id3::Timestamp {

View file

@ -4,7 +4,7 @@ author: "Tianyi Shi"
date: "`r Sys.Date()`"
site: bookdown::bookdown_site
documentclass: book
bibliography: [book.bib, packages.bib]
bibliography: [book.bib]
biblio-style: apalike
link-citations: yes
description: "This is the manual of the Rust crate 'audiotags'"

0
rtfm/intro.Rmd Normal file
View file

View file

@ -1,85 +0,0 @@
@Manual{R-base,
title = {R: A Language and Environment for Statistical Computing},
author = {{R Core Team}},
organization = {R Foundation for Statistical Computing},
address = {Vienna, Austria},
year = {2020},
url = {https://www.R-project.org/},
}
@Manual{R-bookdown,
title = {bookdown: Authoring Books and Technical Documents with R Markdown},
author = {Yihui Xie},
year = {2020},
note = {R package version 0.21},
url = {https://github.com/rstudio/bookdown},
}
@Manual{R-knitr,
title = {knitr: A General-Purpose Package for Dynamic Report Generation in R},
author = {Yihui Xie},
year = {2020},
note = {R package version 1.30},
url = {https://yihui.org/knitr/},
}
@Manual{R-rmarkdown,
title = {rmarkdown: Dynamic Documents for R},
author = {JJ Allaire and Yihui Xie and Jonathan McPherson and Javier Luraschi and Kevin Ushey and Aron Atkins and Hadley Wickham and Joe Cheng and Winston Chang and Richard Iannone},
year = {2020},
note = {R package version 2.4},
url = {https://github.com/rstudio/rmarkdown},
}
@Book{bookdown2016,
title = {bookdown: Authoring Books and Technical Documents with {R} Markdown},
author = {Yihui Xie},
publisher = {Chapman and Hall/CRC},
address = {Boca Raton, Florida},
year = {2016},
note = {ISBN 978-1138700109},
url = {https://github.com/rstudio/bookdown},
}
@Book{knitr2015,
title = {Dynamic Documents with {R} and knitr},
author = {Yihui Xie},
publisher = {Chapman and Hall/CRC},
address = {Boca Raton, Florida},
year = {2015},
edition = {2nd},
note = {ISBN 978-1498716963},
url = {https://yihui.org/knitr/},
}
@InCollection{knitr2014,
booktitle = {Implementing Reproducible Computational Research},
editor = {Victoria Stodden and Friedrich Leisch and Roger D. Peng},
title = {knitr: A Comprehensive Tool for Reproducible Research in {R}},
author = {Yihui Xie},
publisher = {Chapman and Hall/CRC},
year = {2014},
note = {ISBN 978-1466561595},
url = {http://www.crcpress.com/product/isbn/9781466561595},
}
@Book{rmarkdown2018,
title = {R Markdown: The Definitive Guide},
author = {Yihui Xie and J.J. Allaire and Garrett Grolemund},
publisher = {Chapman and Hall/CRC},
address = {Boca Raton, Florida},
year = {2018},
note = {ISBN 9781138359338},
url = {https://bookdown.org/yihui/rmarkdown},
}
@Book{rmarkdown2020,
title = {R Markdown Cookbook},
author = {Yihui Xie and Christophe Dervieux and Emily Riederer},
publisher = {Chapman and Hall/CRC},
address = {Boca Raton, Florida},
year = {2020},
note = {ISBN 9780367563837},
url = {https://bookdown.org/yihui/rmarkdown-cookbook},
}

View file

@ -14,15 +14,6 @@ pre code {
}
@font-face {
font-family: 'Merriweather';
font-style: normal;
font-weight: 400;
src: local('Merriweather'), local('Merriweather-Regular'),
url('https://tianyishi2001.github.io/ox/fonts/merriweather-v13-latin-regular.woff2') format('woff2'),
url('https://tianyishi2001.github.io/ox/fonts/merriweather-v13-latin-regular.woff') format('woff');
}
@font-face {
font-family: 'Lato';
font-style: normal;

View file

@ -3,7 +3,7 @@ use metaflac;
pub use metaflac::Tag as FlacInnerTag;
impl_tag!(FlacTag, FlacInnerTag);
impl_tag!(FlacTag, FlacInnerTag, TagType::Flac);
impl<'a> From<AnyTag<'a>> for FlacTag {
fn from(inp: AnyTag<'a>) -> Self {

View file

@ -3,7 +3,7 @@ use id3;
pub use id3::Tag as Id3v2InnerTag;
impl_tag!(Id3v2Tag, Id3v2InnerTag);
impl_tag!(Id3v2Tag, Id3v2InnerTag, TagType::Id3v2);
impl<'a> From<&'a Id3v2Tag> for AnyTag<'a> {
fn from(inp: &'a Id3v2Tag) -> Self {

View file

@ -3,7 +3,7 @@ use mp4ameta;
pub use mp4ameta::Tag as Mp4InnerTag;
impl_tag!(Mp4Tag, Mp4InnerTag);
impl_tag!(Mp4Tag, Mp4InnerTag, TagType::Mp4);
impl<'a> From<&'a Mp4Tag> for AnyTag<'a> {
fn from(inp: &'a Mp4Tag) -> Self {

View file

@ -27,7 +27,7 @@
//! struct. However, this is going to be a lot of work. I might be able to implement them, but it will be no
//! sooner than the Christmas vacation.
//!
//! See [README](https://github.com/TianyiShi2001/audiotags) for some examples.
//! Read the [manual](https://tianyishi2001.github.io/audiotags) for some examples.
pub(crate) use audiotags_dev_macro::*;

View file

@ -151,4 +151,18 @@ pub trait IntoAnyTag {
}
}
fn into_any(&self) -> &dyn std::any::Any;
fn into_any_mut(&mut self) -> &mut dyn std::any::Any;
}
// struct BoxedAudioTagWrapper {
// inner: Box<dyn AudioTag>,
// }
// impl<'a> BoxedAudioTagWrapper {
// fn into_tag<T>(self) -> T
// where
// T: From<AnyTag<'a>>,
// {
// self.inner.into_anytag().into()
// }
// }

View file

@ -17,7 +17,8 @@ fn test_inner() {
.expect("Fail to read!");
assert_eq!(id3tag_reload.title(), Some("title from metaflac::Tag"));
let mut id3tag_inner: id3::Tag = id3tag_reload.try_into().unwrap();
// let id3tag: Id3v2Tag = id3tag_reload.into();
let mut id3tag_inner: id3::Tag = id3tag_reload.into();
let timestamp = id3::Timestamp {
year: 2013,
month: Some(2u8),