Attention ! Gitlab fournissant maintenant nativement des certificats Let’s Encrypt aux domaines personnalisés des Gitlab Pages, nous avons coupé notre service qui le faisait automatiquement pour vous.

Il est impératif, pour que votre domaine personnalisé continue à avoir un certificat Let’s Encrypt à jour, d’activer la fonctionnalité native dans les paramètres de votre projet. Cette activation remplacera votre certificat actuel par un nouveau certificat Let’s Encrypt géré par Gitlab.

Voir les détails sur https://docs.framasoft.org/fr/gitlab/gitlab-pages-le.html

Commit 15606361 authored by Leonardo Schwarz's avatar Leonardo Schwarz

Update dependencies (notably xpath_reader 0.5.2)

parent 2c2095bb
......@@ -2,6 +2,6 @@ target
/replay/*
!/replay/test_entities
Cargo.lock
/.idea
# rustfmt backup files
*.rs.bk
......@@ -10,14 +10,14 @@ default = []
[dependencies]
error-chain = "0.11"
isolang = "0.2"
regex = "0.2.1"
isolang = "1"
regex = "1"
reqwest_mock = "0.5"
rusqlite = { version = "0.12.0", optional = true }
url = "1.4.0"
uuid = { version = "0.6", features = ["use_std"] }
xpath_reader = "0.4"
uuid = { version = "0.7" }
xpath_reader = "0.5"
[dev-dependencies]
pretty_env_logger = "0.2"
pretty_env_logger = "0.3"
log = "0.4"
use super::*;
use xpath_reader::XpathReader;
use xpath_reader::Reader;
/// Checks if there is an error in the document provided by the reader and
/// returns Ok if there
/// wasn't and Err parsing the MusicBrainz error if the API actually returned
/// an error.
pub fn check_response_error<'d, R>(reader: &'d R) -> Result<(), ClientError>
where
R: XpathReader<'d>,
{
match reader.read_vec::<String>("//error/text") {
pub fn check_response_error<'d>(reader: &'d Reader<'d>) -> Result<(), ClientError> {
let r: Result<Vec<String>, _> = reader.read("//error/text");
match r {
Ok(errs) => {
if errs.len() > 0 {
let text = errs.join("\n");
......@@ -26,7 +25,7 @@ where
mod tests {
use super::*;
use error_chain::ChainedError;
use xpath_reader::XpathStrReader;
use xpath_reader::Reader;
const XML_ERR: &'static str = r#"<?xml version="1.0" encoding="UTF-8"?>
<error>
......@@ -37,10 +36,9 @@ mod tests {
const XML_OK: &'static str = r#"<?xml version="1.0" encoding="UTF-8"?><metadata xmlns="http://musicbrainz.org/ns/mmd-2.0#"><release-group type="Album" type-id="f529b476-6e62-324f-b0aa-1f3e33d313fc" id="23c74936-ad4f-45bb-8b6b-527d4aeaaad6"><title>A.I Complex</title><first-release-date>2014-07-26</first-release-date><primary-type id="f529b476-6e62-324f-b0aa-1f3e33d313fc">Album</primary-type></release-group></metadata>"#;
#[test]
fn error()
{
fn error() {
let context = ::util::musicbrainz_context();
let reader = XpathStrReader::new(XML_ERR, &context).unwrap();
let reader = Reader::from_str(XML_ERR, Some(&context)).unwrap();
let res = check_response_error(&reader);
let err = res.err().unwrap();
......@@ -51,10 +49,9 @@ mod tests {
}
#[test]
fn ok()
{
fn ok() {
let context = ::util::musicbrainz_context();
let reader = XpathStrReader::new(XML_OK, &context).unwrap();
let reader = Reader::from_str(XML_OK, Some(&context)).unwrap();
// should not raise error
check_response_error(&reader).unwrap();
......
......@@ -7,7 +7,7 @@ use reqwest_mock::Client as MockClient;
use reqwest_mock::GenericClient as HttpClient;
use reqwest_mock::{StatusCode, Url};
use reqwest_mock::header::UserAgent;
use xpath_reader::reader::{FromXmlContained, XpathStrReader};
use xpath_reader::reader::{FromXml, Reader};
use std::time::{Duration, Instant};
use std::thread::sleep;
......@@ -18,14 +18,12 @@ mod error;
pub(crate) use self::error::check_response_error;
/// Helper extracting the number of milliseconds from a `Duration`.
fn as_millis(duration: &Duration) -> u64
{
fn as_millis(duration: &Duration) -> u64 {
((duration.as_secs() as f64) + (duration.subsec_nanos() as f64) * 1e6) as u64
}
/// Returns an `Instant` at least 1000 seconds ago.
fn past_instant() -> Instant
{
fn past_instant() -> Instant {
Instant::now() - Duration::new(1000, 0)
}
......@@ -70,8 +68,7 @@ pub struct ClientWaits {
}
impl Default for ClientWaits {
fn default() -> Self
{
fn default() -> Self {
ClientWaits {
backoff_init: 400,
requests: 1000,
......@@ -97,8 +94,7 @@ pub struct Client {
impl Client {
/// Create a new `Client` instance.
pub fn new(config: ClientConfig) -> Self
{
pub fn new(config: ClientConfig) -> Self {
Client {
config: config,
http_client: HttpClient::direct(),
......@@ -111,8 +107,7 @@ impl Client {
/// This is useful for testing purposes where you can inject a different
/// `HttpClient`, i. e. one replaying requests to save API calls or one
/// providing explicit stubbing.
pub fn with_http_client(config: ClientConfig, client: HttpClient) -> Self
{
pub fn with_http_client(config: ClientConfig, client: HttpClient) -> Self {
Client {
config: config,
http_client: client,
......@@ -124,8 +119,7 @@ impl Client {
impl Client {
/// Waits until we are allowed to make the next request to the MusicBrainz
/// API.
fn wait_if_needed(&mut self)
{
fn wait_if_needed(&mut self) {
let now = Instant::now();
let elapsed = now.duration_since(self.last_request);
if as_millis(&elapsed) < self.config.waits.requests {
......@@ -137,27 +131,27 @@ impl Client {
/// Fetch the specified ressource from the server and parse it.
pub fn get_by_mbid<Res>(&mut self, mbid: &Mbid) -> Result<Res, ClientError>
where
Res: Resource + FromXmlContained,
Res: Resource + FromXml,
{
let url = Res::get_url(mbid);
let response_body = self.get_body(url.parse()?)?;
// Parse the response.
let context = ::util::musicbrainz_context();
let reader = XpathStrReader::new(&response_body[..], &context)?;
let reader = Reader::from_str(&response_body[..], Some(&context))?;
check_response_error(&reader)?;
Ok(Res::from_xml(&reader)?)
}
pub(crate) fn get_body(&mut self, url: Url) -> Result<String, ClientError>
{
pub(crate) fn get_body(&mut self, url: Url) -> Result<String, ClientError> {
self.wait_if_needed();
let mut attempts = 0;
let mut backoff = self.config.waits.backoff_init;
while attempts < self.config.max_retries {
let response = self.http_client
let response = self
.http_client
.get(url.clone())
.header(UserAgent::new(self.config.user_agent.clone()))
.send()?;
......@@ -172,26 +166,21 @@ impl Client {
return Ok(response_body);
}
}
Err(
"MusicBrainz returned 503 (ServiceUnavailable) too many times.".into(),
)
Err("MusicBrainz returned 503 (ServiceUnavailable) too many times.".into())
}
/// Returns a search builder to search for an area.
pub fn search_area<'cl>(&'cl mut self) -> AreaSearchBuilder<'cl>
{
pub fn search_area<'cl>(&'cl mut self) -> AreaSearchBuilder<'cl> {
AreaSearchBuilder::new(self)
}
/// Returns a search biulder to search for an artist.
pub fn search_artist<'cl>(&'cl mut self) -> ArtistSearchBuilder<'cl>
{
pub fn search_artist<'cl>(&'cl mut self) -> ArtistSearchBuilder<'cl> {
ArtistSearchBuilder::new(self)
}
/// Returns a search builder to search for a release group.
pub fn search_release_group<'cl>(&'cl mut self) -> ReleaseGroupSearchBuilder<'cl>
{
pub fn search_release_group<'cl>(&'cl mut self) -> ReleaseGroupSearchBuilder<'cl> {
ReleaseGroupSearchBuilder::new(self)
}
}
......@@ -200,8 +189,7 @@ impl Client {
mod tests {
use super::*;
fn get_client(testname: &str) -> Client
{
fn get_client(testname: &str) -> Client {
Client::with_http_client(
ClientConfig {
user_agent: "MusicBrainz-Rust/Testing".to_string(),
......@@ -213,8 +201,7 @@ mod tests {
}
#[test]
fn search_release_group()
{
fn search_release_group() {
let mut client = get_client("release_group_01");
let results = client
.search_release_group()
......
use xpath_reader::{FromXml, FromXmlError, XpathReader};
use xpath_reader::reader::{FromXmlContained, FromXmlElement};
use xpath_reader::{FromXml, Error, Reader};
use entities::{Mbid, Resource};
enum_mb_xml!{
enum_mb_xml! {
/// Specifies what a specific `Area` instance actually is.
pub enum AreaType {
/// Areas included (or previously included) in ISO 3166-1.
......@@ -59,20 +58,15 @@ pub struct Area {
pub iso_3166: Option<String>,
}
impl FromXmlContained for Area {}
impl FromXml for Area {
fn from_xml<'d, R>(reader: &'d R) -> Result<Area, FromXmlError>
where
R: XpathReader<'d>,
{
fn from_xml<'d>(reader: &'d Reader<'d>) -> Result<Area, Error> {
Ok(Area {
mbid: reader.read(".//mb:area/@id")?,
name: reader.read(".//mb:area/mb:name/text()")?,
sort_name: reader.read(".//mb:area/mb:sort-name/text()")?,
area_type: reader.read(".//mb:area/@type")?,
iso_3166: reader.read_option(
".//mb:area/mb:iso-3166-1-code-list/mb:iso-3166-1-code/text()",
)?,
iso_3166: reader
.read(".//mb:area/mb:iso-3166-1-code-list/mb:iso-3166-1-code/text()")?,
})
}
}
......@@ -88,8 +82,7 @@ mod tests {
use std::str::FromStr;
#[test]
fn area_read_xml1()
{
fn area_read_xml1() {
let mbid = Mbid::from_str("a1411661-be21-4290-8dc1-50f3d8e3ea67").unwrap();
let area: Area = ::util::test_utils::fetch_entity(&mbid).unwrap();
......@@ -101,8 +94,7 @@ mod tests {
}
#[test]
fn area_read_xml2()
{
fn area_read_xml2() {
let mbid = Mbid::from_str("2db42837-c832-3c27-b4a3-08198f75693c").unwrap();
let area: Area = ::util::test_utils::fetch_entity(&mbid).unwrap();
......
use xpath_reader::{FromXml, FromXmlError, XpathReader};
use xpath_reader::reader::{FromXmlContained, FromXmlElement};
use xpath_reader::{FromXml, FromXmlOptional, Error, Reader};
use entities::{Mbid, Resource};
use entities::date::PartialDate;
use entities::refs::AreaRef;
enum_mb_xml! {
enum_mb_xml_optional! {
/// Specification of the gender of an artist.
pub enum Gender {
var Female = "Female",
......@@ -14,7 +13,7 @@ enum_mb_xml! {
}
}
enum_mb_xml! {
enum_mb_xml_optional! {
/// Specifies what an `Artist` instance actually is.
pub enum ArtistType {
var Person = "Person",
......@@ -90,23 +89,19 @@ pub struct Artist {
pub isni_code: Option<String>,
}
impl FromXmlContained for Artist {}
impl FromXml for Artist {
fn from_xml<'d, R>(reader: &'d R) -> Result<Self, FromXmlError>
where
R: XpathReader<'d>,
{
fn from_xml<'d>(reader: &'d Reader<'d>) -> Result<Self, Error> {
Ok(Artist {
aliases: reader.read_vec(".//mb:artist/mb:alias-list/mb:alias/text()")?,
annotation: reader.read_option(".//mb:artist/mb:annotation/text()")?,
area: reader.read_option(".//mb:artist/mb:area")?,
artist_type: reader.read_option(".//mb:artist/@type")?,
begin_date: reader.read_option(".//mb:artist/mb:life-span/mb:begin/text()")?,
disambiguation: reader.read_option(".//mb:artist/mb:disambiguation/text()")?,
end_date: reader.read_option(".//mb:artist/mb:life-span/mb:end/text()")?,
gender: reader.read_option(".//mb:artist/mb:gender/text()")?,
ipi_code: reader.read_option(".//mb:artist/mb:ipi/text()")?,
isni_code: reader.read_option(".//mb:artist/mb:isni-list/mb:isni/text()")?,
aliases: reader.read(".//mb:artist/mb:alias-list/mb:alias/text()")?,
annotation: reader.read(".//mb:artist/mb:annotation/text()")?,
area: reader.read(".//mb:artist/mb:area")?,
artist_type: reader.read(".//mb:artist/@type")?,
begin_date: reader.read(".//mb:artist/mb:life-span/mb:begin/text()")?,
disambiguation: reader.read(".//mb:artist/mb:disambiguation/text()")?,
end_date: reader.read(".//mb:artist/mb:life-span/mb:end/text()")?,
gender: reader.read(".//mb:artist/mb:gender/text()")?,
ipi_code: reader.read(".//mb:artist/mb:ipi/text()")?,
isni_code: reader.read(".//mb:artist/mb:isni-list/mb:isni/text()")?,
mbid: reader.read(".//mb:artist/@id")?,
name: reader.read(".//mb:artist/mb:name/text()")?,
sort_name: reader.read(".//mb:artist/mb:sort-name/text()")?,
......@@ -125,9 +120,7 @@ mod tests {
use std::str::FromStr;
#[test]
fn artist_read_xml1()
{
fn artist_read_xml1() {
let mbid = Mbid::from_str("90e7c2f9-273b-4d6c-a662-ab2d73ea4b8e").unwrap();
let artist: Artist = ::util::test_utils::fetch_entity(&mbid).unwrap();
......@@ -158,8 +151,7 @@ mod tests {
}
#[test]
fn artist_read_xml2()
{
fn artist_read_xml2() {
let mbid = Mbid::from_str("650e7db6-b795-4eb5-a702-5ea2fc46c848").unwrap();
let artist: Artist = ::util::test_utils::fetch_entity(&mbid).unwrap();
......
......@@ -6,7 +6,7 @@ use std::str::FromStr;
use std::num::ParseIntError;
use std::error::Error;
use std::fmt::Display;
use xpath_reader::{FromXml, FromXmlError, XpathReader};
use xpath_reader::{FromXml, FromXmlOptional, Reader};
/// Represents a partial date as it is used across MusicBrainz.
///
......@@ -27,8 +27,7 @@ pub struct FullDate {
}
impl PartialDate {
pub fn new(year: Option<u16>, month: Option<u8>, day: Option<u8>) -> PartialDate
{
pub fn new(year: Option<u16>, month: Option<u8>, day: Option<u8>) -> PartialDate {
PartialDate {
year: year,
month: month,
......@@ -36,18 +35,15 @@ impl PartialDate {
}
}
pub fn year(&self) -> Option<u16>
{
pub fn year(&self) -> Option<u16> {
self.year
}
pub fn month(&self) -> Option<u8>
{
pub fn month(&self) -> Option<u8> {
self.month
}
pub fn day(&self) -> Option<u8>
{
pub fn day(&self) -> Option<u8> {
self.day
}
......@@ -68,8 +64,7 @@ impl PartialDate {
/// Some(FullDate::new(2017, 2, 2))
/// );
/// ```
pub fn full_date(&self) -> Option<FullDate>
{
pub fn full_date(&self) -> Option<FullDate> {
if self.year.is_some() && self.month.is_some() && self.day.is_some() {
Some(FullDate {
year: self.year.unwrap(),
......@@ -83,8 +78,7 @@ impl PartialDate {
}
impl FullDate {
pub fn new(year: u16, month: u8, day: u8) -> FullDate
{
pub fn new(year: u16, month: u8, day: u8) -> FullDate {
FullDate {
year: year,
month: month,
......@@ -92,18 +86,15 @@ impl FullDate {
}
}
pub fn year(&self) -> u16
{
pub fn year(&self) -> u16 {
self.year
}
pub fn month(&self) -> u8
{
pub fn month(&self) -> u8 {
self.month
}
pub fn day(&self) -> u8
{
pub fn day(&self) -> u8 {
self.day
}
}
......@@ -111,14 +102,16 @@ impl FullDate {
impl FromStr for PartialDate {
type Err = ParseDateError;
fn from_str(s: &str) -> Result<Self, Self::Err>
{
fn from_str(s: &str) -> Result<Self, Self::Err> {
// Get the pieces of the date.
let ps: Result<Vec<Option<u16>>, ParseIntError> = s.split("-")
.map(|x| if x == "??" || x == "????" {
let ps: Result<Vec<Option<u16>>, ParseIntError> = s
.split("-")
.map(|x| {
if x == "??" || x == "????" {
Ok(None)
} else {
x.parse().map(|y| Some(y))
}
})
.collect();
......@@ -149,25 +142,36 @@ impl FromStr for PartialDate {
}
impl Display for PartialDate {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
// TODO optimize later (no allocations)
let year = self.year.map(|n| format!("{:04}", n)).unwrap_or_else(|| "????".to_string());
let month = self.month.map(|n| format!("{:02}", n)).unwrap_or_else(|| "??".to_string());
let day = self.day.map(|n| format!("{:02}", n)).unwrap_or_else(|| "??".to_string());
let year = self
.year
.map(|n| format!("{:04}", n))
.unwrap_or_else(|| "????".to_string());
let month = self
.month
.map(|n| format!("{:02}", n))
.unwrap_or_else(|| "??".to_string());
let day = self
.day
.map(|n| format!("{:02}", n))
.unwrap_or_else(|| "??".to_string());
write!(f, "{}-{}-{}", year, month, day)
}
}
impl FromXml for PartialDate {
fn from_xml<'d, R>(reader: &'d R) -> Result<Self, FromXmlError>
where
R: XpathReader<'d>,
{
use xpath_reader::errors::ChainXpathErr;
String::from_xml(reader)?.parse().chain_err(|| "Parse Date error").map_err(
|e| FromXmlError::from(e),
)
impl FromXmlOptional for PartialDate {
fn from_xml_optional<'d>(
reader: &'d Reader<'d>,
) -> Result<Option<Self>, ::xpath_reader::Error> {
let s = Option::<String>::from_xml(reader)?;
if let Some(s) = s {
s.parse()
.map(|d| Some(d))
.map_err(::xpath_reader::Error::custom_err)
} else {
Ok(None)
}
}
}
......@@ -181,8 +185,7 @@ pub enum ParseDateError {
}
impl Error for ParseDateError {
fn description(&self) -> &str
{
fn description(&self) -> &str {
use self::ParseDateError::*;
match *self {
WrongNumberOfComponents(_) => "wrong number of components",
......@@ -194,8 +197,7 @@ impl Error for ParseDateError {
// TODO: Evaluate if this is what we want and if we can use this like this in
// requests.
impl Display for ParseDateError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
use self::ParseDateError::*;
match *self {
WrongNumberOfComponents(n) => {
......@@ -207,8 +209,7 @@ impl Display for ParseDateError {
}
impl From<ParseIntError> for ParseDateError {
fn from(e: ParseIntError) -> Self
{
fn from(e: ParseIntError) -> Self {
ParseDateError::ComponentInvalid(e)
}
}
......
use xpath_reader::{FromXml, FromXmlError, XpathReader};
use xpath_reader::reader::{FromXmlContained, FromXmlElement};
use xpath_reader::{FromXml, FromXmlOptional, Error, Reader};
use entities::{Mbid, Resource};
use entities::date::PartialDate;
enum_mb_xml! {
enum_mb_xml_optional! {
pub enum EventType {
var Concert = "Concert",
var Festival = "Festival",
......@@ -58,22 +57,18 @@ impl Resource for Event {
const INCL: &'static str = "aliases+annotation";
}
impl FromXmlContained for Event {}
impl FromXml for Event {
fn from_xml<'d, R>(reader: &'d R) -> Result<Self, FromXmlError>
where
R: XpathReader<'d>,
{
fn from_xml<'d>(reader: &'d Reader<'d>) -> Result<Self, Error> {
Ok(Event {
mbid: reader.read(".//mb:event/@id")?,
name: reader.read(".//mb:event/mb:name")?,
aliases: reader.read_vec(".//mb:event/mb:alias-list/mb:alias/text()")?,
event_type: reader.read_option(".//mb:event/@type")?,
setlist: reader.read_option(".//mb:event/mb:setlist")?,
aliases: reader.read(".//mb:event/mb:alias-list/mb:alias/text()")?,
event_type: reader.read(".//mb:event/@type")?,
setlist: reader.read(".//mb:event/mb:setlist")?,
begin_date: reader.read(".//mb:event/mb:life-span/mb:begin")?,
end_date: reader.read_option(".//mb:event/mb:life-span/mb:end")?,
disambiguation: reader.read_option(".//mb:event/mb:disambiguation")?,
annotation: reader.read_option(".//mb:event/mb:annotation/mb:text/text()")?,
end_date: reader.read(".//mb:event/mb:life-span/mb:end")?,
disambiguation: reader.read(".//mb:event/mb:disambiguation")?,
annotation: reader.read(".//mb:event/mb:annotation/mb:text/text()")?,
})
}
}
......@@ -84,8 +79,7 @@ mod tests {
use std::str::FromStr;
#[test]
fn read_1()
{
fn read_1() {
let mbid = Mbid::from_str("6e2ab7d5-f340-4c41-99a3-c901733402b4").unwrap();
let event: Event = ::util::test_utils::fetch_entity(&mbid).unwrap();
......@@ -101,8 +95,7 @@ mod tests {
}
#[test]
fn read_2()
{
fn read_2() {
let mbid = Mbid::from_str("9754f4dd-6fad-49b7-8f30-940c9af6b776").unwrap();
let event: Event = ::util::test_utils::fetch_entity(&mbid).unwrap();
......
use std::time::Duration;
use xpath_reader::{FromXmlError, XpathReader};
use xpath_reader::{Reader, FromXml, FromXmlOptional};
/// Note that the requirement of the `var` (variant) token is rather ugly but
/// required,
......@@ -31,18 +31,18 @@ macro_rules! enum_mb_xml
)+
}
impl FromXmlElement for $enum {}
impl FromXml for $enum {
fn from_xml<'d, R>(reader: &'d R) -> Result<Self, FromXmlError>
where
R: XpathReader<'d>,
fn from_xml<'d>(reader: &'d Reader<'d>) -> Result<Self, ::xpath_reader::Error>
{
match String::from_xml(reader)?.as_str() {
$(
$str => Ok($enum::$variant),
)+
"" => Err(FromXmlError::Absent),
s => Err(format!("Unknown `{}` value: '{}'", stringify!($enum), s).into()),
s => Err(
::xpath_reader::Error::custom_msg(
format!("Unknown `{}` value: '{}'", stringify!($enum), s)
)
)
}
}
}
......@@ -61,12 +61,71 @@ macro_rules! enum_mb_xml
}
}
pub fn read_mb_duration<'d, R>(reader: &'d R, path: &str) -> Result<Option<Duration>, FromXmlError>
where
R: XpathReader<'d>,
macro_rules! enum_mb_xml_optional
{
match reader.read_option::<String>(path)? {
Some(millis) => Ok(Some(Duration::from_millis(millis.parse()?))),
(
$(#[$attr:meta])* pub enum $enum:ident {
$(
$(#[$attr2:meta])*
var $variant:ident = $str:expr
),+
,
}
)
=>
{
$(#[$attr])*
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum $enum {
$(
$(#[$attr2])* $variant ,
)+
}
impl FromXmlOptional for $enum {
fn from_xml_optional<'d>(reader: &'d Reader<'d>) -> Result<Option<Self>, ::xpath_reader::Error>
{
let s = Option::<String>::from_xml(reader)?;
if let Some(s) = s {
match s.as_ref() {
$(
$str => Ok(Some($enum::$variant)),
)+
s => Err(
::xpath_reader::Error::custom_msg(
format!("Unknown `{}` value: '{}'", stringify!($enum), s)
)
)
}
} else {
Ok(None)
}
}
}
impl ::std::fmt::Display for $enum {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
let s = match *self {
$(
$enum::$variant => $str,
)+
};
write!(f, "{}", s)
}
}
}
}
pub fn read_mb_duration<'d>(
reader: &'d Reader<'d>,
path: &str,
) -> Result<Option<Duration>, ::xpath_reader::Error> {
let s: Option<String> = reader.read(path)?;
match s {
Some(millis) => Ok(Some(Duration::from_millis(
millis.parse().map_err(::xpath_reader::Error::custom_err)?,
))),
None => Ok(None),
}
}
use xpath_reader::{FromXml, FromXmlError, XpathReader};
use xpath_reader::reader::{FromXmlContained, FromXmlElement};
use xpath_reader::{FromXml, FromXmlOptional, Error, Reader};
use entities::{Mbid, Resource};
use entities::date::PartialDate;
......@@ -62,30 +61,26 @@ impl Resource for Label {
const INCL: &'static str = "aliases";
}
impl FromXmlContained for Label {}
impl FromXml for Label {
fn from_xml<'d, R>(reader: &'d R) -> Result<Label, FromXmlError>