From 5334d783f247ca4d217dc7bed40d2fd1b2e98a2f Mon Sep 17 00:00:00 2001 From: Bodil Stokke Date: Fri, 12 Apr 2019 18:46:33 +0100 Subject: [PATCH] Use TryFrom rather than panicking From implementations to do attribute conversion. Now that it's landed in stable and all. --- CHANGELOG.md | 11 ++ macros/src/html.rs | 4 +- typed-html/src/events.rs | 2 +- typed-html/src/lib.rs | 9 +- typed-html/src/types/class.rs | 57 +++--- typed-html/src/types/id.rs | 55 +++--- typed-html/src/types/spacedlist.rs | 187 +++++++++++--------- typed-html/src/types/spacedset.rs | 269 ++++++++++++++++------------- 8 files changed, 319 insertions(+), 275 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ab1f8e..9e7055f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Changed + +- Attribute type conversion is now using the newly stabilised `TryFrom` instead + of `From`, to avoid relying on panicking `From` implementations to detect + conversion errors, though the conversions inside the macro will still panic if + they fail. The appropriate `TryFrom` implementations have been added to + `Class`, `Id`, `SpacedList` and `SpacedSet`, and the corresponding `From` + implementations have been removed. + ## [0.2.0] - 2019-03-16 ### Added diff --git a/macros/src/html.rs b/macros/src/html.rs index cef7ce6..96b592b 100644 --- a/macros/src/html.rs +++ b/macros/src/html.rs @@ -233,7 +233,7 @@ impl Element { value => { let value = process_value(value); body.extend(quote!( - element.attrs.#key = Some(std::convert::Into::into(#value)); + element.attrs.#key = Some(std::convert::TryInto::try_into(#value).unwrap()); )); } } @@ -364,7 +364,7 @@ impl Element { value => { let value = process_value(value); set_attrs.extend(quote!( - element.attrs.#key = Some(std::convert::Into::into(#value)); + element.attrs.#key = Some(std::convert::TryInto::try_into(#value).unwrap()); )); } } diff --git a/typed-html/src/events.rs b/typed-html/src/events.rs index c4d1dcf..b543c93 100644 --- a/typed-html/src/events.rs +++ b/typed-html/src/events.rs @@ -64,7 +64,7 @@ macro_rules! declare_events_struct { $( .chain( iter::once(self.$name.take()) - .filter(|value| value.is_some()) + .filter(Option::is_some) .map(|value| (stringify!($name), value.unwrap())) ) )* diff --git a/typed-html/src/lib.rs b/typed-html/src/lib.rs index 0c868ee..440bb0d 100644 --- a/typed-html/src/lib.rs +++ b/typed-html/src/lib.rs @@ -89,11 +89,12 @@ //! ## Example //! //! ``` +//! # use std::convert::{TryFrom, TryInto}; //! # use typed_html::html; //! # use typed_html::dom::DOMTree; //! # use typed_html::types::{Class, SpacedSet}; -//! # fn main() { -//! let classList: SpacedSet = ["foo", "bar", "baz"].into(); +//! # fn main() -> Result<(), &'static str> { +//! let classList: SpacedSet = ["foo", "bar", "baz"].try_into()?; //! # let doc: DOMTree = //! html!( //!
@@ -101,11 +102,11 @@ //!
// uses From<[&str, &str, &str]> //!
// uses a variable in scope //!
//!
//! ) -//! # ;} +//! # ; Ok(()) } //! ``` //! //! # Generated Nodes diff --git a/typed-html/src/types/class.rs b/typed-html/src/types/class.rs index a1bb969..c12a6a2 100644 --- a/typed-html/src/types/class.rs +++ b/typed-html/src/types/class.rs @@ -1,3 +1,5 @@ +use std::borrow::Borrow; +use std::convert::TryFrom; use std::fmt::{Display, Error, Formatter}; use std::ops::Deref; use std::str::FromStr; @@ -17,40 +19,15 @@ use super::Id; pub struct Class(String); impl Class { - /// Construct a new class name from a string. - /// - /// Returns `Err` if the provided string is invalid. - pub fn try_new>(id: S) -> Result { - let id = id.into(); - { - let mut chars = id.chars(); - match chars.next() { - None => return Err("class name cannot be empty"), - Some(c) if !c.is_alphabetic() => { - return Err("class name must start with an alphabetic character") - } - _ => (), - } - for c in chars { - if !c.is_alphanumeric() && c != '_' && c != '-' && c != '.' { - return Err( - "class name can only contain alphanumerics, dash, dot and underscore", - ); - } - } - } - Ok(Class(id)) - } - /// Construct a new class name from a string. /// /// Panics if the provided string is invalid. - pub fn new>(id: S) -> Self { - let id = id.into(); - Self::try_new(id.clone()).unwrap_or_else(|err| { + pub fn new>(s: S) -> Self { + let s = s.borrow(); + Self::from_str(s).unwrap_or_else(|err| { panic!( "typed_html::types::Class: {:?} is not a valid class name: {}", - id, err + s, err ) }) } @@ -59,7 +36,20 @@ impl Class { impl FromStr for Class { type Err = &'static str; fn from_str(s: &str) -> Result { - Class::try_new(s) + let mut chars = s.chars(); + match chars.next() { + None => return Err("class name cannot be empty"), + Some(c) if !c.is_alphabetic() => { + return Err("class name must start with an alphabetic character") + } + _ => (), + } + for c in chars { + if !c.is_alphanumeric() && c != '_' && c != '-' && c != '.' { + return Err("class name can only contain alphanumerics, dash, dot and underscore"); + } + } + Ok(Class(s.to_string())) } } @@ -69,9 +59,10 @@ impl From for Class { } } -impl<'a> From<&'a str> for Class { - fn from(str: &'a str) -> Self { - Class::from_str(str).unwrap() +impl<'a> TryFrom<&'a str> for Class { + type Error = &'static str; + fn try_from(str: &'a str) -> Result { + Class::from_str(str) } } diff --git a/typed-html/src/types/id.rs b/typed-html/src/types/id.rs index 61e9b8d..8d0577b 100644 --- a/typed-html/src/types/id.rs +++ b/typed-html/src/types/id.rs @@ -1,3 +1,5 @@ +use std::borrow::Borrow; +use std::convert::TryFrom; use std::fmt::{Display, Error, Formatter}; use std::ops::Deref; use std::str::FromStr; @@ -17,35 +19,12 @@ use super::Class; pub struct Id(String); impl Id { - /// Construct a new ID from a string. - /// - /// Returns `Err` if the provided string is invalid. - pub fn try_new>(id: S) -> Result { - let id = id.into(); - { - let mut chars = id.chars(); - match chars.next() { - None => return Err("ID cannot be empty"), - Some(c) if !c.is_alphabetic() => { - return Err("ID must start with an alphabetic character") - } - _ => (), - } - for c in chars { - if !c.is_alphanumeric() && c != '_' && c != '-' && c != '.' { - return Err("ID can only contain alphanumerics, dash, dot and underscore"); - } - } - } - Ok(Id(id)) - } - /// Construct a new ID from a string. /// /// Panics if the provided string is invalid. - pub fn new>(id: S) -> Self { - let id = id.into(); - Self::try_new(id.clone()).unwrap_or_else(|err| { + pub fn new>(id: S) -> Self { + let id = id.borrow(); + Self::from_str(id).unwrap_or_else(|err| { panic!("typed_html::types::Id: {:?} is not a valid ID: {}", id, err) }) } @@ -53,14 +32,28 @@ impl Id { impl FromStr for Id { type Err = &'static str; - fn from_str(s: &str) -> Result { - Id::try_new(s) + fn from_str(id: &str) -> Result { + let mut chars = id.chars(); + match chars.next() { + None => return Err("ID cannot be empty"), + Some(c) if !c.is_alphabetic() => { + return Err("ID must start with an alphabetic character") + } + _ => (), + } + for c in chars { + if !c.is_alphanumeric() && c != '_' && c != '-' && c != '.' { + return Err("ID can only contain alphanumerics, dash, dot and underscore"); + } + } + Ok(Id(id.to_string())) } } -impl<'a> From<&'a str> for Id { - fn from(str: &'a str) -> Self { - Id::from_str(str).unwrap() +impl<'a> TryFrom<&'a str> for Id { + type Error = &'static str; + fn try_from(str: &'a str) -> Result { + Id::from_str(str) } } diff --git a/typed-html/src/types/spacedlist.rs b/typed-html/src/types/spacedlist.rs index 6cb57b6..464dee4 100644 --- a/typed-html/src/types/spacedlist.rs +++ b/typed-html/src/types/spacedlist.rs @@ -1,3 +1,4 @@ +use std::convert::{TryFrom, TryInto}; use std::fmt::{Debug, Display, Error, Formatter}; use std::iter::FromIterator; use std::ops::{Deref, DerefMut}; @@ -18,6 +19,24 @@ impl SpacedList { pub fn new() -> Self { SpacedList(Vec::new()) } + + /// Add a value to the `SpacedList`, converting it as necessary. + /// + /// Panics if the conversion fails. + pub fn add>(&mut self, value: T) + where + >::Error: Debug, + { + self.0.push(value.try_into().unwrap()) + } + + /// Add a value to the `SpacedList`, converting it as necessary. + /// + /// Returns an error if the conversion fails. + pub fn try_add>(&mut self, value: T) -> Result<(), >::Error> { + self.0.push(value.try_into()?); + Ok(()) + } } impl Default for SpacedList { @@ -44,12 +63,13 @@ impl<'a, A: 'a + Clone> FromIterator<&'a A> for SpacedList { } } -impl<'a, A: FromStr> From<&'a str> for SpacedList +impl<'a, A> TryFrom<&'a str> for SpacedList where - ::Err: Debug, + A: FromStr, { - fn from(s: &'a str) -> Self { - Self::from_iter(s.split_whitespace().map(|s| FromStr::from_str(s).unwrap())) + type Error = ::Err; + fn try_from(s: &'a str) -> Result { + s.split_whitespace().map(FromStr::from_str).collect() } } @@ -85,80 +105,84 @@ impl Debug for SpacedList { } } -impl<'a, 'b, A: FromStr> From<(&'a str, &'b str)> for SpacedList +impl<'a, 'b, A> TryFrom<(&'a str, &'b str)> for SpacedList where - ::Err: Debug, + A: FromStr, { - fn from(s: (&str, &str)) -> Self { + type Error = ::Err; + fn try_from(s: (&str, &str)) -> Result { let mut list = Self::new(); - list.push(FromStr::from_str(s.0).unwrap()); - list.push(FromStr::from_str(s.1).unwrap()); - list + list.push(FromStr::from_str(s.0)?); + list.push(FromStr::from_str(s.1)?); + Ok(list) } } -impl<'a, 'b, 'c, A: FromStr> From<(&'a str, &'b str, &'c str)> for SpacedList +impl<'a, 'b, 'c, A> TryFrom<(&'a str, &'b str, &'c str)> for SpacedList where - ::Err: Debug, + A: FromStr, { - fn from(s: (&str, &str, &str)) -> Self { + type Error = ::Err; + fn try_from(s: (&str, &str, &str)) -> Result { let mut list = Self::new(); - list.push(FromStr::from_str(s.0).unwrap()); - list.push(FromStr::from_str(s.1).unwrap()); - list.push(FromStr::from_str(s.2).unwrap()); - list + list.push(FromStr::from_str(s.0)?); + list.push(FromStr::from_str(s.1)?); + list.push(FromStr::from_str(s.2)?); + Ok(list) } } -impl<'a, 'b, 'c, 'd, A: FromStr> From<(&'a str, &'b str, &'c str, &'d str)> for SpacedList +impl<'a, 'b, 'c, 'd, A> TryFrom<(&'a str, &'b str, &'c str, &'d str)> for SpacedList where - ::Err: Debug, + A: FromStr, { - fn from(s: (&str, &str, &str, &str)) -> Self { + type Error = ::Err; + fn try_from(s: (&str, &str, &str, &str)) -> Result { let mut list = Self::new(); - list.push(FromStr::from_str(s.0).unwrap()); - list.push(FromStr::from_str(s.1).unwrap()); - list.push(FromStr::from_str(s.2).unwrap()); - list.push(FromStr::from_str(s.3).unwrap()); - list + list.push(FromStr::from_str(s.0)?); + list.push(FromStr::from_str(s.1)?); + list.push(FromStr::from_str(s.2)?); + list.push(FromStr::from_str(s.3)?); + Ok(list) } } -impl<'a, 'b, 'c, 'd, 'e, A: FromStr> From<(&'a str, &'b str, &'c str, &'d str, &'e str)> +impl<'a, 'b, 'c, 'd, 'e, A> TryFrom<(&'a str, &'b str, &'c str, &'d str, &'e str)> for SpacedList +where + A: FromStr, +{ + type Error = ::Err; + fn try_from(s: (&str, &str, &str, &str, &str)) -> Result { + let mut list = Self::new(); + list.push(FromStr::from_str(s.0)?); + list.push(FromStr::from_str(s.1)?); + list.push(FromStr::from_str(s.2)?); + list.push(FromStr::from_str(s.3)?); + list.push(FromStr::from_str(s.4)?); + Ok(list) + } +} + +impl<'a, 'b, 'c, 'd, 'e, 'f, A> TryFrom<(&'a str, &'b str, &'c str, &'d str, &'e str, &'f str)> for SpacedList where - ::Err: Debug, + A: FromStr, { - fn from(s: (&str, &str, &str, &str, &str)) -> Self { + type Error = ::Err; + fn try_from(s: (&str, &str, &str, &str, &str, &str)) -> Result { let mut list = Self::new(); - list.push(FromStr::from_str(s.0).unwrap()); - list.push(FromStr::from_str(s.1).unwrap()); - list.push(FromStr::from_str(s.2).unwrap()); - list.push(FromStr::from_str(s.3).unwrap()); - list.push(FromStr::from_str(s.4).unwrap()); - list + list.push(FromStr::from_str(s.0)?); + list.push(FromStr::from_str(s.1)?); + list.push(FromStr::from_str(s.2)?); + list.push(FromStr::from_str(s.3)?); + list.push(FromStr::from_str(s.4)?); + list.push(FromStr::from_str(s.5)?); + Ok(list) } } -impl<'a, 'b, 'c, 'd, 'e, 'f, A: FromStr> - From<(&'a str, &'b str, &'c str, &'d str, &'e str, &'f str)> for SpacedList -where - ::Err: Debug, -{ - fn from(s: (&str, &str, &str, &str, &str, &str)) -> Self { - let mut list = Self::new(); - list.push(FromStr::from_str(s.0).unwrap()); - list.push(FromStr::from_str(s.1).unwrap()); - list.push(FromStr::from_str(s.2).unwrap()); - list.push(FromStr::from_str(s.3).unwrap()); - list.push(FromStr::from_str(s.4).unwrap()); - list.push(FromStr::from_str(s.5).unwrap()); - list - } -} - -impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, A: FromStr> - From<( +impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, A> + TryFrom<( &'a str, &'b str, &'c str, @@ -168,23 +192,24 @@ impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, A: FromStr> &'g str, )> for SpacedList where - ::Err: Debug, + A: FromStr, { - fn from(s: (&str, &str, &str, &str, &str, &str, &str)) -> Self { + type Error = ::Err; + fn try_from(s: (&str, &str, &str, &str, &str, &str, &str)) -> Result { let mut list = Self::new(); - list.push(FromStr::from_str(s.0).unwrap()); - list.push(FromStr::from_str(s.1).unwrap()); - list.push(FromStr::from_str(s.2).unwrap()); - list.push(FromStr::from_str(s.3).unwrap()); - list.push(FromStr::from_str(s.4).unwrap()); - list.push(FromStr::from_str(s.5).unwrap()); - list.push(FromStr::from_str(s.6).unwrap()); - list + list.push(FromStr::from_str(s.0)?); + list.push(FromStr::from_str(s.1)?); + list.push(FromStr::from_str(s.2)?); + list.push(FromStr::from_str(s.3)?); + list.push(FromStr::from_str(s.4)?); + list.push(FromStr::from_str(s.5)?); + list.push(FromStr::from_str(s.6)?); + Ok(list) } } -impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, A: FromStr> - From<( +impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, A> + TryFrom<( &'a str, &'b str, &'c str, @@ -195,30 +220,32 @@ impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, A: FromStr> &'h str, )> for SpacedList where - ::Err: Debug, + A: FromStr, { - fn from(s: (&str, &str, &str, &str, &str, &str, &str, &str)) -> Self { + type Error = ::Err; + fn try_from(s: (&str, &str, &str, &str, &str, &str, &str, &str)) -> Result { let mut list = Self::new(); - list.push(FromStr::from_str(s.0).unwrap()); - list.push(FromStr::from_str(s.1).unwrap()); - list.push(FromStr::from_str(s.2).unwrap()); - list.push(FromStr::from_str(s.3).unwrap()); - list.push(FromStr::from_str(s.4).unwrap()); - list.push(FromStr::from_str(s.5).unwrap()); - list.push(FromStr::from_str(s.6).unwrap()); - list.push(FromStr::from_str(s.7).unwrap()); - list + list.push(FromStr::from_str(s.0)?); + list.push(FromStr::from_str(s.1)?); + list.push(FromStr::from_str(s.2)?); + list.push(FromStr::from_str(s.3)?); + list.push(FromStr::from_str(s.4)?); + list.push(FromStr::from_str(s.5)?); + list.push(FromStr::from_str(s.6)?); + list.push(FromStr::from_str(s.7)?); + Ok(list) } } macro_rules! spacedlist_from_array { ($num:tt) => { - impl<'a, A: FromStr> From<[&'a str; $num]> for SpacedList + impl<'a, A> TryFrom<[&'a str; $num]> for SpacedList where - ::Err: Debug, + A: FromStr, { - fn from(s: [&str; $num]) -> Self { - Self::from_iter(s.into_iter().map(|s| FromStr::from_str(*s).unwrap())) + type Error = ::Err; + fn try_from(s: [&str; $num]) -> Result { + s.into_iter().map(|s| FromStr::from_str(*s)).collect() } } }; diff --git a/typed-html/src/types/spacedset.rs b/typed-html/src/types/spacedset.rs index 803995b..b497d8e 100644 --- a/typed-html/src/types/spacedset.rs +++ b/typed-html/src/types/spacedset.rs @@ -1,4 +1,5 @@ use std::collections::BTreeSet; +use std::convert::{TryFrom, TryInto}; use std::fmt::{Debug, Display, Error, Formatter}; use std::iter::FromIterator; use std::ops::{Deref, DerefMut}; @@ -12,18 +13,18 @@ use std::str::FromStr; /// # Examples /// /// ``` -/// # use std::convert::From; +/// # use std::convert::{TryFrom, TryInto}; /// use typed_html::types::{Class, SpacedSet}; /// -/// # fn main() { -/// let classList: SpacedSet = "foo bar baz".into(); -/// let classList: SpacedSet = ["foo", "bar", "baz"].into(); -/// let classList: SpacedSet = ("foo", "bar", "baz").into(); +/// # fn main() -> Result<(), &'static str> { +/// let classList: SpacedSet = "foo bar baz".try_into()?; +/// let classList: SpacedSet = ["foo", "bar", "baz"].try_into()?; +/// let classList: SpacedSet = ("foo", "bar", "baz").try_into()?; /// -/// let classList1: SpacedSet = "foo bar foo".into(); -/// let classList2: SpacedSet = "bar foo bar".into(); +/// let classList1: SpacedSet = "foo bar foo".try_into()?; +/// let classList2: SpacedSet = "bar foo bar".try_into()?; /// assert_eq!(classList1, classList2); -/// # } +/// # Ok(()) } /// ``` #[derive(Clone, PartialEq, Eq, Hash)] pub struct SpacedSet(BTreeSet); @@ -34,9 +35,21 @@ impl SpacedSet { SpacedSet(BTreeSet::new()) } - /// Add a value to the `SpacedSet`. - pub fn add>(&mut self, value: T) -> bool { - self.0.insert(value.into()) + /// Add a value to the `SpacedSet`, converting it as necessary. + /// + /// Panics if the conversion fails. + pub fn add>(&mut self, value: T) -> bool + where + >::Error: Debug, + { + self.0.insert(value.try_into().unwrap()) + } + + /// Add a value to the `SpacedSet`, converting it as necessary. + /// + /// Returns an error if the conversion fails. + pub fn try_add>(&mut self, value: T) -> Result>::Error> { + Ok(self.0.insert(value.try_into()?)) } } @@ -77,12 +90,13 @@ where } } -impl<'a, A: Ord + FromStr> From<&'a str> for SpacedSet +impl<'a, A> TryFrom<&'a str> for SpacedSet where - ::Err: Debug, + A: Ord + FromStr, { - fn from(s: &'a str) -> Self { - Self::from_iter(s.split_whitespace().map(|s| FromStr::from_str(s).unwrap())) + type Error = ::Err; + fn try_from(s: &'a str) -> Result { + s.split_whitespace().map(FromStr::from_str).collect() } } @@ -118,80 +132,84 @@ impl Debug for SpacedSet { } } -impl<'a, 'b, A: Ord + FromStr> From<(&'a str, &'b str)> for SpacedSet +impl<'a, 'b, A> TryFrom<(&'a str, &'b str)> for SpacedSet where - ::Err: Debug, + A: Ord + FromStr, { - fn from(s: (&str, &str)) -> Self { + type Error = ::Err; + fn try_from(s: (&str, &str)) -> Result { let mut list = Self::new(); - list.insert(FromStr::from_str(s.0).unwrap()); - list.insert(FromStr::from_str(s.1).unwrap()); - list + list.insert(FromStr::from_str(s.0)?); + list.insert(FromStr::from_str(s.1)?); + Ok(list) } } -impl<'a, 'b, 'c, A: Ord + FromStr> From<(&'a str, &'b str, &'c str)> for SpacedSet +impl<'a, 'b, 'c, A> TryFrom<(&'a str, &'b str, &'c str)> for SpacedSet where - ::Err: Debug, + A: Ord + FromStr, { - fn from(s: (&str, &str, &str)) -> Self { + type Error = ::Err; + fn try_from(s: (&str, &str, &str)) -> Result { let mut list = Self::new(); - list.insert(FromStr::from_str(s.0).unwrap()); - list.insert(FromStr::from_str(s.1).unwrap()); - list.insert(FromStr::from_str(s.2).unwrap()); - list + list.insert(FromStr::from_str(s.0)?); + list.insert(FromStr::from_str(s.1)?); + list.insert(FromStr::from_str(s.2)?); + Ok(list) } } -impl<'a, 'b, 'c, 'd, A: Ord + FromStr> From<(&'a str, &'b str, &'c str, &'d str)> for SpacedSet +impl<'a, 'b, 'c, 'd, A> TryFrom<(&'a str, &'b str, &'c str, &'d str)> for SpacedSet where - ::Err: Debug, + A: Ord + FromStr, { - fn from(s: (&str, &str, &str, &str)) -> Self { + type Error = ::Err; + fn try_from(s: (&str, &str, &str, &str)) -> Result { let mut list = Self::new(); - list.insert(FromStr::from_str(s.0).unwrap()); - list.insert(FromStr::from_str(s.1).unwrap()); - list.insert(FromStr::from_str(s.2).unwrap()); - list.insert(FromStr::from_str(s.3).unwrap()); - list + list.insert(FromStr::from_str(s.0)?); + list.insert(FromStr::from_str(s.1)?); + list.insert(FromStr::from_str(s.2)?); + list.insert(FromStr::from_str(s.3)?); + Ok(list) } } -impl<'a, 'b, 'c, 'd, 'e, A: Ord + FromStr> From<(&'a str, &'b str, &'c str, &'d str, &'e str)> +impl<'a, 'b, 'c, 'd, 'e, A> TryFrom<(&'a str, &'b str, &'c str, &'d str, &'e str)> for SpacedSet +where + A: Ord + FromStr, +{ + type Error = ::Err; + fn try_from(s: (&str, &str, &str, &str, &str)) -> Result { + let mut list = Self::new(); + list.insert(FromStr::from_str(s.0)?); + list.insert(FromStr::from_str(s.1)?); + list.insert(FromStr::from_str(s.2)?); + list.insert(FromStr::from_str(s.3)?); + list.insert(FromStr::from_str(s.4)?); + Ok(list) + } +} + +impl<'a, 'b, 'c, 'd, 'e, 'f, A> TryFrom<(&'a str, &'b str, &'c str, &'d str, &'e str, &'f str)> for SpacedSet where - ::Err: Debug, + A: Ord + FromStr, { - fn from(s: (&str, &str, &str, &str, &str)) -> Self { + type Error = ::Err; + fn try_from(s: (&str, &str, &str, &str, &str, &str)) -> Result { let mut list = Self::new(); - list.insert(FromStr::from_str(s.0).unwrap()); - list.insert(FromStr::from_str(s.1).unwrap()); - list.insert(FromStr::from_str(s.2).unwrap()); - list.insert(FromStr::from_str(s.3).unwrap()); - list.insert(FromStr::from_str(s.4).unwrap()); - list + list.insert(FromStr::from_str(s.0)?); + list.insert(FromStr::from_str(s.1)?); + list.insert(FromStr::from_str(s.2)?); + list.insert(FromStr::from_str(s.3)?); + list.insert(FromStr::from_str(s.4)?); + list.insert(FromStr::from_str(s.5)?); + Ok(list) } } -impl<'a, 'b, 'c, 'd, 'e, 'f, A: Ord + FromStr> - From<(&'a str, &'b str, &'c str, &'d str, &'e str, &'f str)> for SpacedSet -where - ::Err: Debug, -{ - fn from(s: (&str, &str, &str, &str, &str, &str)) -> Self { - let mut list = Self::new(); - list.insert(FromStr::from_str(s.0).unwrap()); - list.insert(FromStr::from_str(s.1).unwrap()); - list.insert(FromStr::from_str(s.2).unwrap()); - list.insert(FromStr::from_str(s.3).unwrap()); - list.insert(FromStr::from_str(s.4).unwrap()); - list.insert(FromStr::from_str(s.5).unwrap()); - list - } -} - -impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, A: Ord + FromStr> - From<( +impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, A> + TryFrom<( &'a str, &'b str, &'c str, @@ -201,23 +219,24 @@ impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, A: Ord + FromStr> &'g str, )> for SpacedSet where - ::Err: Debug, + A: Ord + FromStr, { - fn from(s: (&str, &str, &str, &str, &str, &str, &str)) -> Self { + type Error = ::Err; + fn try_from(s: (&str, &str, &str, &str, &str, &str, &str)) -> Result { let mut list = Self::new(); - list.insert(FromStr::from_str(s.0).unwrap()); - list.insert(FromStr::from_str(s.1).unwrap()); - list.insert(FromStr::from_str(s.2).unwrap()); - list.insert(FromStr::from_str(s.3).unwrap()); - list.insert(FromStr::from_str(s.4).unwrap()); - list.insert(FromStr::from_str(s.5).unwrap()); - list.insert(FromStr::from_str(s.6).unwrap()); - list + list.insert(FromStr::from_str(s.0)?); + list.insert(FromStr::from_str(s.1)?); + list.insert(FromStr::from_str(s.2)?); + list.insert(FromStr::from_str(s.3)?); + list.insert(FromStr::from_str(s.4)?); + list.insert(FromStr::from_str(s.5)?); + list.insert(FromStr::from_str(s.6)?); + Ok(list) } } -impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, A: Ord + FromStr> - From<( +impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, A> + TryFrom<( &'a str, &'b str, &'c str, @@ -228,63 +247,65 @@ impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, A: Ord + FromStr> &'h str, )> for SpacedSet where - ::Err: Debug, + A: Ord + FromStr, { - fn from(s: (&str, &str, &str, &str, &str, &str, &str, &str)) -> Self { + type Error = ::Err; + fn try_from(s: (&str, &str, &str, &str, &str, &str, &str, &str)) -> Result { let mut list = Self::new(); - list.insert(FromStr::from_str(s.0).unwrap()); - list.insert(FromStr::from_str(s.1).unwrap()); - list.insert(FromStr::from_str(s.2).unwrap()); - list.insert(FromStr::from_str(s.3).unwrap()); - list.insert(FromStr::from_str(s.4).unwrap()); - list.insert(FromStr::from_str(s.5).unwrap()); - list.insert(FromStr::from_str(s.6).unwrap()); - list.insert(FromStr::from_str(s.7).unwrap()); - list + list.insert(FromStr::from_str(s.0)?); + list.insert(FromStr::from_str(s.1)?); + list.insert(FromStr::from_str(s.2)?); + list.insert(FromStr::from_str(s.3)?); + list.insert(FromStr::from_str(s.4)?); + list.insert(FromStr::from_str(s.5)?); + list.insert(FromStr::from_str(s.6)?); + list.insert(FromStr::from_str(s.7)?); + Ok(list) } } -macro_rules! spacedlist_from_array { +macro_rules! spacedset_from_array { ($num:tt) => { - impl<'a, A: Ord + FromStr> From<[&'a str; $num]> for SpacedSet + impl<'a, A> TryFrom<[&'a str; $num]> for SpacedSet where - ::Err: Debug, + A: Ord + FromStr, { - fn from(s: [&str; $num]) -> Self { - Self::from_iter(s.into_iter().map(|s| FromStr::from_str(*s).unwrap())) + type Error = ::Err; + fn try_from(s: [&str; $num]) -> Result { + s.into_iter().map(|s| FromStr::from_str(*s)).collect() } } }; } -spacedlist_from_array!(1); -spacedlist_from_array!(2); -spacedlist_from_array!(3); -spacedlist_from_array!(4); -spacedlist_from_array!(5); -spacedlist_from_array!(6); -spacedlist_from_array!(7); -spacedlist_from_array!(8); -spacedlist_from_array!(9); -spacedlist_from_array!(10); -spacedlist_from_array!(11); -spacedlist_from_array!(12); -spacedlist_from_array!(13); -spacedlist_from_array!(14); -spacedlist_from_array!(15); -spacedlist_from_array!(16); -spacedlist_from_array!(17); -spacedlist_from_array!(18); -spacedlist_from_array!(19); -spacedlist_from_array!(20); -spacedlist_from_array!(21); -spacedlist_from_array!(22); -spacedlist_from_array!(23); -spacedlist_from_array!(24); -spacedlist_from_array!(25); -spacedlist_from_array!(26); -spacedlist_from_array!(27); -spacedlist_from_array!(28); -spacedlist_from_array!(29); -spacedlist_from_array!(30); -spacedlist_from_array!(31); -spacedlist_from_array!(32); +spacedset_from_array!(1); +spacedset_from_array!(2); +spacedset_from_array!(3); +spacedset_from_array!(4); +spacedset_from_array!(5); +spacedset_from_array!(6); +spacedset_from_array!(7); +spacedset_from_array!(8); +spacedset_from_array!(9); +spacedset_from_array!(10); +spacedset_from_array!(11); +spacedset_from_array!(12); +spacedset_from_array!(13); +spacedset_from_array!(14); +spacedset_from_array!(15); +spacedset_from_array!(16); +spacedset_from_array!(17); +spacedset_from_array!(18); +spacedset_from_array!(19); +spacedset_from_array!(20); +spacedset_from_array!(21); +spacedset_from_array!(22); +spacedset_from_array!(23); +spacedset_from_array!(24); +spacedset_from_array!(25); +spacedset_from_array!(26); +spacedset_from_array!(27); +spacedset_from_array!(28); +spacedset_from_array!(29); +spacedset_from_array!(30); +spacedset_from_array!(31); +spacedset_from_array!(32);