Use TryFrom rather than panicking From implementations to do attribute conversion.
Now that it's landed in stable and all.
This commit is contained in:
parent
36c95b0b8e
commit
5334d783f2
11
CHANGELOG.md
11
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
|
||||
|
|
|
@ -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());
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()))
|
||||
)
|
||||
)*
|
||||
|
|
|
@ -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<Class> = ["foo", "bar", "baz"].into();
|
||||
//! # fn main() -> Result<(), &'static str> {
|
||||
//! let classList: SpacedSet<Class> = ["foo", "bar", "baz"].try_into()?;
|
||||
//! # let doc: DOMTree<String> =
|
||||
//! html!(
|
||||
//! <div>
|
||||
|
@ -101,11 +102,11 @@
|
|||
//! <div class=["foo", "bar", "baz"] /> // uses From<[&str, &str, &str]>
|
||||
//! <div class=classList /> // uses a variable in scope
|
||||
//! <div class={ // evaluates a code block
|
||||
//! SpacedSet::from(["foo", "bar", "baz"])
|
||||
//! SpacedSet::try_from(["foo", "bar", "baz"])?
|
||||
//! } />
|
||||
//! </div>
|
||||
//! )
|
||||
//! # ;}
|
||||
//! # ; Ok(()) }
|
||||
//! ```
|
||||
//!
|
||||
//! # Generated Nodes
|
||||
|
|
|
@ -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<S: Into<String>>(id: S) -> Result<Self, &'static str> {
|
||||
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<S: Into<String>>(id: S) -> Self {
|
||||
let id = id.into();
|
||||
Self::try_new(id.clone()).unwrap_or_else(|err| {
|
||||
pub fn new<S: Borrow<str>>(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<Self, Self::Err> {
|
||||
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<Id> 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<Self, Self::Error> {
|
||||
Class::from_str(str)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<S: Into<String>>(id: S) -> Result<Self, &'static str> {
|
||||
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<S: Into<String>>(id: S) -> Self {
|
||||
let id = id.into();
|
||||
Self::try_new(id.clone()).unwrap_or_else(|err| {
|
||||
pub fn new<S: Borrow<str>>(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<Self, Self::Err> {
|
||||
Id::try_new(s)
|
||||
fn from_str(id: &str) -> Result<Self, Self::Err> {
|
||||
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<Self, Self::Error> {
|
||||
Id::from_str(str)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<A> SpacedList<A> {
|
|||
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<T: TryInto<A>>(&mut self, value: T)
|
||||
where
|
||||
<T as TryInto<A>>::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<T: TryInto<A>>(&mut self, value: T) -> Result<(), <T as TryInto<A>>::Error> {
|
||||
self.0.push(value.try_into()?);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> Default for SpacedList<A> {
|
||||
|
@ -44,12 +63,13 @@ impl<'a, A: 'a + Clone> FromIterator<&'a A> for SpacedList<A> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, A: FromStr> From<&'a str> for SpacedList<A>
|
||||
impl<'a, A> TryFrom<&'a str> for SpacedList<A>
|
||||
where
|
||||
<A as FromStr>::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 = <A as FromStr>::Err;
|
||||
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
|
||||
s.split_whitespace().map(FromStr::from_str).collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,80 +105,84 @@ impl<A: Debug> Debug for SpacedList<A> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, A: FromStr> From<(&'a str, &'b str)> for SpacedList<A>
|
||||
impl<'a, 'b, A> TryFrom<(&'a str, &'b str)> for SpacedList<A>
|
||||
where
|
||||
<A as FromStr>::Err: Debug,
|
||||
A: FromStr,
|
||||
{
|
||||
fn from(s: (&str, &str)) -> Self {
|
||||
type Error = <A as FromStr>::Err;
|
||||
fn try_from(s: (&str, &str)) -> Result<Self, Self::Error> {
|
||||
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<A>
|
||||
impl<'a, 'b, 'c, A> TryFrom<(&'a str, &'b str, &'c str)> for SpacedList<A>
|
||||
where
|
||||
<A as FromStr>::Err: Debug,
|
||||
A: FromStr,
|
||||
{
|
||||
fn from(s: (&str, &str, &str)) -> Self {
|
||||
type Error = <A as FromStr>::Err;
|
||||
fn try_from(s: (&str, &str, &str)) -> Result<Self, Self::Error> {
|
||||
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<A>
|
||||
impl<'a, 'b, 'c, 'd, A> TryFrom<(&'a str, &'b str, &'c str, &'d str)> for SpacedList<A>
|
||||
where
|
||||
<A as FromStr>::Err: Debug,
|
||||
A: FromStr,
|
||||
{
|
||||
fn from(s: (&str, &str, &str, &str)) -> Self {
|
||||
type Error = <A as FromStr>::Err;
|
||||
fn try_from(s: (&str, &str, &str, &str)) -> Result<Self, Self::Error> {
|
||||
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<A>
|
||||
where
|
||||
A: FromStr,
|
||||
{
|
||||
type Error = <A as FromStr>::Err;
|
||||
fn try_from(s: (&str, &str, &str, &str, &str)) -> Result<Self, Self::Error> {
|
||||
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<A>
|
||||
where
|
||||
<A as FromStr>::Err: Debug,
|
||||
A: FromStr,
|
||||
{
|
||||
fn from(s: (&str, &str, &str, &str, &str)) -> Self {
|
||||
type Error = <A as FromStr>::Err;
|
||||
fn try_from(s: (&str, &str, &str, &str, &str, &str)) -> Result<Self, Self::Error> {
|
||||
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<A>
|
||||
where
|
||||
<A as FromStr>::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<A>
|
||||
where
|
||||
<A as FromStr>::Err: Debug,
|
||||
A: FromStr,
|
||||
{
|
||||
fn from(s: (&str, &str, &str, &str, &str, &str, &str)) -> Self {
|
||||
type Error = <A as FromStr>::Err;
|
||||
fn try_from(s: (&str, &str, &str, &str, &str, &str, &str)) -> Result<Self, Self::Error> {
|
||||
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<A>
|
||||
where
|
||||
<A as FromStr>::Err: Debug,
|
||||
A: FromStr,
|
||||
{
|
||||
fn from(s: (&str, &str, &str, &str, &str, &str, &str, &str)) -> Self {
|
||||
type Error = <A as FromStr>::Err;
|
||||
fn try_from(s: (&str, &str, &str, &str, &str, &str, &str, &str)) -> Result<Self, Self::Error> {
|
||||
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<A>
|
||||
impl<'a, A> TryFrom<[&'a str; $num]> for SpacedList<A>
|
||||
where
|
||||
<A as FromStr>::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 = <A as FromStr>::Err;
|
||||
fn try_from(s: [&str; $num]) -> Result<Self, Self::Error> {
|
||||
s.into_iter().map(|s| FromStr::from_str(*s)).collect()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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<Class> = "foo bar baz".into();
|
||||
/// let classList: SpacedSet<Class> = ["foo", "bar", "baz"].into();
|
||||
/// let classList: SpacedSet<Class> = ("foo", "bar", "baz").into();
|
||||
/// # fn main() -> Result<(), &'static str> {
|
||||
/// let classList: SpacedSet<Class> = "foo bar baz".try_into()?;
|
||||
/// let classList: SpacedSet<Class> = ["foo", "bar", "baz"].try_into()?;
|
||||
/// let classList: SpacedSet<Class> = ("foo", "bar", "baz").try_into()?;
|
||||
///
|
||||
/// let classList1: SpacedSet<Class> = "foo bar foo".into();
|
||||
/// let classList2: SpacedSet<Class> = "bar foo bar".into();
|
||||
/// let classList1: SpacedSet<Class> = "foo bar foo".try_into()?;
|
||||
/// let classList2: SpacedSet<Class> = "bar foo bar".try_into()?;
|
||||
/// assert_eq!(classList1, classList2);
|
||||
/// # }
|
||||
/// # Ok(()) }
|
||||
/// ```
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct SpacedSet<A: Ord>(BTreeSet<A>);
|
||||
|
@ -34,9 +35,21 @@ impl<A: Ord> SpacedSet<A> {
|
|||
SpacedSet(BTreeSet::new())
|
||||
}
|
||||
|
||||
/// Add a value to the `SpacedSet`.
|
||||
pub fn add<T: Into<A>>(&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<T: TryInto<A>>(&mut self, value: T) -> bool
|
||||
where
|
||||
<T as TryInto<A>>::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<T: TryInto<A>>(&mut self, value: T) -> Result<bool, <T as TryInto<A>>::Error> {
|
||||
Ok(self.0.insert(value.try_into()?))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,12 +90,13 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, A: Ord + FromStr> From<&'a str> for SpacedSet<A>
|
||||
impl<'a, A> TryFrom<&'a str> for SpacedSet<A>
|
||||
where
|
||||
<A as FromStr>::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 = <A as FromStr>::Err;
|
||||
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
|
||||
s.split_whitespace().map(FromStr::from_str).collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,80 +132,84 @@ impl<A: Ord + Debug> Debug for SpacedSet<A> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, A: Ord + FromStr> From<(&'a str, &'b str)> for SpacedSet<A>
|
||||
impl<'a, 'b, A> TryFrom<(&'a str, &'b str)> for SpacedSet<A>
|
||||
where
|
||||
<A as FromStr>::Err: Debug,
|
||||
A: Ord + FromStr,
|
||||
{
|
||||
fn from(s: (&str, &str)) -> Self {
|
||||
type Error = <A as FromStr>::Err;
|
||||
fn try_from(s: (&str, &str)) -> Result<Self, Self::Error> {
|
||||
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<A>
|
||||
impl<'a, 'b, 'c, A> TryFrom<(&'a str, &'b str, &'c str)> for SpacedSet<A>
|
||||
where
|
||||
<A as FromStr>::Err: Debug,
|
||||
A: Ord + FromStr,
|
||||
{
|
||||
fn from(s: (&str, &str, &str)) -> Self {
|
||||
type Error = <A as FromStr>::Err;
|
||||
fn try_from(s: (&str, &str, &str)) -> Result<Self, Self::Error> {
|
||||
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<A>
|
||||
impl<'a, 'b, 'c, 'd, A> TryFrom<(&'a str, &'b str, &'c str, &'d str)> for SpacedSet<A>
|
||||
where
|
||||
<A as FromStr>::Err: Debug,
|
||||
A: Ord + FromStr,
|
||||
{
|
||||
fn from(s: (&str, &str, &str, &str)) -> Self {
|
||||
type Error = <A as FromStr>::Err;
|
||||
fn try_from(s: (&str, &str, &str, &str)) -> Result<Self, Self::Error> {
|
||||
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<A>
|
||||
where
|
||||
A: Ord + FromStr,
|
||||
{
|
||||
type Error = <A as FromStr>::Err;
|
||||
fn try_from(s: (&str, &str, &str, &str, &str)) -> Result<Self, Self::Error> {
|
||||
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<A>
|
||||
where
|
||||
<A as FromStr>::Err: Debug,
|
||||
A: Ord + FromStr,
|
||||
{
|
||||
fn from(s: (&str, &str, &str, &str, &str)) -> Self {
|
||||
type Error = <A as FromStr>::Err;
|
||||
fn try_from(s: (&str, &str, &str, &str, &str, &str)) -> Result<Self, Self::Error> {
|
||||
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<A>
|
||||
where
|
||||
<A as FromStr>::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<A>
|
||||
where
|
||||
<A as FromStr>::Err: Debug,
|
||||
A: Ord + FromStr,
|
||||
{
|
||||
fn from(s: (&str, &str, &str, &str, &str, &str, &str)) -> Self {
|
||||
type Error = <A as FromStr>::Err;
|
||||
fn try_from(s: (&str, &str, &str, &str, &str, &str, &str)) -> Result<Self, Self::Error> {
|
||||
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<A>
|
||||
where
|
||||
<A as FromStr>::Err: Debug,
|
||||
A: Ord + FromStr,
|
||||
{
|
||||
fn from(s: (&str, &str, &str, &str, &str, &str, &str, &str)) -> Self {
|
||||
type Error = <A as FromStr>::Err;
|
||||
fn try_from(s: (&str, &str, &str, &str, &str, &str, &str, &str)) -> Result<Self, Self::Error> {
|
||||
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<A>
|
||||
impl<'a, A> TryFrom<[&'a str; $num]> for SpacedSet<A>
|
||||
where
|
||||
<A as FromStr>::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 = <A as FromStr>::Err;
|
||||
fn try_from(s: [&str; $num]) -> Result<Self, Self::Error> {
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue