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
|
and this project adheres to [Semantic
|
||||||
Versioning](http://semver.org/spec/v2.0.0.html).
|
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
|
## [0.2.0] - 2019-03-16
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -233,7 +233,7 @@ impl Element {
|
||||||
value => {
|
value => {
|
||||||
let value = process_value(value);
|
let value = process_value(value);
|
||||||
body.extend(quote!(
|
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 => {
|
value => {
|
||||||
let value = process_value(value);
|
let value = process_value(value);
|
||||||
set_attrs.extend(quote!(
|
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(
|
.chain(
|
||||||
iter::once(self.$name.take())
|
iter::once(self.$name.take())
|
||||||
.filter(|value| value.is_some())
|
.filter(Option::is_some)
|
||||||
.map(|value| (stringify!($name), value.unwrap()))
|
.map(|value| (stringify!($name), value.unwrap()))
|
||||||
)
|
)
|
||||||
)*
|
)*
|
||||||
|
|
|
@ -89,11 +89,12 @@
|
||||||
//! ## Example
|
//! ## Example
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
|
//! # use std::convert::{TryFrom, TryInto};
|
||||||
//! # use typed_html::html;
|
//! # use typed_html::html;
|
||||||
//! # use typed_html::dom::DOMTree;
|
//! # use typed_html::dom::DOMTree;
|
||||||
//! # use typed_html::types::{Class, SpacedSet};
|
//! # use typed_html::types::{Class, SpacedSet};
|
||||||
//! # fn main() {
|
//! # fn main() -> Result<(), &'static str> {
|
||||||
//! let classList: SpacedSet<Class> = ["foo", "bar", "baz"].into();
|
//! let classList: SpacedSet<Class> = ["foo", "bar", "baz"].try_into()?;
|
||||||
//! # let doc: DOMTree<String> =
|
//! # let doc: DOMTree<String> =
|
||||||
//! html!(
|
//! html!(
|
||||||
//! <div>
|
//! <div>
|
||||||
|
@ -101,11 +102,11 @@
|
||||||
//! <div class=["foo", "bar", "baz"] /> // uses From<[&str, &str, &str]>
|
//! <div class=["foo", "bar", "baz"] /> // uses From<[&str, &str, &str]>
|
||||||
//! <div class=classList /> // uses a variable in scope
|
//! <div class=classList /> // uses a variable in scope
|
||||||
//! <div class={ // evaluates a code block
|
//! <div class={ // evaluates a code block
|
||||||
//! SpacedSet::from(["foo", "bar", "baz"])
|
//! SpacedSet::try_from(["foo", "bar", "baz"])?
|
||||||
//! } />
|
//! } />
|
||||||
//! </div>
|
//! </div>
|
||||||
//! )
|
//! )
|
||||||
//! # ;}
|
//! # ; Ok(()) }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! # Generated Nodes
|
//! # Generated Nodes
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::borrow::Borrow;
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::fmt::{Display, Error, Formatter};
|
use std::fmt::{Display, Error, Formatter};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
@ -19,11 +21,22 @@ pub struct Class(String);
|
||||||
impl Class {
|
impl Class {
|
||||||
/// Construct a new class name from a string.
|
/// Construct a new class name from a string.
|
||||||
///
|
///
|
||||||
/// Returns `Err` if the provided string is invalid.
|
/// Panics if the provided string is invalid.
|
||||||
pub fn try_new<S: Into<String>>(id: S) -> Result<Self, &'static str> {
|
pub fn new<S: Borrow<str>>(s: S) -> Self {
|
||||||
let id = id.into();
|
let s = s.borrow();
|
||||||
{
|
Self::from_str(s).unwrap_or_else(|err| {
|
||||||
let mut chars = id.chars();
|
panic!(
|
||||||
|
"typed_html::types::Class: {:?} is not a valid class name: {}",
|
||||||
|
s, err
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Class {
|
||||||
|
type Err = &'static str;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let mut chars = s.chars();
|
||||||
match chars.next() {
|
match chars.next() {
|
||||||
None => return Err("class name cannot be empty"),
|
None => return Err("class name cannot be empty"),
|
||||||
Some(c) if !c.is_alphabetic() => {
|
Some(c) if !c.is_alphabetic() => {
|
||||||
|
@ -33,33 +46,10 @@ impl Class {
|
||||||
}
|
}
|
||||||
for c in chars {
|
for c in chars {
|
||||||
if !c.is_alphanumeric() && c != '_' && c != '-' && c != '.' {
|
if !c.is_alphanumeric() && c != '_' && c != '-' && c != '.' {
|
||||||
return Err(
|
return Err("class name can only contain alphanumerics, dash, dot and underscore");
|
||||||
"class name can only contain alphanumerics, dash, dot and underscore",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Ok(Class(s.to_string()))
|
||||||
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| {
|
|
||||||
panic!(
|
|
||||||
"typed_html::types::Class: {:?} is not a valid class name: {}",
|
|
||||||
id, err
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for Class {
|
|
||||||
type Err = &'static str;
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
Class::try_new(s)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,9 +59,10 @@ impl From<Id> for Class {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a str> for Class {
|
impl<'a> TryFrom<&'a str> for Class {
|
||||||
fn from(str: &'a str) -> Self {
|
type Error = &'static str;
|
||||||
Class::from_str(str).unwrap()
|
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::fmt::{Display, Error, Formatter};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
@ -19,10 +21,18 @@ pub struct Id(String);
|
||||||
impl Id {
|
impl Id {
|
||||||
/// Construct a new ID from a string.
|
/// Construct a new ID from a string.
|
||||||
///
|
///
|
||||||
/// Returns `Err` if the provided string is invalid.
|
/// Panics if the provided string is invalid.
|
||||||
pub fn try_new<S: Into<String>>(id: S) -> Result<Self, &'static str> {
|
pub fn new<S: Borrow<str>>(id: S) -> Self {
|
||||||
let id = id.into();
|
let id = id.borrow();
|
||||||
{
|
Self::from_str(id).unwrap_or_else(|err| {
|
||||||
|
panic!("typed_html::types::Id: {:?} is not a valid ID: {}", id, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Id {
|
||||||
|
type Err = &'static str;
|
||||||
|
fn from_str(id: &str) -> Result<Self, Self::Err> {
|
||||||
let mut chars = id.chars();
|
let mut chars = id.chars();
|
||||||
match chars.next() {
|
match chars.next() {
|
||||||
None => return Err("ID cannot be empty"),
|
None => return Err("ID cannot be empty"),
|
||||||
|
@ -36,31 +46,14 @@ impl Id {
|
||||||
return Err("ID can only contain alphanumerics, dash, dot and underscore");
|
return Err("ID can only contain alphanumerics, dash, dot and underscore");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Ok(Id(id.to_string()))
|
||||||
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| {
|
|
||||||
panic!("typed_html::types::Id: {:?} is not a valid ID: {}", id, err)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Id {
|
impl<'a> TryFrom<&'a str> for Id {
|
||||||
type Err = &'static str;
|
type Error = &'static str;
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn try_from(str: &'a str) -> Result<Self, Self::Error> {
|
||||||
Id::try_new(s)
|
Id::from_str(str)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a str> for Id {
|
|
||||||
fn from(str: &'a str) -> Self {
|
|
||||||
Id::from_str(str).unwrap()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::convert::{TryFrom, TryInto};
|
||||||
use std::fmt::{Debug, Display, Error, Formatter};
|
use std::fmt::{Debug, Display, Error, Formatter};
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
@ -18,6 +19,24 @@ impl<A> SpacedList<A> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
SpacedList(Vec::new())
|
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> {
|
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
|
where
|
||||||
<A as FromStr>::Err: Debug,
|
A: FromStr,
|
||||||
{
|
{
|
||||||
fn from(s: &'a str) -> Self {
|
type Error = <A as FromStr>::Err;
|
||||||
Self::from_iter(s.split_whitespace().map(|s| FromStr::from_str(s).unwrap()))
|
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
|
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();
|
let mut list = Self::new();
|
||||||
list.push(FromStr::from_str(s.0).unwrap());
|
list.push(FromStr::from_str(s.0)?);
|
||||||
list.push(FromStr::from_str(s.1).unwrap());
|
list.push(FromStr::from_str(s.1)?);
|
||||||
list
|
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
|
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();
|
let mut list = Self::new();
|
||||||
list.push(FromStr::from_str(s.0).unwrap());
|
list.push(FromStr::from_str(s.0)?);
|
||||||
list.push(FromStr::from_str(s.1).unwrap());
|
list.push(FromStr::from_str(s.1)?);
|
||||||
list.push(FromStr::from_str(s.2).unwrap());
|
list.push(FromStr::from_str(s.2)?);
|
||||||
list
|
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
|
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();
|
let mut list = Self::new();
|
||||||
list.push(FromStr::from_str(s.0).unwrap());
|
list.push(FromStr::from_str(s.0)?);
|
||||||
list.push(FromStr::from_str(s.1).unwrap());
|
list.push(FromStr::from_str(s.1)?);
|
||||||
list.push(FromStr::from_str(s.2).unwrap());
|
list.push(FromStr::from_str(s.2)?);
|
||||||
list.push(FromStr::from_str(s.3).unwrap());
|
list.push(FromStr::from_str(s.3)?);
|
||||||
list
|
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>
|
for SpacedList<A>
|
||||||
where
|
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();
|
let mut list = Self::new();
|
||||||
list.push(FromStr::from_str(s.0).unwrap());
|
list.push(FromStr::from_str(s.0)?);
|
||||||
list.push(FromStr::from_str(s.1).unwrap());
|
list.push(FromStr::from_str(s.1)?);
|
||||||
list.push(FromStr::from_str(s.2).unwrap());
|
list.push(FromStr::from_str(s.2)?);
|
||||||
list.push(FromStr::from_str(s.3).unwrap());
|
list.push(FromStr::from_str(s.3)?);
|
||||||
list.push(FromStr::from_str(s.4).unwrap());
|
list.push(FromStr::from_str(s.4)?);
|
||||||
list
|
list.push(FromStr::from_str(s.5)?);
|
||||||
|
Ok(list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'c, 'd, 'e, 'f, A: FromStr>
|
impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, A>
|
||||||
From<(&'a str, &'b str, &'c str, &'d str, &'e str, &'f str)> for SpacedList<A>
|
TryFrom<(
|
||||||
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<(
|
|
||||||
&'a str,
|
&'a str,
|
||||||
&'b str,
|
&'b str,
|
||||||
&'c str,
|
&'c str,
|
||||||
|
@ -168,23 +192,24 @@ impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, A: FromStr>
|
||||||
&'g str,
|
&'g str,
|
||||||
)> for SpacedList<A>
|
)> for SpacedList<A>
|
||||||
where
|
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();
|
let mut list = Self::new();
|
||||||
list.push(FromStr::from_str(s.0).unwrap());
|
list.push(FromStr::from_str(s.0)?);
|
||||||
list.push(FromStr::from_str(s.1).unwrap());
|
list.push(FromStr::from_str(s.1)?);
|
||||||
list.push(FromStr::from_str(s.2).unwrap());
|
list.push(FromStr::from_str(s.2)?);
|
||||||
list.push(FromStr::from_str(s.3).unwrap());
|
list.push(FromStr::from_str(s.3)?);
|
||||||
list.push(FromStr::from_str(s.4).unwrap());
|
list.push(FromStr::from_str(s.4)?);
|
||||||
list.push(FromStr::from_str(s.5).unwrap());
|
list.push(FromStr::from_str(s.5)?);
|
||||||
list.push(FromStr::from_str(s.6).unwrap());
|
list.push(FromStr::from_str(s.6)?);
|
||||||
list
|
Ok(list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, A: FromStr>
|
impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, A>
|
||||||
From<(
|
TryFrom<(
|
||||||
&'a str,
|
&'a str,
|
||||||
&'b str,
|
&'b str,
|
||||||
&'c str,
|
&'c str,
|
||||||
|
@ -195,30 +220,32 @@ impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, A: FromStr>
|
||||||
&'h str,
|
&'h str,
|
||||||
)> for SpacedList<A>
|
)> for SpacedList<A>
|
||||||
where
|
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();
|
let mut list = Self::new();
|
||||||
list.push(FromStr::from_str(s.0).unwrap());
|
list.push(FromStr::from_str(s.0)?);
|
||||||
list.push(FromStr::from_str(s.1).unwrap());
|
list.push(FromStr::from_str(s.1)?);
|
||||||
list.push(FromStr::from_str(s.2).unwrap());
|
list.push(FromStr::from_str(s.2)?);
|
||||||
list.push(FromStr::from_str(s.3).unwrap());
|
list.push(FromStr::from_str(s.3)?);
|
||||||
list.push(FromStr::from_str(s.4).unwrap());
|
list.push(FromStr::from_str(s.4)?);
|
||||||
list.push(FromStr::from_str(s.5).unwrap());
|
list.push(FromStr::from_str(s.5)?);
|
||||||
list.push(FromStr::from_str(s.6).unwrap());
|
list.push(FromStr::from_str(s.6)?);
|
||||||
list.push(FromStr::from_str(s.7).unwrap());
|
list.push(FromStr::from_str(s.7)?);
|
||||||
list
|
Ok(list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! spacedlist_from_array {
|
macro_rules! spacedlist_from_array {
|
||||||
($num:tt) => {
|
($num:tt) => {
|
||||||
impl<'a, A: FromStr> From<[&'a str; $num]> for SpacedList<A>
|
impl<'a, A> TryFrom<[&'a str; $num]> for SpacedList<A>
|
||||||
where
|
where
|
||||||
<A as FromStr>::Err: Debug,
|
A: FromStr,
|
||||||
{
|
{
|
||||||
fn from(s: [&str; $num]) -> Self {
|
type Error = <A as FromStr>::Err;
|
||||||
Self::from_iter(s.into_iter().map(|s| FromStr::from_str(*s).unwrap()))
|
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::collections::BTreeSet;
|
||||||
|
use std::convert::{TryFrom, TryInto};
|
||||||
use std::fmt::{Debug, Display, Error, Formatter};
|
use std::fmt::{Debug, Display, Error, Formatter};
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
@ -12,18 +13,18 @@ use std::str::FromStr;
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use std::convert::From;
|
/// # use std::convert::{TryFrom, TryInto};
|
||||||
/// use typed_html::types::{Class, SpacedSet};
|
/// use typed_html::types::{Class, SpacedSet};
|
||||||
///
|
///
|
||||||
/// # fn main() {
|
/// # fn main() -> Result<(), &'static str> {
|
||||||
/// let classList: SpacedSet<Class> = "foo bar baz".into();
|
/// let classList: SpacedSet<Class> = "foo bar baz".try_into()?;
|
||||||
/// let classList: SpacedSet<Class> = ["foo", "bar", "baz"].into();
|
/// let classList: SpacedSet<Class> = ["foo", "bar", "baz"].try_into()?;
|
||||||
/// let classList: SpacedSet<Class> = ("foo", "bar", "baz").into();
|
/// let classList: SpacedSet<Class> = ("foo", "bar", "baz").try_into()?;
|
||||||
///
|
///
|
||||||
/// let classList1: SpacedSet<Class> = "foo bar foo".into();
|
/// let classList1: SpacedSet<Class> = "foo bar foo".try_into()?;
|
||||||
/// let classList2: SpacedSet<Class> = "bar foo bar".into();
|
/// let classList2: SpacedSet<Class> = "bar foo bar".try_into()?;
|
||||||
/// assert_eq!(classList1, classList2);
|
/// assert_eq!(classList1, classList2);
|
||||||
/// # }
|
/// # Ok(()) }
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct SpacedSet<A: Ord>(BTreeSet<A>);
|
pub struct SpacedSet<A: Ord>(BTreeSet<A>);
|
||||||
|
@ -34,9 +35,21 @@ impl<A: Ord> SpacedSet<A> {
|
||||||
SpacedSet(BTreeSet::new())
|
SpacedSet(BTreeSet::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a value to the `SpacedSet`.
|
/// Add a value to the `SpacedSet`, converting it as necessary.
|
||||||
pub fn add<T: Into<A>>(&mut self, value: T) -> bool {
|
///
|
||||||
self.0.insert(value.into())
|
/// 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
|
where
|
||||||
<A as FromStr>::Err: Debug,
|
A: Ord + FromStr,
|
||||||
{
|
{
|
||||||
fn from(s: &'a str) -> Self {
|
type Error = <A as FromStr>::Err;
|
||||||
Self::from_iter(s.split_whitespace().map(|s| FromStr::from_str(s).unwrap()))
|
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
|
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();
|
let mut list = Self::new();
|
||||||
list.insert(FromStr::from_str(s.0).unwrap());
|
list.insert(FromStr::from_str(s.0)?);
|
||||||
list.insert(FromStr::from_str(s.1).unwrap());
|
list.insert(FromStr::from_str(s.1)?);
|
||||||
list
|
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
|
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();
|
let mut list = Self::new();
|
||||||
list.insert(FromStr::from_str(s.0).unwrap());
|
list.insert(FromStr::from_str(s.0)?);
|
||||||
list.insert(FromStr::from_str(s.1).unwrap());
|
list.insert(FromStr::from_str(s.1)?);
|
||||||
list.insert(FromStr::from_str(s.2).unwrap());
|
list.insert(FromStr::from_str(s.2)?);
|
||||||
list
|
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
|
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();
|
let mut list = Self::new();
|
||||||
list.insert(FromStr::from_str(s.0).unwrap());
|
list.insert(FromStr::from_str(s.0)?);
|
||||||
list.insert(FromStr::from_str(s.1).unwrap());
|
list.insert(FromStr::from_str(s.1)?);
|
||||||
list.insert(FromStr::from_str(s.2).unwrap());
|
list.insert(FromStr::from_str(s.2)?);
|
||||||
list.insert(FromStr::from_str(s.3).unwrap());
|
list.insert(FromStr::from_str(s.3)?);
|
||||||
list
|
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>
|
for SpacedSet<A>
|
||||||
where
|
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();
|
let mut list = Self::new();
|
||||||
list.insert(FromStr::from_str(s.0).unwrap());
|
list.insert(FromStr::from_str(s.0)?);
|
||||||
list.insert(FromStr::from_str(s.1).unwrap());
|
list.insert(FromStr::from_str(s.1)?);
|
||||||
list.insert(FromStr::from_str(s.2).unwrap());
|
list.insert(FromStr::from_str(s.2)?);
|
||||||
list.insert(FromStr::from_str(s.3).unwrap());
|
list.insert(FromStr::from_str(s.3)?);
|
||||||
list.insert(FromStr::from_str(s.4).unwrap());
|
list.insert(FromStr::from_str(s.4)?);
|
||||||
list
|
list.insert(FromStr::from_str(s.5)?);
|
||||||
|
Ok(list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'c, 'd, 'e, 'f, A: Ord + FromStr>
|
impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, A>
|
||||||
From<(&'a str, &'b str, &'c str, &'d str, &'e str, &'f str)> for SpacedSet<A>
|
TryFrom<(
|
||||||
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<(
|
|
||||||
&'a str,
|
&'a str,
|
||||||
&'b str,
|
&'b str,
|
||||||
&'c str,
|
&'c str,
|
||||||
|
@ -201,23 +219,24 @@ impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, A: Ord + FromStr>
|
||||||
&'g str,
|
&'g str,
|
||||||
)> for SpacedSet<A>
|
)> for SpacedSet<A>
|
||||||
where
|
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();
|
let mut list = Self::new();
|
||||||
list.insert(FromStr::from_str(s.0).unwrap());
|
list.insert(FromStr::from_str(s.0)?);
|
||||||
list.insert(FromStr::from_str(s.1).unwrap());
|
list.insert(FromStr::from_str(s.1)?);
|
||||||
list.insert(FromStr::from_str(s.2).unwrap());
|
list.insert(FromStr::from_str(s.2)?);
|
||||||
list.insert(FromStr::from_str(s.3).unwrap());
|
list.insert(FromStr::from_str(s.3)?);
|
||||||
list.insert(FromStr::from_str(s.4).unwrap());
|
list.insert(FromStr::from_str(s.4)?);
|
||||||
list.insert(FromStr::from_str(s.5).unwrap());
|
list.insert(FromStr::from_str(s.5)?);
|
||||||
list.insert(FromStr::from_str(s.6).unwrap());
|
list.insert(FromStr::from_str(s.6)?);
|
||||||
list
|
Ok(list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, A: Ord + FromStr>
|
impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, A>
|
||||||
From<(
|
TryFrom<(
|
||||||
&'a str,
|
&'a str,
|
||||||
&'b str,
|
&'b str,
|
||||||
&'c str,
|
&'c str,
|
||||||
|
@ -228,63 +247,65 @@ impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, A: Ord + FromStr>
|
||||||
&'h str,
|
&'h str,
|
||||||
)> for SpacedSet<A>
|
)> for SpacedSet<A>
|
||||||
where
|
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();
|
let mut list = Self::new();
|
||||||
list.insert(FromStr::from_str(s.0).unwrap());
|
list.insert(FromStr::from_str(s.0)?);
|
||||||
list.insert(FromStr::from_str(s.1).unwrap());
|
list.insert(FromStr::from_str(s.1)?);
|
||||||
list.insert(FromStr::from_str(s.2).unwrap());
|
list.insert(FromStr::from_str(s.2)?);
|
||||||
list.insert(FromStr::from_str(s.3).unwrap());
|
list.insert(FromStr::from_str(s.3)?);
|
||||||
list.insert(FromStr::from_str(s.4).unwrap());
|
list.insert(FromStr::from_str(s.4)?);
|
||||||
list.insert(FromStr::from_str(s.5).unwrap());
|
list.insert(FromStr::from_str(s.5)?);
|
||||||
list.insert(FromStr::from_str(s.6).unwrap());
|
list.insert(FromStr::from_str(s.6)?);
|
||||||
list.insert(FromStr::from_str(s.7).unwrap());
|
list.insert(FromStr::from_str(s.7)?);
|
||||||
list
|
Ok(list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! spacedlist_from_array {
|
macro_rules! spacedset_from_array {
|
||||||
($num:tt) => {
|
($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
|
where
|
||||||
<A as FromStr>::Err: Debug,
|
A: Ord + FromStr,
|
||||||
{
|
{
|
||||||
fn from(s: [&str; $num]) -> Self {
|
type Error = <A as FromStr>::Err;
|
||||||
Self::from_iter(s.into_iter().map(|s| FromStr::from_str(*s).unwrap()))
|
fn try_from(s: [&str; $num]) -> Result<Self, Self::Error> {
|
||||||
|
s.into_iter().map(|s| FromStr::from_str(*s)).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
spacedlist_from_array!(1);
|
spacedset_from_array!(1);
|
||||||
spacedlist_from_array!(2);
|
spacedset_from_array!(2);
|
||||||
spacedlist_from_array!(3);
|
spacedset_from_array!(3);
|
||||||
spacedlist_from_array!(4);
|
spacedset_from_array!(4);
|
||||||
spacedlist_from_array!(5);
|
spacedset_from_array!(5);
|
||||||
spacedlist_from_array!(6);
|
spacedset_from_array!(6);
|
||||||
spacedlist_from_array!(7);
|
spacedset_from_array!(7);
|
||||||
spacedlist_from_array!(8);
|
spacedset_from_array!(8);
|
||||||
spacedlist_from_array!(9);
|
spacedset_from_array!(9);
|
||||||
spacedlist_from_array!(10);
|
spacedset_from_array!(10);
|
||||||
spacedlist_from_array!(11);
|
spacedset_from_array!(11);
|
||||||
spacedlist_from_array!(12);
|
spacedset_from_array!(12);
|
||||||
spacedlist_from_array!(13);
|
spacedset_from_array!(13);
|
||||||
spacedlist_from_array!(14);
|
spacedset_from_array!(14);
|
||||||
spacedlist_from_array!(15);
|
spacedset_from_array!(15);
|
||||||
spacedlist_from_array!(16);
|
spacedset_from_array!(16);
|
||||||
spacedlist_from_array!(17);
|
spacedset_from_array!(17);
|
||||||
spacedlist_from_array!(18);
|
spacedset_from_array!(18);
|
||||||
spacedlist_from_array!(19);
|
spacedset_from_array!(19);
|
||||||
spacedlist_from_array!(20);
|
spacedset_from_array!(20);
|
||||||
spacedlist_from_array!(21);
|
spacedset_from_array!(21);
|
||||||
spacedlist_from_array!(22);
|
spacedset_from_array!(22);
|
||||||
spacedlist_from_array!(23);
|
spacedset_from_array!(23);
|
||||||
spacedlist_from_array!(24);
|
spacedset_from_array!(24);
|
||||||
spacedlist_from_array!(25);
|
spacedset_from_array!(25);
|
||||||
spacedlist_from_array!(26);
|
spacedset_from_array!(26);
|
||||||
spacedlist_from_array!(27);
|
spacedset_from_array!(27);
|
||||||
spacedlist_from_array!(28);
|
spacedset_from_array!(28);
|
||||||
spacedlist_from_array!(29);
|
spacedset_from_array!(29);
|
||||||
spacedlist_from_array!(30);
|
spacedset_from_array!(30);
|
||||||
spacedlist_from_array!(31);
|
spacedset_from_array!(31);
|
||||||
spacedlist_from_array!(32);
|
spacedset_from_array!(32);
|
||||||
|
|
Loading…
Reference in New Issue