This commit is contained in:
Tianyi 2020-10-29 18:01:21 +00:00
parent aa945ae7b6
commit 1206194d5f
26 changed files with 735 additions and 316 deletions

View file

@ -1,3 +1,8 @@
## [0.2.7182] 2020-10-29
- Improve docs
- Ergonomic conversions
## [0.2.718] 2020-10-27
- downcasting

View file

@ -14,4 +14,8 @@ id3 = "0.5.1"
mp4ameta = "0.6"
metaflac = "0.2"
thiserror = "1.0.21"
audiotags-dev-macro = {path = "./audiotags-dev-macro", version = "0.1"}
audiotags-dev-macro = {path = "./audiotags-dev-macro", version = "0.1"}
[features]
defualt = ['from']
from = []

Binary file not shown.

View file

@ -35,32 +35,31 @@ macro_rules! impl_tag {
use std::any::Any;
impl IntoAnyTag for $tag {
fn into_anytag(&self) -> AnyTag<'_> {
impl ToAnyTag for $tag {
fn to_anytag(&self) -> AnyTag<'_> {
self.into()
}
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 ToAny for $tag {
fn to_any(&self) -> &dyn Any {
self
}
fn to_any_mut(&mut self) -> &mut dyn Any {
self
}
}
impl AudioTag for $tag {}
impl From<&$tag> for $inner {
fn from(inp: &$tag) -> Self {
inp.inner.clone()
// From wrapper to inner (same type)
impl From<$tag> for $inner {
fn from(inp: $tag) -> Self {
inp.inner
}
}
// From inner to wrapper (same type)
impl From<$inner> for $tag {
fn from(inp: $inner) -> Self {
Self {
@ -70,47 +69,26 @@ 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)
// }
// }
// From dyn AudioTag to wrapper (any type)
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>() {
if let Some(t_refmut) = inp.to_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 mut t = inp.to_dyn_tag($tag_type);
let t_refmut = t.to_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())
// }
// }
// From dyn AudioTag to inner (any type)
impl std::convert::From<Box<dyn AudioTag>> for $inner {
fn from(inp: Box<dyn AudioTag>) -> Self {
let t: $tag = inp.into();
(&t).into()
t.into()
}
}
};

View file

@ -4,11 +4,11 @@
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Chapter 3 AnyTag | audiotags Manual</title>
<title>3 AnyTag | audiotags Manual</title>
<meta name="description" content="This is the manual of the Rust crate audiotags" />
<meta name="generator" content="bookdown 0.21 and GitBook 2.6.7" />
<meta property="og:title" content="Chapter 3 AnyTag | audiotags Manual" />
<meta property="og:title" content="3 AnyTag | audiotags Manual" />
<meta property="og:type" content="book" />
@ -16,7 +16,7 @@
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Chapter 3 AnyTag | audiotags Manual" />
<meta name="twitter:title" content="3 AnyTag | audiotags Manual" />
<meta name="twitter:description" content="This is the manual of the Rust crate audiotags" />
@ -24,15 +24,15 @@
<meta name="author" content="Tianyi Shi" />
<meta name="date" content="2020-10-27" />
<meta name="date" content="2020-10-29" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<link rel="prev" href="conversion.html"/>
<link rel="next" href="downcast.html"/>
<link rel="prev" href="conversion-and-downcast.html"/>
<script src="libs/header-attrs-2.4/header-attrs.js"></script>
<script src="libs/jquery-2.2.3/jquery.min.js"></script>
<link href="libs/gitbook-2.6.7/css/style.css" rel="stylesheet" />
@ -138,10 +138,13 @@ code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warni
<li class="chapter" data-level="" data-path="index.html"><a href="index.html#examples-in-this-manual"><i class="fa fa-check"></i>Examples in this manual</a></li>
</ul></li>
<li class="chapter" data-level="1" data-path="start-simple.html"><a href="start-simple.html"><i class="fa fa-check"></i><b>1</b> Start Simple</a></li>
<li class="chapter" data-level="2" data-path="conversion.html"><a href="conversion.html"><i class="fa fa-check"></i><b>2</b> Conversion</a></li>
<li class="chapter" data-level="2" data-path="conversion-and-downcast.html"><a href="conversion-and-downcast.html"><i class="fa fa-check"></i><b>2</b> Conversion and Downcast</a>
<ul>
<li class="chapter" data-level="2.1" data-path="conversion-and-downcast.html"><a href="conversion-and-downcast.html#converting-from-a-boxdyn-audiotag-to-another"><i class="fa fa-check"></i><b>2.1</b> Converting from a <code>Box&lt;dyn AudioTag</code> to Another</a></li>
<li class="chapter" data-level="2.2" data-path="conversion-and-downcast.html"><a href="conversion-and-downcast.html#converting-into-a-concrete-type-downcasting"><i class="fa fa-check"></i><b>2.2</b> Converting into a Concrete Type (Downcasting)</a></li>
<li class="chapter" data-level="2.3" data-path="conversion-and-downcast.html"><a href="conversion-and-downcast.html#upcasting"><i class="fa fa-check"></i><b>2.3</b> Upcasting</a></li>
</ul></li>
<li class="chapter" data-level="3" data-path="anytag.html"><a href="anytag.html"><i class="fa fa-check"></i><b>3</b> <code>AnyTag</code></a></li>
<li class="chapter" data-level="4" data-path="downcast.html"><a href="downcast.html"><i class="fa fa-check"></i><b>4</b> Downcast</a></li>
<li class="chapter" data-level="" data-path="references.html"><a href="references.html"><i class="fa fa-check"></i>References</a></li>
<li class="divider"></li>
<li><a href="https://github.com/rstudio/bookdown" target="blank">Published with bookdown</a></li>
@ -163,18 +166,18 @@ code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warni
<section class="normal" id="section-">
<div id="anytag" class="section level1" number="3">
<h1><span class="header-section-number">Chapter 3</span> <code>AnyTag</code></h1>
<h1><span class="header-section-number">3</span> <code>AnyTag</code></h1>
<p>The following example shows how you can create a “generic” <code>AnyTag</code> and convert it into a specific tag type.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb3-1"><a href="anytag.html#cb3-1" aria-hidden="true"></a><span class="kw">use</span> <span class="pp">audiotags::</span><span class="op">{</span>AnyTag<span class="op">,</span> AudioTagEdit<span class="op">,</span> Id3v2Tag<span class="op">};</span></span>
<span id="cb3-2"><a href="anytag.html#cb3-2" aria-hidden="true"></a></span>
<span id="cb3-3"><a href="anytag.html#cb3-3" aria-hidden="true"></a><span class="kw">fn</span> main() <span class="op">{</span></span>
<span id="cb3-4"><a href="anytag.html#cb3-4" aria-hidden="true"></a> <span class="kw">let</span> <span class="kw">mut</span> tag <span class="op">=</span> <span class="pp">AnyTag::</span><span class="kw">default</span>()<span class="op">;</span></span>
<span id="cb3-5"><a href="anytag.html#cb3-5" aria-hidden="true"></a> tag<span class="op">.</span>set_title(<span class="st">&quot;foo&quot;</span>)<span class="op">;</span></span>
<span id="cb3-6"><a href="anytag.html#cb3-6" aria-hidden="true"></a> tag<span class="op">.</span>set_year(<span class="dv">2001</span>)<span class="op">;</span></span>
<span id="cb3-7"><a href="anytag.html#cb3-7" aria-hidden="true"></a> <span class="kw">let</span> tag<span class="op">:</span> Id3v2Tag <span class="op">=</span> tag<span class="op">.</span>into()<span class="op">;</span></span>
<span id="cb3-8"><a href="anytag.html#cb3-8" aria-hidden="true"></a> <span class="pp">assert_eq!</span>(tag<span class="op">.</span>year()<span class="op">,</span> <span class="cn">Some</span>(<span class="dv">2001</span>))<span class="op">;</span></span>
<span id="cb3-9"><a href="anytag.html#cb3-9" aria-hidden="true"></a> tag<span class="op">.</span>write_to_path(<span class="st">&quot;assets/a.mp3&quot;</span>)<span class="op">.</span>unwrap()<span class="op">;</span></span>
<span id="cb3-10"><a href="anytag.html#cb3-10" aria-hidden="true"></a><span class="op">}</span></span></code></pre></div>
<div class="sourceCode" id="cb7"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb7-1"><a href="anytag.html#cb7-1" aria-hidden="true"></a><span class="kw">use</span> <span class="pp">audiotags::</span><span class="op">{</span>AnyTag<span class="op">,</span> AudioTagEdit<span class="op">,</span> Id3v2Tag<span class="op">};</span></span>
<span id="cb7-2"><a href="anytag.html#cb7-2" aria-hidden="true"></a></span>
<span id="cb7-3"><a href="anytag.html#cb7-3" aria-hidden="true"></a><span class="kw">fn</span> main() <span class="op">{</span></span>
<span id="cb7-4"><a href="anytag.html#cb7-4" aria-hidden="true"></a> <span class="kw">let</span> <span class="kw">mut</span> tag <span class="op">=</span> <span class="pp">AnyTag::</span><span class="kw">default</span>()<span class="op">;</span></span>
<span id="cb7-5"><a href="anytag.html#cb7-5" aria-hidden="true"></a> tag<span class="op">.</span>set_title(<span class="st">&quot;foo&quot;</span>)<span class="op">;</span></span>
<span id="cb7-6"><a href="anytag.html#cb7-6" aria-hidden="true"></a> tag<span class="op">.</span>set_year(<span class="dv">2001</span>)<span class="op">;</span></span>
<span id="cb7-7"><a href="anytag.html#cb7-7" aria-hidden="true"></a> <span class="kw">let</span> tag<span class="op">:</span> Id3v2Tag <span class="op">=</span> tag<span class="op">.</span>into()<span class="op">;</span></span>
<span id="cb7-8"><a href="anytag.html#cb7-8" aria-hidden="true"></a> <span class="pp">assert_eq!</span>(tag<span class="op">.</span>year()<span class="op">,</span> <span class="cn">Some</span>(<span class="dv">2001</span>))<span class="op">;</span></span>
<span id="cb7-9"><a href="anytag.html#cb7-9" aria-hidden="true"></a> tag<span class="op">.</span>write_to_path(<span class="st">&quot;assets/a.mp3&quot;</span>)<span class="op">.</span>unwrap()<span class="op">;</span></span>
<span id="cb7-10"><a href="anytag.html#cb7-10" aria-hidden="true"></a><span class="op">}</span></span></code></pre></div>
</div>
</section>
@ -182,8 +185,8 @@ code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warni
</div>
</div>
</div>
<a href="conversion.html" class="navigation navigation-prev " aria-label="Previous page"><i class="fa fa-angle-left"></i></a>
<a href="downcast.html" class="navigation navigation-next " aria-label="Next page"><i class="fa fa-angle-right"></i></a>
<a href="conversion-and-downcast.html" class="navigation navigation-prev navigation-unique" aria-label="Previous page"><i class="fa fa-angle-left"></i></a>
</div>
</div>
<script src="libs/gitbook-2.6.7/js/app.min.js"></script>

Binary file not shown.

Binary file not shown.

View file

@ -116,7 +116,7 @@
\title{audiotags Manual}
\author{Tianyi Shi}
\date{2020-10-27}
\date{2020-10-29}
\begin{document}
\maketitle
@ -155,16 +155,13 @@ The following example shows how you can read an audio file, parse, set, and save
\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{use} \PreprocessorTok{audiotags::}\OperatorTok{\{}\NormalTok{MimeType}\OperatorTok{,}\NormalTok{ Picture}\OperatorTok{,}\NormalTok{ Tag}\OperatorTok{,}\NormalTok{ TagType}\OperatorTok{\};}
\KeywordTok{const}\NormalTok{ MP3\_FILE}\OperatorTok{:} \OperatorTok{\&}\OtherTok{\textquotesingle{}static} \DataTypeTok{str} \OperatorTok{=} \StringTok{"assets/a.mp3"}\OperatorTok{;}
\KeywordTok{fn}\NormalTok{ main() }\OperatorTok{\{}
\CommentTok{// using \textasciigrave{}default()\textasciigrave{} so that the metadata format is guessed}
\CommentTok{// (from the file extension) (in this case, Id3v2 tag is read)}
\KeywordTok{let} \KeywordTok{mut}\NormalTok{ tag }\OperatorTok{=} \PreprocessorTok{Tag::}\KeywordTok{default}\NormalTok{()}\OperatorTok{.}\NormalTok{read\_from\_path(MP3\_FILE)}\OperatorTok{.}\NormalTok{unwrap()}\OperatorTok{;}
\CommentTok{// using \textasciigrave{}default()\textasciigrave{} or \textasciigrave{}new()\textasciigrave{} alone so that the metadata format is}
\CommentTok{// guessed (from the file extension) (in this case, Id3v2 tag is read)}
\KeywordTok{let} \KeywordTok{mut}\NormalTok{ tag }\OperatorTok{=} \PreprocessorTok{Tag::}\NormalTok{new()}\OperatorTok{.}\NormalTok{read\_from\_path(MP3\_FILE)}\OperatorTok{.}\NormalTok{unwrap()}\OperatorTok{;}
\CommentTok{// You can also specify the metadata format (tag type):}
\KeywordTok{let}\NormalTok{ \_tag }\OperatorTok{=} \PreprocessorTok{Tag::}\NormalTok{with\_tag\_type(}\PreprocessorTok{TagType::}\NormalTok{Id3v2)}
\KeywordTok{let}\NormalTok{ \_tag }\OperatorTok{=} \PreprocessorTok{Tag::}\NormalTok{new()}
\OperatorTok{.}\NormalTok{with\_tag\_type(}\PreprocessorTok{TagType::}\NormalTok{Id3v2)}
\OperatorTok{.}\NormalTok{read\_from\_path(MP3\_FILE)}
\OperatorTok{.}\NormalTok{expect(}\StringTok{"Fail to read!"}\NormalTok{)}\OperatorTok{;}
@ -186,19 +183,45 @@ The following example shows how you can read an audio file, parse, set, and save
\PreprocessorTok{assert!}\NormalTok{(tag}\OperatorTok{.}\NormalTok{album\_cover()}\OperatorTok{.}\NormalTok{is\_none())}\OperatorTok{;}
\NormalTok{ tag}\OperatorTok{.}\NormalTok{remove\_album\_cover()}\OperatorTok{;}
\NormalTok{ tag}\OperatorTok{.}\NormalTok{save\_to\_path(MP3\_FILE)}\OperatorTok{.}\NormalTok{expect(}\StringTok{"Fail to save"}\NormalTok{)}\OperatorTok{;}
\NormalTok{ tag}\OperatorTok{.}\NormalTok{write\_to\_path(MP3\_FILE)}\OperatorTok{.}\NormalTok{expect(}\StringTok{"Fail to save"}\NormalTok{)}\OperatorTok{;}
\CommentTok{// }\AlertTok{TASK}\CommentTok{: reload the file and prove the data have been saved}
\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}
\hypertarget{conversion}{%
\chapter{Conversion}\label{conversion}}
The following example shows how you can read the tag in an \texttt{mp3} file, convert it into an \texttt{mp4} tag, and write it to an \texttt{m4a} file.
Note that \texttt{Tag} always reads into a \texttt{Box\textless{}dyn\ AudioTag\textgreater{}}. If you do not want a trait object, you can use the underlying concrete types. However, you'll also need to manually bring the traits into scope if you prefer not to write \texttt{audiotags::*}.
\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{use} \PreprocessorTok{audiotags::}\OperatorTok{\{}\PreprocessorTok{traits::}\OperatorTok{*,}\NormalTok{ FlacTag}\OperatorTok{,}\NormalTok{ Id3v2Tag}\OperatorTok{,}\NormalTok{ Mp4Tag}\OperatorTok{\};}
\CommentTok{// or alternatively \textasciigrave{}use audiotags::*\textasciigrave{}}
\KeywordTok{fn}\NormalTok{ main() }\OperatorTok{\{}
\KeywordTok{let} \KeywordTok{mut}\NormalTok{ tag }\OperatorTok{=} \PreprocessorTok{FlacTag::}\NormalTok{read\_from\_path(}\StringTok{"assets/a.flac"}\NormalTok{)}\OperatorTok{.}\NormalTok{unwrap()}\OperatorTok{;}
\NormalTok{ tag}\OperatorTok{.}\NormalTok{set\_title(}\StringTok{"foo"}\NormalTok{)}\OperatorTok{;}
\PreprocessorTok{assert\_eq!}\NormalTok{(tag}\OperatorTok{.}\NormalTok{title()}\OperatorTok{,} \ConstantTok{Some}\NormalTok{(}\StringTok{"foo"}\NormalTok{))}\OperatorTok{;}
\KeywordTok{let} \KeywordTok{mut}\NormalTok{ tag }\OperatorTok{=} \PreprocessorTok{Mp4Tag::}\NormalTok{read\_from\_path(}\StringTok{"assets/a.m4a"}\NormalTok{)}\OperatorTok{.}\NormalTok{unwrap()}\OperatorTok{;}
\NormalTok{ tag}\OperatorTok{.}\NormalTok{set\_title(}\StringTok{"foo"}\NormalTok{)}\OperatorTok{;}
\PreprocessorTok{assert\_eq!}\NormalTok{(tag}\OperatorTok{.}\NormalTok{title()}\OperatorTok{,} \ConstantTok{Some}\NormalTok{(}\StringTok{"foo"}\NormalTok{))}\OperatorTok{;}
\KeywordTok{let} \KeywordTok{mut}\NormalTok{ tag }\OperatorTok{=} \PreprocessorTok{Id3v2Tag::}\NormalTok{read\_from\_path(}\StringTok{"assets/a.mp3"}\NormalTok{)}\OperatorTok{.}\NormalTok{unwrap()}\OperatorTok{;}
\NormalTok{ tag}\OperatorTok{.}\NormalTok{set\_title(}\StringTok{"foo"}\NormalTok{)}\OperatorTok{;}
\PreprocessorTok{assert\_eq!}\NormalTok{(tag}\OperatorTok{.}\NormalTok{title()}\OperatorTok{,} \ConstantTok{Some}\NormalTok{(}\StringTok{"foo"}\NormalTok{))}\OperatorTok{;}
\CommentTok{// all other methods in trait \textasciigrave{}AudioTagEdit\textasciigrave{} are available, not just title}
\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}
\hypertarget{conversion-and-downcast}{%
\chapter{Conversion and Downcast}\label{conversion-and-downcast}}
The following example shows how you can read the tag in an \texttt{mp3} file, convert it into an \texttt{mp4} tag, and write it to an \texttt{m4a} file.
\hypertarget{converting-from-a-boxdyn-audiotag-to-another}{%
\section{\texorpdfstring{Converting from a \texttt{Box\textless{}dyn\ AudioTag} to Another}{Converting from a Box\textless dyn AudioTag to Another}}\label{converting-from-a-boxdyn-audiotag-to-another}}
\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{use} \PreprocessorTok{audiotags::}\OperatorTok{\{}\NormalTok{Config}\OperatorTok{,}\NormalTok{ Tag}\OperatorTok{,}\NormalTok{ TagType}\OperatorTok{\};}
\KeywordTok{fn}\NormalTok{ main() }\OperatorTok{\{}
@ -211,12 +234,13 @@ The following example shows how you can read the tag in an \texttt{mp3} file, co
\CommentTok{// set the title}
\NormalTok{ mp3tag}\OperatorTok{.}\NormalTok{set\_title(}\StringTok{"title from mp3 file"}\NormalTok{)}\OperatorTok{;}
\CommentTok{// we can convert it to an mp4 tag and save it to an m4a file.}
\KeywordTok{let} \KeywordTok{mut}\NormalTok{ mp4tag }\OperatorTok{=}\NormalTok{ mp3tag}\OperatorTok{.}\NormalTok{into\_tag(}\PreprocessorTok{TagType::}\NormalTok{Mp4)}\OperatorTok{;}
\KeywordTok{let} \KeywordTok{mut}\NormalTok{ mp4tag }\OperatorTok{=}\NormalTok{ mp3tag}\OperatorTok{.}\NormalTok{to\_dyn\_tag(}\PreprocessorTok{TagType::}\NormalTok{Mp4)}\OperatorTok{;}
\NormalTok{ mp4tag}\OperatorTok{.}\NormalTok{write\_to\_path(M4A\_FILE)}\OperatorTok{.}\NormalTok{unwrap()}\OperatorTok{;}
\CommentTok{// reload the tag from the m4a file; this time specifying the}
\CommentTok{// tag type (you can also use \textasciigrave{}default()\textasciigrave{})}
\KeywordTok{let} \KeywordTok{mut}\NormalTok{ mp4tag }\OperatorTok{=} \PreprocessorTok{Tag::}\NormalTok{with\_tag\_type(}\PreprocessorTok{TagType::}\NormalTok{Mp4)}
\KeywordTok{let} \KeywordTok{mut}\NormalTok{ mp4tag }\OperatorTok{=} \PreprocessorTok{Tag::}\NormalTok{new()}
\OperatorTok{.}\NormalTok{with\_tag\_type(}\PreprocessorTok{TagType::}\NormalTok{Mp4)}
\OperatorTok{.}\NormalTok{read\_from\_path(M4A\_FILE)}
\OperatorTok{.}\NormalTok{unwrap()}\OperatorTok{;}
\CommentTok{// the tag originated from an mp3 file is successfully written}
@ -232,12 +256,76 @@ The following example shows how you can read the tag in an \texttt{mp3} file, co
\CommentTok{// convert to id3 tag, which does not support multiple artists}
\NormalTok{ mp4tag}\OperatorTok{.}\NormalTok{set\_config(}\PreprocessorTok{Config::}\KeywordTok{default}\NormalTok{()}\OperatorTok{.}\NormalTok{sep\_artist(}\StringTok{"/"}\NormalTok{))}\OperatorTok{;}
\CommentTok{// separator is by default \textasciigrave{};\textasciigrave{} but we can customise it}
\KeywordTok{let}\NormalTok{ mp3tag }\OperatorTok{=}\NormalTok{ mp4tag}\OperatorTok{.}\NormalTok{into\_tag(}\PreprocessorTok{TagType::}\NormalTok{Id3v2)}\OperatorTok{;}
\KeywordTok{let}\NormalTok{ mp3tag }\OperatorTok{=}\NormalTok{ mp4tag}\OperatorTok{.}\NormalTok{to\_dyn\_tag(}\PreprocessorTok{TagType::}\NormalTok{Id3v2)}\OperatorTok{;}
\PreprocessorTok{assert\_eq!}\NormalTok{(mp3tag}\OperatorTok{.}\NormalTok{artist()}\OperatorTok{,} \ConstantTok{Some}\NormalTok{(}\StringTok{"artist1 of mp4/artist2 of mp4"}\NormalTok{))}\OperatorTok{;}
\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}
\hypertarget{converting-into-a-concrete-type-downcasting}{%
\section{Converting into a Concrete Type (Downcasting)}\label{converting-into-a-concrete-type-downcasting}}
\begin{quote}
Can I convert into a concrete type?
\end{quote}
Yes, you can directly convert \texttt{.into()} it (this is technically known as a ``downcast''):
\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{use} \PreprocessorTok{audiotags::}\OperatorTok{\{}\NormalTok{FlacTag}\OperatorTok{,}\NormalTok{ Tag}\OperatorTok{\};}
\KeywordTok{fn}\NormalTok{ main() }\OperatorTok{\{}
\KeywordTok{let}\NormalTok{ id3v2tag }\OperatorTok{=} \PreprocessorTok{Tag::}\KeywordTok{default}\NormalTok{()}\OperatorTok{.}\NormalTok{read\_from\_path(}\StringTok{"assets/a.mp3"}\NormalTok{)}\OperatorTok{.}\NormalTok{unwrap()}\OperatorTok{;}
\KeywordTok{let}\NormalTok{ \_flactag}\OperatorTok{:}\NormalTok{ FlacTag }\OperatorTok{=}\NormalTok{ id3v2tag}\OperatorTok{.}\NormalTok{into()}\OperatorTok{;}
\CommentTok{// of course, you can \textasciigrave{}let id3v2tag\_concrete: Id3v2Tag = id3v2tag.into();\textasciigrave{}}
\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}
You can even convert \texttt{.into()} the `backend' tag type:
\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{use} \PreprocessorTok{audiotags::}\NormalTok{Tag}\OperatorTok{;}
\KeywordTok{fn}\NormalTok{ main() }\OperatorTok{\{}
\KeywordTok{let}\NormalTok{ mp3tag }\OperatorTok{=} \PreprocessorTok{Tag::}\KeywordTok{default}\NormalTok{()}\OperatorTok{.}\NormalTok{read\_from\_path(}\StringTok{"assets/a.mp3"}\NormalTok{)}\OperatorTok{.}\NormalTok{unwrap()}\OperatorTok{;}
\KeywordTok{let}\NormalTok{ flactag}\OperatorTok{:} \PreprocessorTok{metaflac::}\NormalTok{Tag }\OperatorTok{=}\NormalTok{ mp3tag}\OperatorTok{.}\NormalTok{into()}\OperatorTok{;} \CommentTok{// into the \textquotesingle{}backend\textquotesingle{} tag}
\CommentTok{// then you can use methods specific to metaflac}
\KeywordTok{let}\NormalTok{ \_ }\OperatorTok{=}\NormalTok{ flactag}\OperatorTok{.}\NormalTok{get\_streaminfo()}\OperatorTok{;}
\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}
This is useful when you really need to use the methods not provided by \texttt{audiotags::traits::*}.
You can also downcast the concrete \texttt{audiotags::FlacTag} to \texttt{metaflac::Tag} and so no.
\hypertarget{upcasting}{%
\section{Upcasting}\label{upcasting}}
Since you're allowed to downcast, naturally you can also upcast:
\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{use} \PreprocessorTok{audiotags::}\OperatorTok{*;}
\KeywordTok{fn}\NormalTok{ main() }\OperatorTok{\{}
\KeywordTok{let} \KeywordTok{mut}\NormalTok{ innertag }\OperatorTok{=} \PreprocessorTok{metaflac::Tag::}\KeywordTok{default}\NormalTok{()}\OperatorTok{;}
\NormalTok{ innertag}
\OperatorTok{.}\NormalTok{vorbis\_comments\_mut()}
\OperatorTok{.}\NormalTok{set\_title(}\PreprocessorTok{vec!}\NormalTok{[}\StringTok{"title from metaflac::Tag"}\NormalTok{])}\OperatorTok{;}
\KeywordTok{let}\NormalTok{ tag}\OperatorTok{:}\NormalTok{ FlacTag }\OperatorTok{=}\NormalTok{ innertag}\OperatorTok{.}\NormalTok{into()}\OperatorTok{;}
\KeywordTok{let}\NormalTok{ \_id3tag }\OperatorTok{=}\NormalTok{ tag}\OperatorTok{.}\NormalTok{to\_dyn\_tag(}\PreprocessorTok{TagType::}\NormalTok{Id3v2)}\OperatorTok{;}
\CommentTok{// in this case the "title" metadata will be}
\CommentTok{// losslessly written into the id3tag.}
\CommentTok{// However, if you have FLAC{-}specific fields,}
\CommentTok{// they will be lost upon conversion}
\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}
\hypertarget{anytag}{%
\chapter{\texorpdfstring{\texttt{AnyTag}}{AnyTag}}\label{anytag}}
@ -258,55 +346,7 @@ The following example shows how you can create a ``generic'' \texttt{AnyTag} and
\end{Highlighting}
\end{Shaded}
\hypertarget{downcast}{%
\chapter{Downcast}\label{downcast}}
The following example shows how you can downcast a \texttt{Box\textless{}dyn\ AudioTag\textgreater{}} into its ``backend'' tag type. This allows you to set the uncommon metadata supported by the corresponding backend but not by \textbf{audiotags}.
\begin{Shaded}
\begin{Highlighting}[]
\KeywordTok{use} \PreprocessorTok{audiotags::}\OperatorTok{*;}
\KeywordTok{fn}\NormalTok{ main() }\OperatorTok{\{}
\KeywordTok{let} \KeywordTok{mut}\NormalTok{ innertag }\OperatorTok{=} \PreprocessorTok{metaflac::Tag::}\KeywordTok{default}\NormalTok{()}\OperatorTok{;}
\NormalTok{ innertag}
\OperatorTok{.}\NormalTok{vorbis\_comments\_mut()}
\OperatorTok{.}\NormalTok{set\_title(}\PreprocessorTok{vec!}\NormalTok{[}\StringTok{"title from metaflac::Tag"}\NormalTok{])}\OperatorTok{;}
\KeywordTok{let}\NormalTok{ tag}\OperatorTok{:}\NormalTok{ FlacTag }\OperatorTok{=}\NormalTok{ innertag}\OperatorTok{.}\NormalTok{into()}\OperatorTok{;}
\KeywordTok{let} \KeywordTok{mut}\NormalTok{ id3tag }\OperatorTok{=}\NormalTok{ tag}\OperatorTok{.}\NormalTok{into\_tag(}\PreprocessorTok{TagType::}\NormalTok{Id3v2)}\OperatorTok{;}
\NormalTok{ id3tag}
\OperatorTok{.}\NormalTok{write\_to\_path(}\StringTok{"assets/a.mp3"}\NormalTok{)}
\OperatorTok{.}\NormalTok{expect(}\StringTok{"Fail to write!"}\NormalTok{)}\OperatorTok{;}
\KeywordTok{let}\NormalTok{ id3tag\_reload }\OperatorTok{=} \PreprocessorTok{Tag::}\KeywordTok{default}\NormalTok{()}
\OperatorTok{.}\NormalTok{read\_from\_path(}\StringTok{"assets/a.mp3"}\NormalTok{)}
\OperatorTok{.}\NormalTok{expect(}\StringTok{"Fail to read!"}\NormalTok{)}\OperatorTok{;}
\PreprocessorTok{assert\_eq!}\NormalTok{(id3tag\_reload}\OperatorTok{.}\NormalTok{title()}\OperatorTok{,} \ConstantTok{Some}\NormalTok{(}\StringTok{"title from metaflac::Tag"}\NormalTok{))}\OperatorTok{;}
\KeywordTok{let} \KeywordTok{mut}\NormalTok{ id3tag\_inner}\OperatorTok{:} \PreprocessorTok{id3::}\NormalTok{Tag }\OperatorTok{=}\NormalTok{ id3tag\_reload}\OperatorTok{.}\NormalTok{try\_into()}\OperatorTok{.}\NormalTok{unwrap()}\OperatorTok{;}
\CommentTok{// this would fail if \textasciigrave{}id3tag\_reload\textasciigrave{} isn\textquotesingle{}t really a id3 tag.}
\KeywordTok{let}\NormalTok{ timestamp }\OperatorTok{=} \PreprocessorTok{id3::}\NormalTok{Timestamp }\OperatorTok{\{}
\NormalTok{ year}\OperatorTok{:} \DecValTok{2013}\OperatorTok{,}
\NormalTok{ month}\OperatorTok{:} \ConstantTok{Some}\NormalTok{(}\DecValTok{2u8}\NormalTok{)}\OperatorTok{,}
\NormalTok{ day}\OperatorTok{:} \ConstantTok{Some}\NormalTok{(}\DecValTok{5u8}\NormalTok{)}\OperatorTok{,}
\NormalTok{ hour}\OperatorTok{:} \ConstantTok{Some}\NormalTok{(}\DecValTok{6u8}\NormalTok{)}\OperatorTok{,}
\NormalTok{ minute}\OperatorTok{:} \ConstantTok{None}\OperatorTok{,}
\NormalTok{ second}\OperatorTok{:} \ConstantTok{None}\OperatorTok{,}
\OperatorTok{\};}
\NormalTok{ id3tag\_inner}\OperatorTok{.}\NormalTok{set\_date\_recorded(timestamp}\OperatorTok{.}\NormalTok{clone())}\OperatorTok{;}
\NormalTok{ id3tag\_inner}
\OperatorTok{.}\NormalTok{write\_to\_path(}\StringTok{"assets/a.mp3"}\OperatorTok{,} \PreprocessorTok{id3::Version::}\NormalTok{Id3v24)}
\OperatorTok{.}\NormalTok{expect(}\StringTok{"Fail to write!"}\NormalTok{)}\OperatorTok{;}
\KeywordTok{let}\NormalTok{ id3tag\_reload }\OperatorTok{=} \PreprocessorTok{id3::Tag::}\NormalTok{read\_from\_path(}\StringTok{"assets/a.mp3"}\NormalTok{)}
\OperatorTok{.}\NormalTok{expect(}\StringTok{"Fail to read!"}\NormalTok{)}\OperatorTok{;}
\PreprocessorTok{assert\_eq!}\NormalTok{(id3tag\_reload}\OperatorTok{.}\NormalTok{date\_recorded()}\OperatorTok{,} \ConstantTok{Some}\NormalTok{(timestamp))}\OperatorTok{;}
\OperatorTok{\}}
\end{Highlighting}
\end{Shaded}
\bibliography{book.bib,packages.bib}
\bibliography{book.bib}
\end{document}

View file

@ -0,0 +1,315 @@
<!DOCTYPE html>
<html lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>2 Conversion and Downcast | audiotags Manual</title>
<meta name="description" content="This is the manual of the Rust crate audiotags" />
<meta name="generator" content="bookdown 0.21 and GitBook 2.6.7" />
<meta property="og:title" content="2 Conversion and Downcast | audiotags Manual" />
<meta property="og:type" content="book" />
<meta property="og:description" content="This is the manual of the Rust crate audiotags" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="2 Conversion and Downcast | audiotags Manual" />
<meta name="twitter:description" content="This is the manual of the Rust crate audiotags" />
<meta name="author" content="Tianyi Shi" />
<meta name="date" content="2020-10-29" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<link rel="prev" href="start-simple.html"/>
<link rel="next" href="anytag.html"/>
<script src="libs/header-attrs-2.4/header-attrs.js"></script>
<script src="libs/jquery-2.2.3/jquery.min.js"></script>
<link href="libs/gitbook-2.6.7/css/style.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-table.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-bookdown.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-highlight.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-search.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-fontsettings.css" rel="stylesheet" />
<link href="libs/gitbook-2.6.7/css/plugin-clipboard.css" rel="stylesheet" />
<style type="text/css">
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="style.css" type="text/css" />
</head>
<body>
<div class="book without-animation with-summary font-size-2 font-family-1" data-basepath=".">
<div class="book-summary">
<nav role="navigation">
<ul class="summary">
<li><strong><a href="https://tianyishi2001.github.io/audiotags">audiotags Manual</a></strong></li>
<li class="divider"></li>
<li class="chapter" data-level="" data-path="index.html"><a href="index.html"><i class="fa fa-check"></i>Preface</a>
<ul>
<li class="chapter" data-level="" data-path="index.html"><a href="index.html#examples-in-this-manual"><i class="fa fa-check"></i>Examples in this manual</a></li>
</ul></li>
<li class="chapter" data-level="1" data-path="start-simple.html"><a href="start-simple.html"><i class="fa fa-check"></i><b>1</b> Start Simple</a></li>
<li class="chapter" data-level="2" data-path="conversion-and-downcast.html"><a href="conversion-and-downcast.html"><i class="fa fa-check"></i><b>2</b> Conversion and Downcast</a>
<ul>
<li class="chapter" data-level="2.1" data-path="conversion-and-downcast.html"><a href="conversion-and-downcast.html#converting-from-a-boxdyn-audiotag-to-another"><i class="fa fa-check"></i><b>2.1</b> Converting from a <code>Box&lt;dyn AudioTag</code> to Another</a></li>
<li class="chapter" data-level="2.2" data-path="conversion-and-downcast.html"><a href="conversion-and-downcast.html#converting-into-a-concrete-type-downcasting"><i class="fa fa-check"></i><b>2.2</b> Converting into a Concrete Type (Downcasting)</a></li>
<li class="chapter" data-level="2.3" data-path="conversion-and-downcast.html"><a href="conversion-and-downcast.html#upcasting"><i class="fa fa-check"></i><b>2.3</b> Upcasting</a></li>
</ul></li>
<li class="chapter" data-level="3" data-path="anytag.html"><a href="anytag.html"><i class="fa fa-check"></i><b>3</b> <code>AnyTag</code></a></li>
<li class="divider"></li>
<li><a href="https://github.com/rstudio/bookdown" target="blank">Published with bookdown</a></li>
</ul>
</nav>
</div>
<div class="book-body">
<div class="body-inner">
<div class="book-header" role="navigation">
<h1>
<i class="fa fa-circle-o-notch fa-spin"></i><a href="./">audiotags Manual</a>
</h1>
</div>
<div class="page-wrapper" tabindex="-1" role="main">
<div class="page-inner">
<section class="normal" id="section-">
<div id="conversion-and-downcast" class="section level1" number="2">
<h1><span class="header-section-number">2</span> Conversion and Downcast</h1>
<p>The following example shows how you can read the tag in an <code>mp3</code> file, convert it into an <code>mp4</code> tag, and write it to an <code>m4a</code> file.</p>
<div id="converting-from-a-boxdyn-audiotag-to-another" class="section level2" number="2.1">
<h2><span class="header-section-number">2.1</span> Converting from a <code>Box&lt;dyn AudioTag</code> to Another</h2>
<div class="sourceCode" id="cb3"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb3-1"><a href="conversion-and-downcast.html#cb3-1" aria-hidden="true"></a></span>
<span id="cb3-2"><a href="conversion-and-downcast.html#cb3-2" aria-hidden="true"></a><span class="kw">use</span> <span class="pp">audiotags::</span><span class="op">{</span>Config<span class="op">,</span> Tag<span class="op">,</span> TagType<span class="op">};</span></span>
<span id="cb3-3"><a href="conversion-and-downcast.html#cb3-3" aria-hidden="true"></a></span>
<span id="cb3-4"><a href="conversion-and-downcast.html#cb3-4" aria-hidden="true"></a><span class="kw">fn</span> main() <span class="op">{</span></span>
<span id="cb3-5"><a href="conversion-and-downcast.html#cb3-5" aria-hidden="true"></a> <span class="co">// we have an mp3 and an m4a file</span></span>
<span id="cb3-6"><a href="conversion-and-downcast.html#cb3-6" aria-hidden="true"></a> <span class="kw">const</span> MP3_FILE<span class="op">:</span> <span class="op">&amp;</span><span class="ot">&#39;static</span> <span class="dt">str</span> <span class="op">=</span> <span class="st">&quot;assets/a.mp3&quot;</span><span class="op">;</span></span>
<span id="cb3-7"><a href="conversion-and-downcast.html#cb3-7" aria-hidden="true"></a> <span class="kw">const</span> M4A_FILE<span class="op">:</span> <span class="op">&amp;</span><span class="ot">&#39;static</span> <span class="dt">str</span> <span class="op">=</span> <span class="st">&quot;assets/a.m4a&quot;</span><span class="op">;</span></span>
<span id="cb3-8"><a href="conversion-and-downcast.html#cb3-8" aria-hidden="true"></a> <span class="co">// read tag from the mp3 file. Using `default()` so that the</span></span>
<span id="cb3-9"><a href="conversion-and-downcast.html#cb3-9" aria-hidden="true"></a> <span class="co">// type of tag is guessed from the file extension</span></span>
<span id="cb3-10"><a href="conversion-and-downcast.html#cb3-10" aria-hidden="true"></a> <span class="kw">let</span> <span class="kw">mut</span> mp3tag <span class="op">=</span> <span class="pp">Tag::</span><span class="kw">default</span>()<span class="op">.</span>read_from_path(MP3_FILE)<span class="op">.</span>unwrap()<span class="op">;</span></span>
<span id="cb3-11"><a href="conversion-and-downcast.html#cb3-11" aria-hidden="true"></a> <span class="co">// set the title</span></span>
<span id="cb3-12"><a href="conversion-and-downcast.html#cb3-12" aria-hidden="true"></a> mp3tag<span class="op">.</span>set_title(<span class="st">&quot;title from mp3 file&quot;</span>)<span class="op">;</span></span>
<span id="cb3-13"><a href="conversion-and-downcast.html#cb3-13" aria-hidden="true"></a> <span class="co">// we can convert it to an mp4 tag and save it to an m4a file.</span></span>
<span id="cb3-14"><a href="conversion-and-downcast.html#cb3-14" aria-hidden="true"></a> <span class="kw">let</span> <span class="kw">mut</span> mp4tag <span class="op">=</span> mp3tag<span class="op">.</span>to_dyn_tag(<span class="pp">TagType::</span>Mp4)<span class="op">;</span></span>
<span id="cb3-15"><a href="conversion-and-downcast.html#cb3-15" aria-hidden="true"></a> mp4tag<span class="op">.</span>write_to_path(M4A_FILE)<span class="op">.</span>unwrap()<span class="op">;</span></span>
<span id="cb3-16"><a href="conversion-and-downcast.html#cb3-16" aria-hidden="true"></a></span>
<span id="cb3-17"><a href="conversion-and-downcast.html#cb3-17" aria-hidden="true"></a> <span class="co">// reload the tag from the m4a file; this time specifying the</span></span>
<span id="cb3-18"><a href="conversion-and-downcast.html#cb3-18" aria-hidden="true"></a> <span class="co">// tag type (you can also use `default()`)</span></span>
<span id="cb3-19"><a href="conversion-and-downcast.html#cb3-19" aria-hidden="true"></a> <span class="kw">let</span> <span class="kw">mut</span> mp4tag <span class="op">=</span> <span class="pp">Tag::</span>new()</span>
<span id="cb3-20"><a href="conversion-and-downcast.html#cb3-20" aria-hidden="true"></a> <span class="op">.</span>with_tag_type(<span class="pp">TagType::</span>Mp4)</span>
<span id="cb3-21"><a href="conversion-and-downcast.html#cb3-21" aria-hidden="true"></a> <span class="op">.</span>read_from_path(M4A_FILE)</span>
<span id="cb3-22"><a href="conversion-and-downcast.html#cb3-22" aria-hidden="true"></a> <span class="op">.</span>unwrap()<span class="op">;</span></span>
<span id="cb3-23"><a href="conversion-and-downcast.html#cb3-23" aria-hidden="true"></a> <span class="co">// the tag originated from an mp3 file is successfully written</span></span>
<span id="cb3-24"><a href="conversion-and-downcast.html#cb3-24" aria-hidden="true"></a> <span class="co">// to an m4a file!</span></span>
<span id="cb3-25"><a href="conversion-and-downcast.html#cb3-25" aria-hidden="true"></a> <span class="pp">assert_eq!</span>(mp4tag<span class="op">.</span>title()<span class="op">,</span> <span class="cn">Some</span>(<span class="st">&quot;title from mp3 file&quot;</span>))<span class="op">;</span></span>
<span id="cb3-26"><a href="conversion-and-downcast.html#cb3-26" aria-hidden="true"></a> <span class="co">// multiple artists</span></span>
<span id="cb3-27"><a href="conversion-and-downcast.html#cb3-27" aria-hidden="true"></a> mp4tag<span class="op">.</span>add_artist(<span class="st">&quot;artist1 of mp4&quot;</span>)<span class="op">;</span></span>
<span id="cb3-28"><a href="conversion-and-downcast.html#cb3-28" aria-hidden="true"></a> mp4tag<span class="op">.</span>add_artist(<span class="st">&quot;artist2 of mp4&quot;</span>)<span class="op">;</span></span>
<span id="cb3-29"><a href="conversion-and-downcast.html#cb3-29" aria-hidden="true"></a> <span class="pp">assert_eq!</span>(</span>
<span id="cb3-30"><a href="conversion-and-downcast.html#cb3-30" aria-hidden="true"></a> mp4tag<span class="op">.</span>artists()<span class="op">,</span></span>
<span id="cb3-31"><a href="conversion-and-downcast.html#cb3-31" aria-hidden="true"></a> <span class="cn">Some</span>(<span class="pp">vec!</span>[<span class="st">&quot;artist1 of mp4&quot;</span><span class="op">,</span> <span class="st">&quot;artist2 of mp4&quot;</span>])</span>
<span id="cb3-32"><a href="conversion-and-downcast.html#cb3-32" aria-hidden="true"></a> )<span class="op">;</span></span>
<span id="cb3-33"><a href="conversion-and-downcast.html#cb3-33" aria-hidden="true"></a> <span class="co">// convert to id3 tag, which does not support multiple artists</span></span>
<span id="cb3-34"><a href="conversion-and-downcast.html#cb3-34" aria-hidden="true"></a> mp4tag<span class="op">.</span>set_config(<span class="pp">Config::</span><span class="kw">default</span>()<span class="op">.</span>sep_artist(<span class="st">&quot;/&quot;</span>))<span class="op">;</span></span>
<span id="cb3-35"><a href="conversion-and-downcast.html#cb3-35" aria-hidden="true"></a> <span class="co">// separator is by default `;` but we can customise it</span></span>
<span id="cb3-36"><a href="conversion-and-downcast.html#cb3-36" aria-hidden="true"></a> <span class="kw">let</span> mp3tag <span class="op">=</span> mp4tag<span class="op">.</span>to_dyn_tag(<span class="pp">TagType::</span>Id3v2)<span class="op">;</span></span>
<span id="cb3-37"><a href="conversion-and-downcast.html#cb3-37" aria-hidden="true"></a> <span class="pp">assert_eq!</span>(mp3tag<span class="op">.</span>artist()<span class="op">,</span> <span class="cn">Some</span>(<span class="st">&quot;artist1 of mp4/artist2 of mp4&quot;</span>))<span class="op">;</span></span>
<span id="cb3-38"><a href="conversion-and-downcast.html#cb3-38" aria-hidden="true"></a><span class="op">}</span></span></code></pre></div>
</div>
<div id="converting-into-a-concrete-type-downcasting" class="section level2" number="2.2">
<h2><span class="header-section-number">2.2</span> Converting into a Concrete Type (Downcasting)</h2>
<blockquote>
<p>Can I convert into a concrete type?</p>
</blockquote>
<p>Yes, you can directly convert <code>.into()</code> it (this is technically known as a “downcast”):</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb4-1"><a href="conversion-and-downcast.html#cb4-1" aria-hidden="true"></a><span class="kw">use</span> <span class="pp">audiotags::</span><span class="op">{</span>FlacTag<span class="op">,</span> Tag<span class="op">};</span></span>
<span id="cb4-2"><a href="conversion-and-downcast.html#cb4-2" aria-hidden="true"></a></span>
<span id="cb4-3"><a href="conversion-and-downcast.html#cb4-3" aria-hidden="true"></a><span class="kw">fn</span> main() <span class="op">{</span></span>
<span id="cb4-4"><a href="conversion-and-downcast.html#cb4-4" aria-hidden="true"></a> <span class="kw">let</span> id3v2tag <span class="op">=</span> <span class="pp">Tag::</span><span class="kw">default</span>()<span class="op">.</span>read_from_path(<span class="st">&quot;assets/a.mp3&quot;</span>)<span class="op">.</span>unwrap()<span class="op">;</span></span>
<span id="cb4-5"><a href="conversion-and-downcast.html#cb4-5" aria-hidden="true"></a> <span class="kw">let</span> _flactag<span class="op">:</span> FlacTag <span class="op">=</span> id3v2tag<span class="op">.</span>into()<span class="op">;</span></span>
<span id="cb4-6"><a href="conversion-and-downcast.html#cb4-6" aria-hidden="true"></a> <span class="co">// of course, you can `let id3v2tag_concrete: Id3v2Tag = id3v2tag.into();`</span></span>
<span id="cb4-7"><a href="conversion-and-downcast.html#cb4-7" aria-hidden="true"></a><span class="op">}</span></span></code></pre></div>
<p>You can even convert <code>.into()</code> the backend tag type:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb5-1"><a href="conversion-and-downcast.html#cb5-1" aria-hidden="true"></a><span class="kw">use</span> <span class="pp">audiotags::</span>Tag<span class="op">;</span></span>
<span id="cb5-2"><a href="conversion-and-downcast.html#cb5-2" aria-hidden="true"></a></span>
<span id="cb5-3"><a href="conversion-and-downcast.html#cb5-3" aria-hidden="true"></a><span class="kw">fn</span> main() <span class="op">{</span></span>
<span id="cb5-4"><a href="conversion-and-downcast.html#cb5-4" aria-hidden="true"></a> <span class="kw">let</span> mp3tag <span class="op">=</span> <span class="pp">Tag::</span><span class="kw">default</span>()<span class="op">.</span>read_from_path(<span class="st">&quot;assets/a.mp3&quot;</span>)<span class="op">.</span>unwrap()<span class="op">;</span></span>
<span id="cb5-5"><a href="conversion-and-downcast.html#cb5-5" aria-hidden="true"></a> <span class="kw">let</span> flactag<span class="op">:</span> <span class="pp">metaflac::</span>Tag <span class="op">=</span> mp3tag<span class="op">.</span>into()<span class="op">;</span> <span class="co">// into the &#39;backend&#39; tag</span></span>
<span id="cb5-6"><a href="conversion-and-downcast.html#cb5-6" aria-hidden="true"></a> <span class="co">// then you can use methods specific to metaflac</span></span>
<span id="cb5-7"><a href="conversion-and-downcast.html#cb5-7" aria-hidden="true"></a> <span class="kw">let</span> _ <span class="op">=</span> flactag<span class="op">.</span>get_streaminfo()<span class="op">;</span></span>
<span id="cb5-8"><a href="conversion-and-downcast.html#cb5-8" aria-hidden="true"></a><span class="op">}</span></span></code></pre></div>
<p>This is useful when you really need to use the methods not provided by <code>audiotags::traits::*</code>.</p>
<p>You can also downcast the concrete <code>audiotags::FlacTag</code> to <code>metaflac::Tag</code> and so no.</p>
</div>
<div id="upcasting" class="section level2" number="2.3">
<h2><span class="header-section-number">2.3</span> Upcasting</h2>
<p>Since youre allowed to downcast, naturally you can also upcast:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb6-1"><a href="conversion-and-downcast.html#cb6-1" aria-hidden="true"></a><span class="kw">use</span> <span class="pp">audiotags::</span><span class="op">*;</span></span>
<span id="cb6-2"><a href="conversion-and-downcast.html#cb6-2" aria-hidden="true"></a></span>
<span id="cb6-3"><a href="conversion-and-downcast.html#cb6-3" aria-hidden="true"></a><span class="kw">fn</span> main() <span class="op">{</span></span>
<span id="cb6-4"><a href="conversion-and-downcast.html#cb6-4" aria-hidden="true"></a> <span class="kw">let</span> <span class="kw">mut</span> innertag <span class="op">=</span> <span class="pp">metaflac::Tag::</span><span class="kw">default</span>()<span class="op">;</span></span>
<span id="cb6-5"><a href="conversion-and-downcast.html#cb6-5" aria-hidden="true"></a> innertag</span>
<span id="cb6-6"><a href="conversion-and-downcast.html#cb6-6" aria-hidden="true"></a> <span class="op">.</span>vorbis_comments_mut()</span>
<span id="cb6-7"><a href="conversion-and-downcast.html#cb6-7" aria-hidden="true"></a> <span class="op">.</span>set_title(<span class="pp">vec!</span>[<span class="st">&quot;title from metaflac::Tag&quot;</span>])<span class="op">;</span></span>
<span id="cb6-8"><a href="conversion-and-downcast.html#cb6-8" aria-hidden="true"></a> <span class="kw">let</span> tag<span class="op">:</span> FlacTag <span class="op">=</span> innertag<span class="op">.</span>into()<span class="op">;</span></span>
<span id="cb6-9"><a href="conversion-and-downcast.html#cb6-9" aria-hidden="true"></a> <span class="kw">let</span> _id3tag <span class="op">=</span> tag<span class="op">.</span>to_dyn_tag(<span class="pp">TagType::</span>Id3v2)<span class="op">;</span></span>
<span id="cb6-10"><a href="conversion-and-downcast.html#cb6-10" aria-hidden="true"></a> <span class="co">// in this case the &quot;title&quot; metadata will be</span></span>
<span id="cb6-11"><a href="conversion-and-downcast.html#cb6-11" aria-hidden="true"></a> <span class="co">// losslessly written into the id3tag.</span></span>
<span id="cb6-12"><a href="conversion-and-downcast.html#cb6-12" aria-hidden="true"></a> <span class="co">// However, if you have FLAC-specific fields,</span></span>
<span id="cb6-13"><a href="conversion-and-downcast.html#cb6-13" aria-hidden="true"></a> <span class="co">// they will be lost upon conversion</span></span>
<span id="cb6-14"><a href="conversion-and-downcast.html#cb6-14" aria-hidden="true"></a><span class="op">}</span></span></code></pre></div>
</div>
</div>
</section>
</div>
</div>
</div>
<a href="start-simple.html" class="navigation navigation-prev " aria-label="Previous page"><i class="fa fa-angle-left"></i></a>
<a href="anytag.html" class="navigation navigation-next " aria-label="Next page"><i class="fa fa-angle-right"></i></a>
</div>
</div>
<script src="libs/gitbook-2.6.7/js/app.min.js"></script>
<script src="libs/gitbook-2.6.7/js/lunr.js"></script>
<script src="libs/gitbook-2.6.7/js/clipboard.min.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-search.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-sharing.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-fontsettings.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-bookdown.js"></script>
<script src="libs/gitbook-2.6.7/js/jquery.highlight.js"></script>
<script src="libs/gitbook-2.6.7/js/plugin-clipboard.js"></script>
<script>
gitbook.require(["gitbook"], function(gitbook) {
gitbook.start({
"sharing": {
"github": false,
"facebook": true,
"twitter": true,
"linkedin": false,
"weibo": false,
"instapaper": false,
"vk": false,
"all": ["facebook", "twitter", "linkedin", "weibo", "instapaper"]
},
"fontsettings": {
"theme": "white",
"family": "sans",
"size": 2
},
"edit": {
"link": null,
"text": null
},
"history": {
"link": null,
"text": null
},
"view": {
"link": null,
"text": null
},
"download": ["audiotags.pdf", "audiotags.epub"],
"toc": {
"collapse": "subsection"
}
});
});
</script>
</body>
</html>

View file

@ -177,7 +177,7 @@ code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warni
<span id="cb2-10"><a href="conversion.html#cb2-10" aria-hidden="true"></a> <span class="co">// set the title</span></span>
<span id="cb2-11"><a href="conversion.html#cb2-11" aria-hidden="true"></a> mp3tag<span class="op">.</span>set_title(<span class="st">&quot;title from mp3 file&quot;</span>)<span class="op">;</span></span>
<span id="cb2-12"><a href="conversion.html#cb2-12" aria-hidden="true"></a> <span class="co">// we can convert it to an mp4 tag and save it to an m4a file.</span></span>
<span id="cb2-13"><a href="conversion.html#cb2-13" aria-hidden="true"></a> <span class="kw">let</span> <span class="kw">mut</span> mp4tag <span class="op">=</span> mp3tag<span class="op">.</span>into_tag(<span class="pp">TagType::</span>Mp4)<span class="op">;</span></span>
<span id="cb2-13"><a href="conversion.html#cb2-13" aria-hidden="true"></a> <span class="kw">let</span> <span class="kw">mut</span> mp4tag <span class="op">=</span> mp3tag<span class="op">.</span>to_dyn_tag(<span class="pp">TagType::</span>Mp4)<span class="op">;</span></span>
<span id="cb2-14"><a href="conversion.html#cb2-14" aria-hidden="true"></a> mp4tag<span class="op">.</span>write_to_path(M4A_FILE)<span class="op">.</span>unwrap()<span class="op">;</span></span>
<span id="cb2-15"><a href="conversion.html#cb2-15" aria-hidden="true"></a></span>
<span id="cb2-16"><a href="conversion.html#cb2-16" aria-hidden="true"></a> <span class="co">// reload the tag from the m4a file; this time specifying the</span></span>
@ -198,7 +198,7 @@ code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warni
<span id="cb2-31"><a href="conversion.html#cb2-31" aria-hidden="true"></a> <span class="co">// convert to id3 tag, which does not support multiple artists</span></span>
<span id="cb2-32"><a href="conversion.html#cb2-32" aria-hidden="true"></a> mp4tag<span class="op">.</span>set_config(<span class="pp">Config::</span><span class="kw">default</span>()<span class="op">.</span>sep_artist(<span class="st">&quot;/&quot;</span>))<span class="op">;</span></span>
<span id="cb2-33"><a href="conversion.html#cb2-33" aria-hidden="true"></a> <span class="co">// separator is by default `;` but we can customise it</span></span>
<span id="cb2-34"><a href="conversion.html#cb2-34" aria-hidden="true"></a> <span class="kw">let</span> mp3tag <span class="op">=</span> mp4tag<span class="op">.</span>into_tag(<span class="pp">TagType::</span>Id3v2)<span class="op">;</span></span>
<span id="cb2-34"><a href="conversion.html#cb2-34" aria-hidden="true"></a> <span class="kw">let</span> mp3tag <span class="op">=</span> mp4tag<span class="op">.</span>to_dyn_tag(<span class="pp">TagType::</span>Id3v2)<span class="op">;</span></span>
<span id="cb2-35"><a href="conversion.html#cb2-35" aria-hidden="true"></a> <span class="pp">assert_eq!</span>(mp3tag<span class="op">.</span>artist()<span class="op">,</span> <span class="cn">Some</span>(<span class="st">&quot;artist1 of mp4/artist2 of mp4&quot;</span>))<span class="op">;</span></span>
<span id="cb2-36"><a href="conversion.html#cb2-36" aria-hidden="true"></a><span class="op">}</span></span></code></pre></div>

View file

@ -173,7 +173,7 @@ code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warni
<span id="cb4-6"><a href="downcast.html#cb4-6" aria-hidden="true"></a> <span class="op">.</span>vorbis_comments_mut()</span>
<span id="cb4-7"><a href="downcast.html#cb4-7" aria-hidden="true"></a> <span class="op">.</span>set_title(<span class="pp">vec!</span>[<span class="st">&quot;title from metaflac::Tag&quot;</span>])<span class="op">;</span></span>
<span id="cb4-8"><a href="downcast.html#cb4-8" aria-hidden="true"></a> <span class="kw">let</span> tag<span class="op">:</span> FlacTag <span class="op">=</span> innertag<span class="op">.</span>into()<span class="op">;</span></span>
<span id="cb4-9"><a href="downcast.html#cb4-9" aria-hidden="true"></a> <span class="kw">let</span> <span class="kw">mut</span> id3tag <span class="op">=</span> tag<span class="op">.</span>into_tag(<span class="pp">TagType::</span>Id3v2)<span class="op">;</span></span>
<span id="cb4-9"><a href="downcast.html#cb4-9" aria-hidden="true"></a> <span class="kw">let</span> <span class="kw">mut</span> id3tag <span class="op">=</span> tag<span class="op">.</span>to_dyn_tag(<span class="pp">TagType::</span>Id3v2)<span class="op">;</span></span>
<span id="cb4-10"><a href="downcast.html#cb4-10" aria-hidden="true"></a> id3tag</span>
<span id="cb4-11"><a href="downcast.html#cb4-11" aria-hidden="true"></a> <span class="op">.</span>write_to_path(<span class="st">&quot;assets/a.mp3&quot;</span>)</span>
<span id="cb4-12"><a href="downcast.html#cb4-12" aria-hidden="true"></a> <span class="op">.</span>expect(<span class="st">&quot;Fail to write!&quot;</span>)<span class="op">;</span></span>

View file

@ -24,7 +24,7 @@
<meta name="author" content="Tianyi Shi" />
<meta name="date" content="2020-10-27" />
<meta name="date" content="2020-10-29" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="apple-mobile-web-app-capable" content="yes" />
@ -138,10 +138,13 @@ code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warni
<li class="chapter" data-level="" data-path="index.html"><a href="index.html#examples-in-this-manual"><i class="fa fa-check"></i>Examples in this manual</a></li>
</ul></li>
<li class="chapter" data-level="1" data-path="start-simple.html"><a href="start-simple.html"><i class="fa fa-check"></i><b>1</b> Start Simple</a></li>
<li class="chapter" data-level="2" data-path="conversion.html"><a href="conversion.html"><i class="fa fa-check"></i><b>2</b> Conversion</a></li>
<li class="chapter" data-level="2" data-path="conversion-and-downcast.html"><a href="conversion-and-downcast.html"><i class="fa fa-check"></i><b>2</b> Conversion and Downcast</a>
<ul>
<li class="chapter" data-level="2.1" data-path="conversion-and-downcast.html"><a href="conversion-and-downcast.html#converting-from-a-boxdyn-audiotag-to-another"><i class="fa fa-check"></i><b>2.1</b> Converting from a <code>Box&lt;dyn AudioTag</code> to Another</a></li>
<li class="chapter" data-level="2.2" data-path="conversion-and-downcast.html"><a href="conversion-and-downcast.html#converting-into-a-concrete-type-downcasting"><i class="fa fa-check"></i><b>2.2</b> Converting into a Concrete Type (Downcasting)</a></li>
<li class="chapter" data-level="2.3" data-path="conversion-and-downcast.html"><a href="conversion-and-downcast.html#upcasting"><i class="fa fa-check"></i><b>2.3</b> Upcasting</a></li>
</ul></li>
<li class="chapter" data-level="3" data-path="anytag.html"><a href="anytag.html"><i class="fa fa-check"></i><b>3</b> <code>AnyTag</code></a></li>
<li class="chapter" data-level="4" data-path="downcast.html"><a href="downcast.html"><i class="fa fa-check"></i><b>4</b> Downcast</a></li>
<li class="chapter" data-level="" data-path="references.html"><a href="references.html"><i class="fa fa-check"></i>References</a></li>
<li class="divider"></li>
<li><a href="https://github.com/rstudio/bookdown" target="blank">Published with bookdown</a></li>
@ -165,7 +168,7 @@ code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warni
<div id="header">
<h1 class="title">audiotags Manual</h1>
<p class="author"><em>Tianyi Shi</em></p>
<p class="date"><em>2020-10-27</em></p>
<p class="date"><em>2020-10-29</em></p>
</div>
<div id="preface" class="section level1 unnumbered">
<h1>Preface</h1>

View file

@ -1,4 +1,6 @@
start-simple
conversion
conversion-and-downcast
converting-from-a-boxdyn-audiotag-to-another
converting-into-a-concrete-type-downcasting
upcasting
anytag
downcast

File diff suppressed because one or more lines are too long

View file

@ -4,11 +4,11 @@
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Chapter 1 Start Simple | audiotags Manual</title>
<title>1 Start Simple | audiotags Manual</title>
<meta name="description" content="This is the manual of the Rust crate audiotags" />
<meta name="generator" content="bookdown 0.21 and GitBook 2.6.7" />
<meta property="og:title" content="Chapter 1 Start Simple | audiotags Manual" />
<meta property="og:title" content="1 Start Simple | audiotags Manual" />
<meta property="og:type" content="book" />
@ -16,7 +16,7 @@
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Chapter 1 Start Simple | audiotags Manual" />
<meta name="twitter:title" content="1 Start Simple | audiotags Manual" />
<meta name="twitter:description" content="This is the manual of the Rust crate audiotags" />
@ -24,7 +24,7 @@
<meta name="author" content="Tianyi Shi" />
<meta name="date" content="2020-10-27" />
<meta name="date" content="2020-10-29" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="apple-mobile-web-app-capable" content="yes" />
@ -32,7 +32,7 @@
<link rel="prev" href="index.html"/>
<link rel="next" href="conversion.html"/>
<link rel="next" href="conversion-and-downcast.html"/>
<script src="libs/header-attrs-2.4/header-attrs.js"></script>
<script src="libs/jquery-2.2.3/jquery.min.js"></script>
<link href="libs/gitbook-2.6.7/css/style.css" rel="stylesheet" />
@ -138,10 +138,13 @@ code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warni
<li class="chapter" data-level="" data-path="index.html"><a href="index.html#examples-in-this-manual"><i class="fa fa-check"></i>Examples in this manual</a></li>
</ul></li>
<li class="chapter" data-level="1" data-path="start-simple.html"><a href="start-simple.html"><i class="fa fa-check"></i><b>1</b> Start Simple</a></li>
<li class="chapter" data-level="2" data-path="conversion.html"><a href="conversion.html"><i class="fa fa-check"></i><b>2</b> Conversion</a></li>
<li class="chapter" data-level="2" data-path="conversion-and-downcast.html"><a href="conversion-and-downcast.html"><i class="fa fa-check"></i><b>2</b> Conversion and Downcast</a>
<ul>
<li class="chapter" data-level="2.1" data-path="conversion-and-downcast.html"><a href="conversion-and-downcast.html#converting-from-a-boxdyn-audiotag-to-another"><i class="fa fa-check"></i><b>2.1</b> Converting from a <code>Box&lt;dyn AudioTag</code> to Another</a></li>
<li class="chapter" data-level="2.2" data-path="conversion-and-downcast.html"><a href="conversion-and-downcast.html#converting-into-a-concrete-type-downcasting"><i class="fa fa-check"></i><b>2.2</b> Converting into a Concrete Type (Downcasting)</a></li>
<li class="chapter" data-level="2.3" data-path="conversion-and-downcast.html"><a href="conversion-and-downcast.html#upcasting"><i class="fa fa-check"></i><b>2.3</b> Upcasting</a></li>
</ul></li>
<li class="chapter" data-level="3" data-path="anytag.html"><a href="anytag.html"><i class="fa fa-check"></i><b>3</b> <code>AnyTag</code></a></li>
<li class="chapter" data-level="4" data-path="downcast.html"><a href="downcast.html"><i class="fa fa-check"></i><b>4</b> Downcast</a></li>
<li class="chapter" data-level="" data-path="references.html"><a href="references.html"><i class="fa fa-check"></i>References</a></li>
<li class="divider"></li>
<li><a href="https://github.com/rstudio/bookdown" target="blank">Published with bookdown</a></li>
@ -163,42 +166,55 @@ code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warni
<section class="normal" id="section-">
<div id="start-simple" class="section level1" number="1">
<h1><span class="header-section-number">Chapter 1</span> Start Simple</h1>
<h1><span class="header-section-number">1</span> Start Simple</h1>
<p>The following example shows how you can read an audio file, parse, set, and save its metadata:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="start-simple.html#cb1-1" aria-hidden="true"></a><span class="kw">use</span> <span class="pp">audiotags::</span><span class="op">{</span>MimeType<span class="op">,</span> Picture<span class="op">,</span> Tag<span class="op">,</span> TagType<span class="op">};</span></span>
<span id="cb1-2"><a href="start-simple.html#cb1-2" aria-hidden="true"></a></span>
<span id="cb1-3"><a href="start-simple.html#cb1-3" aria-hidden="true"></a><span class="kw">const</span> MP3_FILE<span class="op">:</span> <span class="op">&amp;</span><span class="ot">&#39;static</span> <span class="dt">str</span> <span class="op">=</span> <span class="st">&quot;assets/a.mp3&quot;</span><span class="op">;</span></span>
<span id="cb1-4"><a href="start-simple.html#cb1-4" aria-hidden="true"></a></span>
<span id="cb1-5"><a href="start-simple.html#cb1-5" aria-hidden="true"></a><span class="kw">fn</span> main() <span class="op">{</span></span>
<span id="cb1-6"><a href="start-simple.html#cb1-6" aria-hidden="true"></a> <span class="co">// using `default()` so that the metadata format is guessed</span></span>
<span id="cb1-7"><a href="start-simple.html#cb1-7" aria-hidden="true"></a> <span class="co">// (from the file extension) (in this case, Id3v2 tag is read)</span></span>
<span id="cb1-8"><a href="start-simple.html#cb1-8" aria-hidden="true"></a> <span class="kw">let</span> <span class="kw">mut</span> tag <span class="op">=</span> <span class="pp">Tag::</span><span class="kw">default</span>()<span class="op">.</span>read_from_path(MP3_FILE)<span class="op">.</span>unwrap()<span class="op">;</span></span>
<span id="cb1-9"><a href="start-simple.html#cb1-9" aria-hidden="true"></a> <span class="co">// You can also specify the metadata format (tag type):</span></span>
<span id="cb1-10"><a href="start-simple.html#cb1-10" aria-hidden="true"></a> <span class="kw">let</span> _tag <span class="op">=</span> <span class="pp">Tag::</span>with_tag_type(<span class="pp">TagType::</span>Id3v2)</span>
<span id="cb1-11"><a href="start-simple.html#cb1-11" aria-hidden="true"></a> <span class="op">.</span>read_from_path(MP3_FILE)</span>
<span id="cb1-12"><a href="start-simple.html#cb1-12" aria-hidden="true"></a> <span class="op">.</span>expect(<span class="st">&quot;Fail to read!&quot;</span>)<span class="op">;</span></span>
<span id="cb1-13"><a href="start-simple.html#cb1-13" aria-hidden="true"></a></span>
<span id="cb1-14"><a href="start-simple.html#cb1-14" aria-hidden="true"></a> tag<span class="op">.</span>set_title(<span class="st">&quot;foo title&quot;</span>)<span class="op">;</span></span>
<span id="cb1-15"><a href="start-simple.html#cb1-15" aria-hidden="true"></a> <span class="pp">assert_eq!</span>(tag<span class="op">.</span>title()<span class="op">,</span> <span class="cn">Some</span>(<span class="st">&quot;foo title&quot;</span>))<span class="op">;</span></span>
<span id="cb1-16"><a href="start-simple.html#cb1-16" aria-hidden="true"></a> tag<span class="op">.</span>remove_title()<span class="op">;</span></span>
<span id="cb1-17"><a href="start-simple.html#cb1-17" aria-hidden="true"></a> <span class="pp">assert!</span>(tag<span class="op">.</span>title()<span class="op">.</span>is_none())<span class="op">;</span></span>
<span id="cb1-18"><a href="start-simple.html#cb1-18" aria-hidden="true"></a> tag<span class="op">.</span>remove_title()<span class="op">;</span></span>
<span id="cb1-19"><a href="start-simple.html#cb1-19" aria-hidden="true"></a> <span class="co">// trying to remove a field that&#39;s already empty won&#39;t hurt</span></span>
<span id="cb1-20"><a href="start-simple.html#cb1-20" aria-hidden="true"></a></span>
<span id="cb1-21"><a href="start-simple.html#cb1-21" aria-hidden="true"></a> <span class="kw">let</span> cover <span class="op">=</span> Picture <span class="op">{</span></span>
<span id="cb1-22"><a href="start-simple.html#cb1-22" aria-hidden="true"></a> mime_type<span class="op">:</span> <span class="pp">MimeType::</span>Jpeg<span class="op">,</span></span>
<span id="cb1-23"><a href="start-simple.html#cb1-23" aria-hidden="true"></a> data<span class="op">:</span> <span class="op">&amp;</span><span class="pp">vec!</span>[<span class="dv">0u8</span><span class="op">;</span> <span class="dv">10</span>]<span class="op">,</span></span>
<span id="cb1-24"><a href="start-simple.html#cb1-24" aria-hidden="true"></a> <span class="op">};</span></span>
<span id="cb1-25"><a href="start-simple.html#cb1-25" aria-hidden="true"></a></span>
<span id="cb1-26"><a href="start-simple.html#cb1-26" aria-hidden="true"></a> tag<span class="op">.</span>set_album_cover(cover<span class="op">.</span>clone())<span class="op">;</span></span>
<span id="cb1-27"><a href="start-simple.html#cb1-27" aria-hidden="true"></a> <span class="pp">assert_eq!</span>(tag<span class="op">.</span>album_cover()<span class="op">,</span> <span class="cn">Some</span>(cover))<span class="op">;</span></span>
<span id="cb1-28"><a href="start-simple.html#cb1-28" aria-hidden="true"></a> tag<span class="op">.</span>remove_album_cover()<span class="op">;</span></span>
<span id="cb1-29"><a href="start-simple.html#cb1-29" aria-hidden="true"></a> <span class="pp">assert!</span>(tag<span class="op">.</span>album_cover()<span class="op">.</span>is_none())<span class="op">;</span></span>
<span id="cb1-30"><a href="start-simple.html#cb1-30" aria-hidden="true"></a> tag<span class="op">.</span>remove_album_cover()<span class="op">;</span></span>
<span id="cb1-31"><a href="start-simple.html#cb1-31" aria-hidden="true"></a></span>
<span id="cb1-32"><a href="start-simple.html#cb1-32" aria-hidden="true"></a> tag<span class="op">.</span>save_to_path(MP3_FILE)<span class="op">.</span>expect(<span class="st">&quot;Fail to save&quot;</span>)<span class="op">;</span></span>
<span id="cb1-33"><a href="start-simple.html#cb1-33" aria-hidden="true"></a> <span class="co">// </span><span class="al">TASK</span><span class="co">: reload the file and prove the data have been saved</span></span>
<span id="cb1-34"><a href="start-simple.html#cb1-34" aria-hidden="true"></a><span class="op">}</span></span></code></pre></div>
<div class="sourceCode" id="cb1"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="start-simple.html#cb1-1" aria-hidden="true"></a><span class="kw">fn</span> main() <span class="op">{</span></span>
<span id="cb1-2"><a href="start-simple.html#cb1-2" aria-hidden="true"></a> <span class="co">// using `default()` or `new()` alone so that the metadata format is</span></span>
<span id="cb1-3"><a href="start-simple.html#cb1-3" aria-hidden="true"></a> <span class="co">// guessed (from the file extension) (in this case, Id3v2 tag is read)</span></span>
<span id="cb1-4"><a href="start-simple.html#cb1-4" aria-hidden="true"></a> <span class="kw">let</span> <span class="kw">mut</span> tag <span class="op">=</span> <span class="pp">Tag::</span>new()<span class="op">.</span>read_from_path(MP3_FILE)<span class="op">.</span>unwrap()<span class="op">;</span></span>
<span id="cb1-5"><a href="start-simple.html#cb1-5" aria-hidden="true"></a> <span class="co">// You can also specify the metadata format (tag type):</span></span>
<span id="cb1-6"><a href="start-simple.html#cb1-6" aria-hidden="true"></a> <span class="kw">let</span> _tag <span class="op">=</span> <span class="pp">Tag::</span>new()</span>
<span id="cb1-7"><a href="start-simple.html#cb1-7" aria-hidden="true"></a> <span class="op">.</span>with_tag_type(<span class="pp">TagType::</span>Id3v2)</span>
<span id="cb1-8"><a href="start-simple.html#cb1-8" aria-hidden="true"></a> <span class="op">.</span>read_from_path(MP3_FILE)</span>
<span id="cb1-9"><a href="start-simple.html#cb1-9" aria-hidden="true"></a> <span class="op">.</span>expect(<span class="st">&quot;Fail to read!&quot;</span>)<span class="op">;</span></span>
<span id="cb1-10"><a href="start-simple.html#cb1-10" aria-hidden="true"></a></span>
<span id="cb1-11"><a href="start-simple.html#cb1-11" aria-hidden="true"></a> tag<span class="op">.</span>set_title(<span class="st">&quot;foo title&quot;</span>)<span class="op">;</span></span>
<span id="cb1-12"><a href="start-simple.html#cb1-12" aria-hidden="true"></a> <span class="pp">assert_eq!</span>(tag<span class="op">.</span>title()<span class="op">,</span> <span class="cn">Some</span>(<span class="st">&quot;foo title&quot;</span>))<span class="op">;</span></span>
<span id="cb1-13"><a href="start-simple.html#cb1-13" aria-hidden="true"></a> tag<span class="op">.</span>remove_title()<span class="op">;</span></span>
<span id="cb1-14"><a href="start-simple.html#cb1-14" aria-hidden="true"></a> <span class="pp">assert!</span>(tag<span class="op">.</span>title()<span class="op">.</span>is_none())<span class="op">;</span></span>
<span id="cb1-15"><a href="start-simple.html#cb1-15" aria-hidden="true"></a> tag<span class="op">.</span>remove_title()<span class="op">;</span></span>
<span id="cb1-16"><a href="start-simple.html#cb1-16" aria-hidden="true"></a> <span class="co">// trying to remove a field that&#39;s already empty won&#39;t hurt</span></span>
<span id="cb1-17"><a href="start-simple.html#cb1-17" aria-hidden="true"></a></span>
<span id="cb1-18"><a href="start-simple.html#cb1-18" aria-hidden="true"></a> <span class="kw">let</span> cover <span class="op">=</span> Picture <span class="op">{</span></span>
<span id="cb1-19"><a href="start-simple.html#cb1-19" aria-hidden="true"></a> mime_type<span class="op">:</span> <span class="pp">MimeType::</span>Jpeg<span class="op">,</span></span>
<span id="cb1-20"><a href="start-simple.html#cb1-20" aria-hidden="true"></a> data<span class="op">:</span> <span class="op">&amp;</span><span class="pp">vec!</span>[<span class="dv">0u8</span><span class="op">;</span> <span class="dv">10</span>]<span class="op">,</span></span>
<span id="cb1-21"><a href="start-simple.html#cb1-21" aria-hidden="true"></a> <span class="op">};</span></span>
<span id="cb1-22"><a href="start-simple.html#cb1-22" aria-hidden="true"></a></span>
<span id="cb1-23"><a href="start-simple.html#cb1-23" aria-hidden="true"></a> tag<span class="op">.</span>set_album_cover(cover<span class="op">.</span>clone())<span class="op">;</span></span>
<span id="cb1-24"><a href="start-simple.html#cb1-24" aria-hidden="true"></a> <span class="pp">assert_eq!</span>(tag<span class="op">.</span>album_cover()<span class="op">,</span> <span class="cn">Some</span>(cover))<span class="op">;</span></span>
<span id="cb1-25"><a href="start-simple.html#cb1-25" aria-hidden="true"></a> tag<span class="op">.</span>remove_album_cover()<span class="op">;</span></span>
<span id="cb1-26"><a href="start-simple.html#cb1-26" aria-hidden="true"></a> <span class="pp">assert!</span>(tag<span class="op">.</span>album_cover()<span class="op">.</span>is_none())<span class="op">;</span></span>
<span id="cb1-27"><a href="start-simple.html#cb1-27" aria-hidden="true"></a> tag<span class="op">.</span>remove_album_cover()<span class="op">;</span></span>
<span id="cb1-28"><a href="start-simple.html#cb1-28" aria-hidden="true"></a></span>
<span id="cb1-29"><a href="start-simple.html#cb1-29" aria-hidden="true"></a> tag<span class="op">.</span>write_to_path(MP3_FILE)<span class="op">.</span>expect(<span class="st">&quot;Fail to save&quot;</span>)<span class="op">;</span></span>
<span id="cb1-30"><a href="start-simple.html#cb1-30" aria-hidden="true"></a> <span class="co">// </span><span class="al">TASK</span><span class="co">: reload the file and prove the data have been saved</span></span>
<span id="cb1-31"><a href="start-simple.html#cb1-31" aria-hidden="true"></a><span class="op">}</span></span></code></pre></div>
<p>Note that <code>Tag</code> always reads into a <code>Box&lt;dyn AudioTag&gt;</code>. If you do not want a trait object, you can use the underlying concrete types. However, youll also need to manually bring the traits into scope if you prefer not to write <code>audiotags::*</code>.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb2-1"><a href="start-simple.html#cb2-1" aria-hidden="true"></a><span class="kw">use</span> <span class="pp">audiotags::</span><span class="op">{</span><span class="pp">traits::</span><span class="op">*,</span> FlacTag<span class="op">,</span> Id3v2Tag<span class="op">,</span> Mp4Tag<span class="op">};</span></span>
<span id="cb2-2"><a href="start-simple.html#cb2-2" aria-hidden="true"></a><span class="co">// or alternatively `use audiotags::*`</span></span>
<span id="cb2-3"><a href="start-simple.html#cb2-3" aria-hidden="true"></a></span>
<span id="cb2-4"><a href="start-simple.html#cb2-4" aria-hidden="true"></a><span class="kw">fn</span> main() <span class="op">{</span></span>
<span id="cb2-5"><a href="start-simple.html#cb2-5" aria-hidden="true"></a> <span class="kw">let</span> <span class="kw">mut</span> tag <span class="op">=</span> <span class="pp">FlacTag::</span>read_from_path(<span class="st">&quot;assets/a.flac&quot;</span>)<span class="op">.</span>unwrap()<span class="op">;</span></span>
<span id="cb2-6"><a href="start-simple.html#cb2-6" aria-hidden="true"></a> tag<span class="op">.</span>set_title(<span class="st">&quot;foo&quot;</span>)<span class="op">;</span></span>
<span id="cb2-7"><a href="start-simple.html#cb2-7" aria-hidden="true"></a> <span class="pp">assert_eq!</span>(tag<span class="op">.</span>title()<span class="op">,</span> <span class="cn">Some</span>(<span class="st">&quot;foo&quot;</span>))<span class="op">;</span></span>
<span id="cb2-8"><a href="start-simple.html#cb2-8" aria-hidden="true"></a> <span class="kw">let</span> <span class="kw">mut</span> tag <span class="op">=</span> <span class="pp">Mp4Tag::</span>read_from_path(<span class="st">&quot;assets/a.m4a&quot;</span>)<span class="op">.</span>unwrap()<span class="op">;</span></span>
<span id="cb2-9"><a href="start-simple.html#cb2-9" aria-hidden="true"></a> tag<span class="op">.</span>set_title(<span class="st">&quot;foo&quot;</span>)<span class="op">;</span></span>
<span id="cb2-10"><a href="start-simple.html#cb2-10" aria-hidden="true"></a> <span class="pp">assert_eq!</span>(tag<span class="op">.</span>title()<span class="op">,</span> <span class="cn">Some</span>(<span class="st">&quot;foo&quot;</span>))<span class="op">;</span></span>
<span id="cb2-11"><a href="start-simple.html#cb2-11" aria-hidden="true"></a> <span class="kw">let</span> <span class="kw">mut</span> tag <span class="op">=</span> <span class="pp">Id3v2Tag::</span>read_from_path(<span class="st">&quot;assets/a.mp3&quot;</span>)<span class="op">.</span>unwrap()<span class="op">;</span></span>
<span id="cb2-12"><a href="start-simple.html#cb2-12" aria-hidden="true"></a> tag<span class="op">.</span>set_title(<span class="st">&quot;foo&quot;</span>)<span class="op">;</span></span>
<span id="cb2-13"><a href="start-simple.html#cb2-13" aria-hidden="true"></a> <span class="pp">assert_eq!</span>(tag<span class="op">.</span>title()<span class="op">,</span> <span class="cn">Some</span>(<span class="st">&quot;foo&quot;</span>))<span class="op">;</span></span>
<span id="cb2-14"><a href="start-simple.html#cb2-14" aria-hidden="true"></a> <span class="co">// all other methods in trait `AudioTagEdit` are available, not just title</span></span>
<span id="cb2-15"><a href="start-simple.html#cb2-15" aria-hidden="true"></a><span class="op">}</span></span></code></pre></div>
</div>
</section>
@ -207,7 +223,7 @@ code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warni
</div>
</div>
<a href="index.html" class="navigation navigation-prev " aria-label="Previous page"><i class="fa fa-angle-left"></i></a>
<a href="conversion.html" class="navigation navigation-next " aria-label="Next page"><i class="fa fa-angle-right"></i></a>
<a href="conversion-and-downcast.html" class="navigation navigation-next " aria-label="Next page"><i class="fa fa-angle-right"></i></a>
</div>
</div>
<script src="libs/gitbook-2.6.7/js/app.min.js"></script>

View file

@ -13,25 +13,6 @@ pre code {
white-space: inherit;
}
@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;
font-weight: 400;
src: local('Lato Regular'), local('Lato-Regular'),
url('https://tianyishi2001.github.io/ox/fonts/lato-v11-latin-regular.woff2') format('woff2'),
url('https://tianyishi2001.github.io/ox/fonts/lato-v11-latin-regular.woff') format('woff');
}
@font-face {
font-family: "nexus-serif";
src: url("https://tianyishi2001.github.io/ox/fonts/nexus-serif/NexusSerifWebPro-Regular.woff");

View file

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

View file

@ -1,8 +1,11 @@
# Conversion
# Conversion and Downcast
The following example shows how you can read the tag in an `mp3` file, convert it into an `mp4` tag, and write it to an `m4a` file.
## Converting from a `Box<dyn AudioTag` to Another
```rust
use audiotags::{Config, Tag, TagType};
fn main() {
@ -15,12 +18,13 @@ fn main() {
// set the title
mp3tag.set_title("title from mp3 file");
// we can convert it to an mp4 tag and save it to an m4a file.
let mut mp4tag = mp3tag.into_tag(TagType::Mp4);
let mut mp4tag = mp3tag.to_dyn_tag(TagType::Mp4);
mp4tag.write_to_path(M4A_FILE).unwrap();
// reload the tag from the m4a file; this time specifying the
// tag type (you can also use `default()`)
let mut mp4tag = Tag::with_tag_type(TagType::Mp4)
let mut mp4tag = Tag::new()
.with_tag_type(TagType::Mp4)
.read_from_path(M4A_FILE)
.unwrap();
// the tag originated from an mp3 file is successfully written
@ -36,7 +40,61 @@ fn main() {
// convert to id3 tag, which does not support multiple artists
mp4tag.set_config(Config::default().sep_artist("/"));
// separator is by default `;` but we can customise it
let mp3tag = mp4tag.into_tag(TagType::Id3v2);
let mp3tag = mp4tag.to_dyn_tag(TagType::Id3v2);
assert_eq!(mp3tag.artist(), Some("artist1 of mp4/artist2 of mp4"));
}
```
## Converting into a Concrete Type (Downcasting)
> Can I convert into a concrete type?
Yes, you can directly convert `.into()` it (this is technically known as a "downcast"):
```rust
use audiotags::{FlacTag, Tag};
fn main() {
let id3v2tag = Tag::default().read_from_path("assets/a.mp3").unwrap();
let _flactag: FlacTag = id3v2tag.into();
// of course, you can `let id3v2tag_concrete: Id3v2Tag = id3v2tag.into();`
}
```
You can even convert `.into()` the 'backend' tag type:
```rust
use audiotags::Tag;
fn main() {
let mp3tag = Tag::default().read_from_path("assets/a.mp3").unwrap();
let flactag: metaflac::Tag = mp3tag.into(); // into the 'backend' tag
// then you can use methods specific to metaflac
let _ = flactag.get_streaminfo();
}
```
This is useful when you really need to use the methods not provided by `audiotags::traits::*`.
You can also downcast the concrete `audiotags::FlacTag` to `metaflac::Tag` and so no.
## Upcasting
Since you're allowed to downcast, naturally you can also upcast:
```rust
use audiotags::*;
fn main() {
let mut innertag = metaflac::Tag::default();
innertag
.vorbis_comments_mut()
.set_title(vec!["title from metaflac::Tag"]);
let tag: FlacTag = innertag.into();
let _id3tag = tag.to_dyn_tag(TagType::Id3v2);
// in this case the "title" metadata will be
// losslessly written into the id3tag.
// However, if you have FLAC-specific fields,
// they will be lost upon conversion
}
```

View file

@ -11,7 +11,7 @@ fn main() {
.vorbis_comments_mut()
.set_title(vec!["title from metaflac::Tag"]);
let tag: FlacTag = innertag.into();
let mut id3tag = tag.into_tag(TagType::Id3v2);
let mut id3tag = tag.to_dyn_tag(TagType::Id3v2);
id3tag
.write_to_path("assets/a.mp3")
.expect("Fail to write!");

View file

@ -3,16 +3,13 @@
The following example shows how you can read an audio file, parse, set, and save its metadata:
```rust
use audiotags::{MimeType, Picture, Tag, TagType};
const MP3_FILE: &'static str = "assets/a.mp3";
fn main() {
// using `default()` so that the metadata format is guessed
// (from the file extension) (in this case, Id3v2 tag is read)
let mut tag = Tag::default().read_from_path(MP3_FILE).unwrap();
// using `default()` or `new()` alone so that the metadata format is
// guessed (from the file extension) (in this case, Id3v2 tag is read)
let mut tag = Tag::new().read_from_path(MP3_FILE).unwrap();
// You can also specify the metadata format (tag type):
let _tag = Tag::with_tag_type(TagType::Id3v2)
let _tag = Tag::new()
.with_tag_type(TagType::Id3v2)
.read_from_path(MP3_FILE)
.expect("Fail to read!");
@ -34,7 +31,27 @@ fn main() {
assert!(tag.album_cover().is_none());
tag.remove_album_cover();
tag.save_to_path(MP3_FILE).expect("Fail to save");
tag.write_to_path(MP3_FILE).expect("Fail to save");
// TASK: reload the file and prove the data have been saved
}
```
Note that `Tag` always reads into a `Box<dyn AudioTag>`. If you do not want a trait object, you can use the underlying concrete types. However, you'll also need to manually bring the traits into scope if you prefer not to write `audiotags::*`.
```rust
use audiotags::{traits::*, FlacTag, Id3v2Tag, Mp4Tag};
// or alternatively `use audiotags::*`
fn main() {
let mut tag = FlacTag::read_from_path("assets/a.flac").unwrap();
tag.set_title("foo");
assert_eq!(tag.title(), Some("foo"));
let mut tag = Mp4Tag::read_from_path("assets/a.m4a").unwrap();
tag.set_title("foo");
assert_eq!(tag.title(), Some("foo"));
let mut tag = Id3v2Tag::read_from_path("assets/a.mp3").unwrap();
tag.set_title("foo");
assert_eq!(tag.title(), Some("foo"));
// all other methods in trait `AudioTagEdit` are available, not just title
}
```

View file

@ -13,16 +13,6 @@ pre code {
white-space: inherit;
}
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 400;
src: local('Lato Regular'), local('Lato-Regular'),
url('https://tianyishi2001.github.io/ox/fonts/lato-v11-latin-regular.woff2') format('woff2'),
url('https://tianyishi2001.github.io/ox/fonts/lato-v11-latin-regular.woff') format('woff');
}
@font-face {
font-family: "nexus-serif";
src: url("https://tianyishi2001.github.io/ox/fonts/nexus-serif/NexusSerifWebPro-Regular.woff");

View file

@ -4,10 +4,10 @@ use crate::*;
pub struct AnyTag<'a> {
pub config: Config,
pub title: Option<&'a str>,
pub artists: Option<Vec<&'a str>>, // ? iterator
pub artists: Option<Vec<&'a str>>,
pub year: Option<i32>,
pub album_title: Option<&'a str>,
pub album_artists: Option<Vec<&'a str>>, // ? iterator
pub album_artists: Option<Vec<&'a str>>,
pub album_cover: Option<Picture<'a>>,
pub track_number: Option<u16>,
pub total_tracks: Option<u16>,
@ -15,10 +15,6 @@ pub struct AnyTag<'a> {
pub total_discs: Option<u16>,
}
// impl<'a> From<&'a AnyTag> for AnyTag<'a> {
// fn from(inp: &'a AnyTag)
// }
impl AudioTagConfig for AnyTag<'_> {
fn config(&self) -> &Config {
&self.config

View file

@ -1,9 +1,6 @@
/// Error types that could occur in this library.
/// Error that could occur in this library.
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("")]
DowncastError,
/// Fail to guess the metadata format based on the file extension.
#[error("Fail to guess the metadata format based on the file extension.")]
UnknownFileExtension(String),

View file

@ -55,10 +55,81 @@ use std::path::Path;
pub use std::convert::{TryFrom, TryInto};
/// A builder for `Box<dyn AudioTag>`. If you do not want a trait object, you can use individual types.
///
/// # Examples
///
/// ```
/// use audiotags::{Tag, TagType};
/// // Guess the format by default
/// let mut tag = Tag::new().read_from_path("assets/a.mp3").unwrap();
/// tag.set_title("Foo");
/// // you can convert the tag type and save the metadata to another file.
/// tag.to_dyn_tag(TagType::Mp4).write_to_path("assets/a.m4a");
/// // you can specify the tag type (but when you want to do this, also consider directly using the concrete type)
/// let tag = Tag::new().with_tag_type(TagType::Mp4).read_from_path("assets/a.m4a").unwrap();
/// assert_eq!(tag.title(), Some("Foo"));
/// ```
#[derive(Default)]
pub struct Tag {
/// The tag type which can be specified with `.with_tag_type()` before parsing.
tag_type: Option<TagType>,
/// The config which can be specified with `.with_config()` before parsing.
config: Config,
}
impl Tag {
/// Initiate a new Tag (a builder for `Box<dyn AudioTag>`) with default configurations.
/// You can then optionally chain `with_tag_type` and/or `with_config`.
/// Finally, you `read_from_path`
pub fn new() -> Self {
Self::default()
}
/// Specify the tag type
pub fn with_tag_type(self, tag_type: TagType) -> Self {
Self {
tag_type: Some(tag_type),
config: self.config,
}
}
/// Specify configuration, if you do not want to use the default
pub fn with_config(self, config: Config) -> Self {
Self {
tag_type: self.tag_type,
config: config.clone(),
}
}
pub fn read_from_path(&self, path: impl AsRef<Path>) -> crate::Result<Box<dyn AudioTag>> {
match self.tag_type.unwrap_or(TagType::try_from_ext(
path.as_ref()
.extension()
.unwrap()
.to_string_lossy()
.to_string()
.to_lowercase()
.as_str(),
)?) {
TagType::Id3v2 => Ok(Box::new({
let mut t = Id3v2Tag::read_from_path(path)?;
t.set_config(self.config.clone());
t
})),
TagType::Mp4 => Ok(Box::new({
let mut t = Mp4Tag::read_from_path(path)?;
t.set_config(self.config.clone());
t
})),
TagType::Flac => Ok(Box::new({
let mut t = FlacTag::read_from_path(path)?;
t.set_config(self.config.clone());
t
})),
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum TagType {
// /// Guess the tag type based on the file extension
// Guess,
/// ## Common file extensions
///
/// `.mp3`
@ -90,57 +161,10 @@ impl TagType {
}
}
#[derive(Default)]
pub struct Tag {
tag_type: Option<TagType>,
config: Config,
}
impl Tag {
pub fn with_tag_type(tag_type: TagType) -> Self {
Self {
tag_type: Some(tag_type),
config: Config::default(),
}
}
pub fn with_config(config: Config) -> Self {
Self {
tag_type: None,
config: config.clone(),
}
}
pub fn with_tag_type_and_config(tag_type: TagType, config: Config) -> Self {
Self {
tag_type: Some(tag_type),
config: config.clone(),
}
}
pub fn read_from_path(&self, path: impl AsRef<Path>) -> crate::Result<Box<dyn AudioTag>> {
match self.tag_type.unwrap_or(TagType::try_from_ext(
path.as_ref()
.extension()
.unwrap()
.to_string_lossy()
.to_string()
.to_lowercase()
.as_str(),
)?) {
TagType::Id3v2 => Ok(Box::new({
let mut t = Id3v2Tag::read_from_path(path)?;
t.set_config(self.config.clone());
t
})),
TagType::Mp4 => Ok(Box::new({
let mut t = Mp4Tag::read_from_path(path)?;
t.set_config(self.config.clone());
t
})),
TagType::Flac => Ok(Box::new({
let mut t = FlacTag::read_from_path(path)?;
t.set_config(self.config.clone());
t
})),
}
}
/// Convert a concrete tag type into another
#[macro_export]
macro_rules! convert {
($inp:expr, $target_type:ty) => {
$target_type::from(inp.to_anytag())
};
}

View file

@ -1,6 +1,6 @@
use super::*;
pub trait AudioTag: AudioTagEdit + AudioTagWrite + IntoAnyTag {}
pub trait AudioTag: AudioTagEdit + AudioTagWrite + ToAnyTag {}
// pub trait TagIo {
// fn read_from_path(path: &str) -> crate::Result<AnyTag>;
@ -137,32 +137,22 @@ pub trait AudioTagConfig {
fn set_config(&mut self, config: Config);
}
pub trait IntoAnyTag {
fn into_anytag(&self) -> AnyTag<'_>;
pub trait ToAnyTag: ToAny {
fn to_anytag(&self) -> AnyTag<'_>;
/// Convert the tag type, which can be lossy.
fn into_tag(&self, tag_type: TagType) -> Box<dyn AudioTag> {
fn to_dyn_tag(&self, tag_type: TagType) -> Box<dyn AudioTag> {
// TODO: write a macro or something that implement this method for every tag type so that if the
// TODO: target type is the same, just return self
match tag_type {
TagType::Id3v2 => Box::new(Id3v2Tag::from(self.into_anytag())),
TagType::Mp4 => Box::new(Mp4Tag::from(self.into_anytag())),
TagType::Flac => Box::new(FlacTag::from(self.into_anytag())),
TagType::Id3v2 => Box::new(Id3v2Tag::from(self.to_anytag())),
TagType::Mp4 => Box::new(Mp4Tag::from(self.to_anytag())),
TagType::Flac => Box::new(FlacTag::from(self.to_anytag())),
}
}
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()
// }
// }
pub trait ToAny {
fn to_any(&self) -> &dyn std::any::Any;
fn to_any_mut(&mut self) -> &mut dyn std::any::Any;
}

View file

@ -7,7 +7,7 @@ fn test_inner() {
.vorbis_comments_mut()
.set_title(vec!["title from metaflac::Tag"]);
let tag: FlacTag = innertag.into();
let mut id3tag = tag.into_tag(TagType::Id3v2);
let mut id3tag = tag.to_dyn_tag(TagType::Id3v2);
id3tag
.write_to_path("assets/a.mp3")
.expect("Fail to write!");