I'm halfway through the HTML spec.
This commit is contained in:
parent
73344d0dbf
commit
16f0be33a4
|
@ -23,7 +23,7 @@ pub fn global_attrs(span: Span) -> StringyMap<Ident, TokenStream> {
|
||||||
insert("autocapitalize", "String");
|
insert("autocapitalize", "String");
|
||||||
insert("contenteditable", "bool");
|
insert("contenteditable", "bool");
|
||||||
insert("contextmenu", "crate::types::Id");
|
insert("contextmenu", "crate::types::Id");
|
||||||
insert("dir", "String");
|
insert("dir", "crate::types::TextDirection");
|
||||||
insert("draggable", "bool");
|
insert("draggable", "bool");
|
||||||
insert("hidden", "bool");
|
insert("hidden", "bool");
|
||||||
insert("is", "String");
|
insert("is", "String");
|
||||||
|
|
|
@ -26,7 +26,7 @@ fn main() {
|
||||||
<body>
|
<body>
|
||||||
<h1 data-lol="omg" data-foo=wibble.foo>"Hello Kitty!"</h1>
|
<h1 data-lol="omg" data-foo=wibble.foo>"Hello Kitty!"</h1>
|
||||||
<p class=splain_class>
|
<p class=splain_class>
|
||||||
"She is not a "<em>"cat"</em>". She is a "<em>"human girl"</em>"."
|
"She is not a "<em><a href="https://en.wikipedia.org/wiki/Cat">"cat"</a></em>". She is a "<em>"human girl"</em>"."
|
||||||
</p>
|
</p>
|
||||||
<p class=["foo", "bar"]>{the_big_question}</p>
|
<p class=["foo", "bar"]>{the_big_question}</p>
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,7 +32,17 @@ pub trait Element: Node {
|
||||||
|
|
||||||
pub trait MetadataContent: Node {}
|
pub trait MetadataContent: Node {}
|
||||||
pub trait FlowContent: Node {}
|
pub trait FlowContent: Node {}
|
||||||
pub trait PhrasingContent: Node {}
|
pub trait SectioningContent: Node {}
|
||||||
|
pub trait HeadingContent: Node {}
|
||||||
|
// Phrasing content seems to be entirely a subclass of FlowContent
|
||||||
|
pub trait PhrasingContent: FlowContent {}
|
||||||
|
pub trait EmbeddedContent: Node {}
|
||||||
|
pub trait InteractiveContent: Node {}
|
||||||
|
pub trait FormContent: Node {}
|
||||||
|
|
||||||
|
// Traits for elements that are more picky about their children
|
||||||
|
pub trait DescriptionListContent: Node {}
|
||||||
|
pub trait HGroupContent: Node {}
|
||||||
|
|
||||||
impl IntoIterator for TextNode {
|
impl IntoIterator for TextNode {
|
||||||
type Item = TextNode;
|
type Item = TextNode;
|
||||||
|
@ -93,7 +103,7 @@ declare_element!(body {} [] FlowContent);
|
||||||
// Metadata content
|
// Metadata content
|
||||||
declare_element!(base {
|
declare_element!(base {
|
||||||
href: Uri,
|
href: Uri,
|
||||||
target: String,
|
target: Target,
|
||||||
} [] [MetadataContent]);
|
} [] [MetadataContent]);
|
||||||
declare_element!(link {
|
declare_element!(link {
|
||||||
as: Mime,
|
as: Mime,
|
||||||
|
@ -121,15 +131,151 @@ declare_element!(style {
|
||||||
declare_element!(title {} [] [MetadataContent] TextNode);
|
declare_element!(title {} [] [MetadataContent] TextNode);
|
||||||
|
|
||||||
// Flow content
|
// Flow content
|
||||||
|
declare_element!(a {
|
||||||
|
download: String,
|
||||||
|
href: Uri,
|
||||||
|
hreflang: LanguageTag,
|
||||||
|
ping: SpacedList<Uri>,
|
||||||
|
rel: SpacedList<LinkType>,
|
||||||
|
target: Target,
|
||||||
|
type: Mime,
|
||||||
|
} [] [FlowContent, PhrasingContent, InteractiveContent] FlowContent);
|
||||||
|
declare_element!(abbr {} [] [FlowContent, PhrasingContent] PhrasingContent);
|
||||||
|
declare_element!(address {} [] [FlowContent] FlowContent); // FIXME it has additional constraints on FlowContent
|
||||||
|
declare_element!(article {} [] [FlowContent, SectioningContent] FlowContent);
|
||||||
|
declare_element!(aside {} [] [FlowContent, SectioningContent] FlowContent);
|
||||||
|
declare_element!(audio {
|
||||||
|
autoplay: bool,
|
||||||
|
controls: bool,
|
||||||
|
crossorigin: CrossOrigin,
|
||||||
|
loop: bool,
|
||||||
|
muted: bool,
|
||||||
|
preload: Preload,
|
||||||
|
src: Uri,
|
||||||
|
} [] [FlowContent, PhrasingContent]);
|
||||||
|
declare_element!(b {} [] [FlowContent, PhrasingContent] PhrasingContent);
|
||||||
|
declare_element!(bdo {} [] [FlowContent, PhrasingContent] PhrasingContent);
|
||||||
|
declare_element!(bdi {} [] [FlowContent, PhrasingContent] PhrasingContent);
|
||||||
|
declare_element!(blockquote {
|
||||||
|
cite: Uri,
|
||||||
|
} [] [FlowContent] FlowContent);
|
||||||
|
declare_element!(br {} [] [FlowContent, PhrasingContent]);
|
||||||
|
declare_element!(button {
|
||||||
|
autofocus: bool,
|
||||||
|
disabled: bool,
|
||||||
|
form: Id,
|
||||||
|
formaction: Uri,
|
||||||
|
formenctype: FormEncodingType,
|
||||||
|
formmethod: FormMethod,
|
||||||
|
formnovalidate: bool,
|
||||||
|
formtarget: Target,
|
||||||
|
name: Id,
|
||||||
|
type: ButtonType,
|
||||||
|
value: String,
|
||||||
|
} [] [FlowContent, PhrasingContent, InteractiveContent, FormContent] PhrasingContent);
|
||||||
|
declare_element!(canvas {
|
||||||
|
height: usize,
|
||||||
|
width: usize,
|
||||||
|
} [] [FlowContent] FlowContent); // FIXME has additional child constraints
|
||||||
|
declare_element!(cite {} [] [FlowContent, PhrasingContent] PhrasingContent);
|
||||||
|
declare_element!(code {} [] [FlowContent, PhrasingContent] PhrasingContent);
|
||||||
|
declare_element!(data {
|
||||||
|
value: String,
|
||||||
|
} [] [FlowContent, PhrasingContent] PhrasingContent);
|
||||||
|
declare_element!(datalist {} [] [FlowContent, PhrasingContent] Element_option);
|
||||||
|
declare_element!(del {
|
||||||
|
cite: Uri,
|
||||||
|
datetime: String, // FIXME should be "a valid date string with an optional time",
|
||||||
|
// but I have other hells to live in right now.
|
||||||
|
} [] [FlowContent, PhrasingContent] FlowContent);
|
||||||
|
declare_element!(details {
|
||||||
|
open: bool,
|
||||||
|
} [summary] [FlowContent, SectioningContent, InteractiveContent] FlowContent);
|
||||||
|
declare_element!(dfn {} [] [FlowContent, PhrasingContent] PhrasingContent);
|
||||||
declare_element!(div {} [] [FlowContent] FlowContent);
|
declare_element!(div {} [] [FlowContent] FlowContent);
|
||||||
declare_element!(p {} [] [FlowContent] PhrasingContent);
|
declare_element!(dl {} [] [FlowContent] DescriptionListContent);
|
||||||
declare_element!(h1 {} [] [FlowContent] PhrasingContent);
|
|
||||||
declare_element!(h2 {} [] [FlowContent] PhrasingContent);
|
|
||||||
declare_element!(h3 {} [] [FlowContent] PhrasingContent);
|
|
||||||
declare_element!(h4 {} [] [FlowContent] PhrasingContent);
|
|
||||||
declare_element!(h5 {} [] [FlowContent] PhrasingContent);
|
|
||||||
declare_element!(h6 {} [] [FlowContent] PhrasingContent);
|
|
||||||
declare_element!(em {} [] [FlowContent, PhrasingContent] PhrasingContent);
|
declare_element!(em {} [] [FlowContent, PhrasingContent] PhrasingContent);
|
||||||
|
declare_element!(embed {
|
||||||
|
height: usize,
|
||||||
|
src: Uri,
|
||||||
|
type: Mime,
|
||||||
|
width: usize,
|
||||||
|
} [] [FlowContent, PhrasingContent, EmbeddedContent, InteractiveContent]);
|
||||||
|
// FIXME the legend attribute should be optional
|
||||||
|
declare_element!(fieldset {} [legend] [FlowContent, SectioningContent, FormContent] FlowContent);
|
||||||
|
// FIXME the figcaption attribute should be optional
|
||||||
|
declare_element!(figure {} [figcaption] [FlowContent, SectioningContent] FlowContent);
|
||||||
|
declare_element!(footer {} [] [FlowContent] FlowContent);
|
||||||
|
declare_element!(form {
|
||||||
|
accept-charset: SpacedList<CharacterEncoding>,
|
||||||
|
action: Uri,
|
||||||
|
autocomplete: OnOff,
|
||||||
|
enctype: FormEncodingType,
|
||||||
|
method: FormMethod,
|
||||||
|
name: Id,
|
||||||
|
novalidate: bool,
|
||||||
|
target: Target,
|
||||||
|
} [] [FlowContent] FlowContent);
|
||||||
|
declare_element!(h1 {} [] [FlowContent, HeadingContent, HGroupContent] PhrasingContent);
|
||||||
|
declare_element!(h2 {} [] [FlowContent, HeadingContent, HGroupContent] PhrasingContent);
|
||||||
|
declare_element!(h3 {} [] [FlowContent, HeadingContent, HGroupContent] PhrasingContent);
|
||||||
|
declare_element!(h4 {} [] [FlowContent, HeadingContent, HGroupContent] PhrasingContent);
|
||||||
|
declare_element!(h5 {} [] [FlowContent, HeadingContent, HGroupContent] PhrasingContent);
|
||||||
|
declare_element!(h6 {} [] [FlowContent, HeadingContent, HGroupContent] PhrasingContent);
|
||||||
|
declare_element!(header {} [] [FlowContent] FlowContent);
|
||||||
|
declare_element!(hgroup {} [] [FlowContent, HeadingContent] HGroupContent);
|
||||||
|
declare_element!(hr {} [] [FlowContent]);
|
||||||
|
declare_element!(i {} [] [FlowContent, PhrasingContent] PhrasingContent);
|
||||||
|
declare_element!(iframe {
|
||||||
|
allow: FeaturePolicy,
|
||||||
|
allowfullscreen: bool,
|
||||||
|
allowpaymentrequest: bool,
|
||||||
|
height: usize,
|
||||||
|
name: Id,
|
||||||
|
referrerpolicy: ReferrerPolicy,
|
||||||
|
sandbox: SpacedSet<Sandbox>,
|
||||||
|
src: Uri,
|
||||||
|
srcdoc: Uri,
|
||||||
|
width: usize,
|
||||||
|
} [] [FlowContent, PhrasingContent, EmbeddedContent, InteractiveContent] FlowContent);
|
||||||
|
declare_element!(img {
|
||||||
|
alt: String,
|
||||||
|
crossorigin: CrossOrigin,
|
||||||
|
decoding: ImageDecoding,
|
||||||
|
height: usize,
|
||||||
|
ismap: bool,
|
||||||
|
sizes: SpacedList<String>, // FIXME it's not really just a string
|
||||||
|
src: Uri,
|
||||||
|
srcset: String, // FIXME this is much more complicated
|
||||||
|
usemap: String, // FIXME should be a fragment starting with '#'
|
||||||
|
width: usize,
|
||||||
|
} [] [FlowContent, PhrasingContent, EmbeddedContent]);
|
||||||
|
declare_element!(input {
|
||||||
|
autocomplete: String,
|
||||||
|
autofocus: bool,
|
||||||
|
disabled: bool,
|
||||||
|
form: Id,
|
||||||
|
list: Id,
|
||||||
|
name: Id,
|
||||||
|
required: bool,
|
||||||
|
tabindex: usize,
|
||||||
|
type: InputType,
|
||||||
|
value: String,
|
||||||
|
} [] [FlowContent, FormContent, PhrasingContent]);
|
||||||
|
declare_element!(p {} [] [FlowContent] PhrasingContent);
|
||||||
|
|
||||||
|
// Non-content elements
|
||||||
|
declare_element!(dd {} [] [DescriptionListContent] FlowContent);
|
||||||
|
declare_element!(dt {} [] [DescriptionListContent] FlowContent);
|
||||||
|
declare_element!(figcaption {} [] [] FlowContent);
|
||||||
|
declare_element!(legend {} [] [] PhrasingContent);
|
||||||
|
declare_element!(option {
|
||||||
|
disabled: bool,
|
||||||
|
label: String,
|
||||||
|
selected: bool,
|
||||||
|
value: String,
|
||||||
|
} [] [] TextNode);
|
||||||
|
declare_element!(summary {} [] [] PhrasingContent);
|
||||||
|
|
||||||
// Don't @ me
|
// Don't @ me
|
||||||
declare_element!(blink {} [] [FlowContent, PhrasingContent] PhrasingContent);
|
declare_element!(blink {} [] [FlowContent, PhrasingContent] PhrasingContent);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::convert::TryFrom;
|
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 super::Id;
|
use super::Id;
|
||||||
|
|
||||||
|
@ -47,6 +48,13 @@ impl Class {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromStr for Class {
|
||||||
|
type Err = &'static str;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Class::try_new(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<String> for Class {
|
impl TryFrom<String> for Class {
|
||||||
type Error = &'static str;
|
type Error = &'static str;
|
||||||
fn try_from(s: String) -> Result<Self, Self::Error> {
|
fn try_from(s: String) -> Result<Self, Self::Error> {
|
||||||
|
|
|
@ -1,221 +0,0 @@
|
||||||
use std::collections::BTreeSet;
|
|
||||||
use std::fmt::{Debug, Display, Error, Formatter};
|
|
||||||
use std::iter::FromIterator;
|
|
||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
|
|
||||||
use super::Class;
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub struct ClassList(BTreeSet<Class>);
|
|
||||||
|
|
||||||
impl ClassList {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
ClassList(BTreeSet::new())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for ClassList {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromIterator<Class> for ClassList {
|
|
||||||
fn from_iter<I>(iter: I) -> Self
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = Class>,
|
|
||||||
{
|
|
||||||
ClassList(iter.into_iter().collect())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FromIterator<&'a Class> for ClassList {
|
|
||||||
fn from_iter<I>(iter: I) -> Self
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = &'a Class>,
|
|
||||||
{
|
|
||||||
ClassList(iter.into_iter().cloned().collect())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromIterator<String> for ClassList {
|
|
||||||
fn from_iter<I>(iter: I) -> Self
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = String>,
|
|
||||||
{
|
|
||||||
ClassList(iter.into_iter().map(Class::new).collect())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> FromIterator<&'a str> for ClassList {
|
|
||||||
fn from_iter<I>(iter: I) -> Self
|
|
||||||
where
|
|
||||||
I: IntoIterator<Item = &'a str>,
|
|
||||||
{
|
|
||||||
ClassList(iter.into_iter().map(Class::new).collect())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a str> for ClassList {
|
|
||||||
fn from(s: &'a str) -> Self {
|
|
||||||
Self::from_iter(s.split_whitespace().map(Class::new))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for ClassList {
|
|
||||||
type Target = BTreeSet<Class>;
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for ClassList {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for ClassList {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
let mut it = self.0.iter().peekable();
|
|
||||||
while let Some(class) = it.next() {
|
|
||||||
Display::fmt(class, f)?;
|
|
||||||
if it.peek().is_some() {
|
|
||||||
Display::fmt(" ", f)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for ClassList {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
f.debug_list().entries(self.0.iter()).finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(&str, &str)> for ClassList {
|
|
||||||
fn from(s: (&str, &str)) -> Self {
|
|
||||||
let mut list = Self::new();
|
|
||||||
list.insert(Class::new(s.0));
|
|
||||||
list.insert(Class::new(s.1));
|
|
||||||
list
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(&str, &str, &str)> for ClassList {
|
|
||||||
fn from(s: (&str, &str, &str)) -> Self {
|
|
||||||
let mut list = Self::new();
|
|
||||||
list.insert(Class::new(s.0));
|
|
||||||
list.insert(Class::new(s.1));
|
|
||||||
list.insert(Class::new(s.2));
|
|
||||||
list
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(&str, &str, &str, &str)> for ClassList {
|
|
||||||
fn from(s: (&str, &str, &str, &str)) -> Self {
|
|
||||||
let mut list = Self::new();
|
|
||||||
list.insert(Class::new(s.0));
|
|
||||||
list.insert(Class::new(s.1));
|
|
||||||
list.insert(Class::new(s.2));
|
|
||||||
list.insert(Class::new(s.3));
|
|
||||||
list
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(&str, &str, &str, &str, &str)> for ClassList {
|
|
||||||
fn from(s: (&str, &str, &str, &str, &str)) -> Self {
|
|
||||||
let mut list = Self::new();
|
|
||||||
list.insert(Class::new(s.0));
|
|
||||||
list.insert(Class::new(s.1));
|
|
||||||
list.insert(Class::new(s.2));
|
|
||||||
list.insert(Class::new(s.3));
|
|
||||||
list.insert(Class::new(s.4));
|
|
||||||
list
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(&str, &str, &str, &str, &str, &str)> for ClassList {
|
|
||||||
fn from(s: (&str, &str, &str, &str, &str, &str)) -> Self {
|
|
||||||
let mut list = Self::new();
|
|
||||||
list.insert(Class::new(s.0));
|
|
||||||
list.insert(Class::new(s.1));
|
|
||||||
list.insert(Class::new(s.2));
|
|
||||||
list.insert(Class::new(s.3));
|
|
||||||
list.insert(Class::new(s.4));
|
|
||||||
list.insert(Class::new(s.5));
|
|
||||||
list
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(&str, &str, &str, &str, &str, &str, &str)> for ClassList {
|
|
||||||
fn from(s: (&str, &str, &str, &str, &str, &str, &str)) -> Self {
|
|
||||||
let mut list = Self::new();
|
|
||||||
list.insert(Class::new(s.0));
|
|
||||||
list.insert(Class::new(s.1));
|
|
||||||
list.insert(Class::new(s.2));
|
|
||||||
list.insert(Class::new(s.3));
|
|
||||||
list.insert(Class::new(s.4));
|
|
||||||
list.insert(Class::new(s.5));
|
|
||||||
list.insert(Class::new(s.6));
|
|
||||||
list
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(&str, &str, &str, &str, &str, &str, &str, &str)> for ClassList {
|
|
||||||
fn from(s: (&str, &str, &str, &str, &str, &str, &str, &str)) -> Self {
|
|
||||||
let mut list = Self::new();
|
|
||||||
list.insert(Class::new(s.0));
|
|
||||||
list.insert(Class::new(s.1));
|
|
||||||
list.insert(Class::new(s.2));
|
|
||||||
list.insert(Class::new(s.3));
|
|
||||||
list.insert(Class::new(s.4));
|
|
||||||
list.insert(Class::new(s.5));
|
|
||||||
list.insert(Class::new(s.6));
|
|
||||||
list.insert(Class::new(s.7));
|
|
||||||
list
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! classlist_from_array {
|
|
||||||
($num:tt) => {
|
|
||||||
impl From<[&str; $num]> for ClassList {
|
|
||||||
fn from(s: [&str; $num]) -> Self {
|
|
||||||
Self::from_iter(s.into_iter().map(|s| Class::new(*s)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
classlist_from_array!(1);
|
|
||||||
classlist_from_array!(2);
|
|
||||||
classlist_from_array!(3);
|
|
||||||
classlist_from_array!(4);
|
|
||||||
classlist_from_array!(5);
|
|
||||||
classlist_from_array!(6);
|
|
||||||
classlist_from_array!(7);
|
|
||||||
classlist_from_array!(8);
|
|
||||||
classlist_from_array!(9);
|
|
||||||
classlist_from_array!(10);
|
|
||||||
classlist_from_array!(11);
|
|
||||||
classlist_from_array!(12);
|
|
||||||
classlist_from_array!(13);
|
|
||||||
classlist_from_array!(14);
|
|
||||||
classlist_from_array!(15);
|
|
||||||
classlist_from_array!(16);
|
|
||||||
classlist_from_array!(17);
|
|
||||||
classlist_from_array!(18);
|
|
||||||
classlist_from_array!(19);
|
|
||||||
classlist_from_array!(20);
|
|
||||||
classlist_from_array!(21);
|
|
||||||
classlist_from_array!(22);
|
|
||||||
classlist_from_array!(23);
|
|
||||||
classlist_from_array!(24);
|
|
||||||
classlist_from_array!(25);
|
|
||||||
classlist_from_array!(26);
|
|
||||||
classlist_from_array!(27);
|
|
||||||
classlist_from_array!(28);
|
|
||||||
classlist_from_array!(29);
|
|
||||||
classlist_from_array!(30);
|
|
||||||
classlist_from_array!(31);
|
|
||||||
classlist_from_array!(32);
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::convert::TryFrom;
|
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 super::Class;
|
use super::Class;
|
||||||
|
|
||||||
|
@ -42,6 +43,13 @@ impl Id {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromStr for Id {
|
||||||
|
type Err = &'static str;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Id::try_new(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<String> for Id {
|
impl TryFrom<String> for Id {
|
||||||
type Error = &'static str;
|
type Error = &'static str;
|
||||||
fn try_from(s: String) -> Result<Self, Self::Error> {
|
fn try_from(s: String) -> Result<Self, Self::Error> {
|
||||||
|
|
|
@ -4,19 +4,126 @@ pub use self::class::Class;
|
||||||
mod id;
|
mod id;
|
||||||
pub use self::id::Id;
|
pub use self::id::Id;
|
||||||
|
|
||||||
mod classlist;
|
mod spacedlist;
|
||||||
pub use self::classlist::ClassList;
|
pub use self::spacedlist::SpacedList;
|
||||||
|
|
||||||
|
mod spacedset;
|
||||||
|
pub use self::spacedset::SpacedSet;
|
||||||
|
|
||||||
|
pub type ClassList = SpacedSet<Class>;
|
||||||
|
|
||||||
pub use http::Uri;
|
pub use http::Uri;
|
||||||
pub use language_tags::LanguageTag;
|
pub use language_tags::LanguageTag;
|
||||||
pub use mime::Mime;
|
pub use mime::Mime;
|
||||||
|
|
||||||
#[derive(EnumString, Display)]
|
pub type Target = String;
|
||||||
pub enum CrossOrigin {
|
pub type CharacterEncoding = String;
|
||||||
#[strum(to_string = "anonymous")]
|
pub type FeaturePolicy = String;
|
||||||
Anonymous,
|
|
||||||
#[strum(to_string = "use-credentials")]
|
enum_set_type! {
|
||||||
UseCredentials,
|
#[derive(EnumString, Display)]
|
||||||
|
pub enum ButtonType {
|
||||||
|
#[strum(to_string = "submit")]
|
||||||
|
Submit,
|
||||||
|
#[strum(to_string = "reset")]
|
||||||
|
Reset,
|
||||||
|
#[strum(to_string = "button")]
|
||||||
|
Button,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum_set_type! {
|
||||||
|
#[derive(EnumString, Display)]
|
||||||
|
pub enum CrossOrigin {
|
||||||
|
#[strum(to_string = "anonymous")]
|
||||||
|
Anonymous,
|
||||||
|
#[strum(to_string = "use-credentials")]
|
||||||
|
UseCredentials,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum_set_type! {
|
||||||
|
#[derive(EnumString, Display)]
|
||||||
|
pub enum FormEncodingType {
|
||||||
|
#[strum(to_string = "application/x-www-form-urlencoded")]
|
||||||
|
UrlEncoded,
|
||||||
|
#[strum(to_string = "multipart/form-data")]
|
||||||
|
FormData,
|
||||||
|
#[strum(to_string = "text/plain")]
|
||||||
|
Text,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum_set_type! {
|
||||||
|
#[derive(EnumString, Display)]
|
||||||
|
pub enum FormMethod {
|
||||||
|
#[strum(to_string = "post")]
|
||||||
|
Post,
|
||||||
|
#[strum(to_string = "get")]
|
||||||
|
Get,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum_set_type! {
|
||||||
|
#[derive(EnumString, Display)]
|
||||||
|
pub enum ImageDecoding {
|
||||||
|
#[strum(to_string = "sync")]
|
||||||
|
Sync,
|
||||||
|
#[strum(to_string = "async")]
|
||||||
|
Async,
|
||||||
|
#[strum(to_string = "auto")]
|
||||||
|
Auto,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum_set_type! {
|
||||||
|
#[derive(EnumString, Display)]
|
||||||
|
pub enum InputType {
|
||||||
|
#[strum(to_string = "button")]
|
||||||
|
Button,
|
||||||
|
#[strum(to_string = "checkbox")]
|
||||||
|
Checkbox,
|
||||||
|
#[strum(to_string = "color")]
|
||||||
|
Color,
|
||||||
|
#[strum(to_string = "date")]
|
||||||
|
Date,
|
||||||
|
#[strum(to_string = "datetime-local")]
|
||||||
|
DatetimeLocal,
|
||||||
|
#[strum(to_string = "email")]
|
||||||
|
Email,
|
||||||
|
#[strum(to_string = "file")]
|
||||||
|
File,
|
||||||
|
#[strum(to_string = "hidden")]
|
||||||
|
Hidden,
|
||||||
|
#[strum(to_string = "image")]
|
||||||
|
Image,
|
||||||
|
#[strum(to_string = "month")]
|
||||||
|
Month,
|
||||||
|
#[strum(to_string = "number")]
|
||||||
|
Number,
|
||||||
|
#[strum(to_string = "password")]
|
||||||
|
Password,
|
||||||
|
#[strum(to_string = "radio")]
|
||||||
|
Radio,
|
||||||
|
#[strum(to_string = "range")]
|
||||||
|
Range,
|
||||||
|
#[strum(to_string = "reset")]
|
||||||
|
Reset,
|
||||||
|
#[strum(to_string = "search")]
|
||||||
|
Search,
|
||||||
|
#[strum(to_string = "submit")]
|
||||||
|
Submit,
|
||||||
|
#[strum(to_string = "tel")]
|
||||||
|
Tel,
|
||||||
|
#[strum(to_string = "text")]
|
||||||
|
Text,
|
||||||
|
#[strum(to_string = "time")]
|
||||||
|
Time,
|
||||||
|
#[strum(to_string = "url")]
|
||||||
|
Url,
|
||||||
|
#[strum(to_string = "week")]
|
||||||
|
Week,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum_set_type! {
|
enum_set_type! {
|
||||||
|
@ -68,3 +175,79 @@ enum_set_type! {
|
||||||
Tag,
|
Tag,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum_set_type! {
|
||||||
|
#[derive(EnumString, Display)]
|
||||||
|
pub enum OnOff {
|
||||||
|
#[strum(to_string = "on")]
|
||||||
|
On,
|
||||||
|
#[strum(to_string = "off")]
|
||||||
|
Off,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum_set_type! {
|
||||||
|
#[derive(EnumString, Display)]
|
||||||
|
pub enum Preload {
|
||||||
|
#[strum(to_string = "none")]
|
||||||
|
None,
|
||||||
|
#[strum(to_string = "metadata")]
|
||||||
|
Metadata,
|
||||||
|
#[strum(to_string = "auto")]
|
||||||
|
Auto,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum_set_type! {
|
||||||
|
#[derive(EnumString, Display)]
|
||||||
|
pub enum ReferrerPolicy {
|
||||||
|
#[strum(to_string = "no-referrer")]
|
||||||
|
NoReferrer,
|
||||||
|
#[strum(to_string = "no-referrer-when-downgrade")]
|
||||||
|
NoReferrerWhenDowngrade,
|
||||||
|
#[strum(to_string = "origin")]
|
||||||
|
Origin,
|
||||||
|
#[strum(to_string = "origin-when-cross-origin")]
|
||||||
|
OriginWhenCrossOrigin,
|
||||||
|
#[strum(to_string = "unsafe-url")]
|
||||||
|
UnsafeUrl,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum_set_type! {
|
||||||
|
#[derive(EnumString, Display)]
|
||||||
|
pub enum Sandbox {
|
||||||
|
#[strum(to_string = "allow-forms")]
|
||||||
|
AllowForms,
|
||||||
|
#[strum(to_string = "allow-modals")]
|
||||||
|
AllowModals,
|
||||||
|
#[strum(to_string = "allow-orientation-lock")]
|
||||||
|
AllowOrientationLock,
|
||||||
|
#[strum(to_string = "allow-pointer-lock")]
|
||||||
|
AllowPointerLock,
|
||||||
|
#[strum(to_string = "allow-popups")]
|
||||||
|
AllowPopups,
|
||||||
|
#[strum(to_string = "allow-popups-to-escape-sandbox")]
|
||||||
|
AllowPopupsToEscapeSandbox,
|
||||||
|
#[strum(to_string = "allow-presentation")]
|
||||||
|
AllowPresentation,
|
||||||
|
#[strum(to_string = "allow-same-origin")]
|
||||||
|
AllowSameOrigin,
|
||||||
|
#[strum(to_string = "allow-scripts")]
|
||||||
|
AllowScripts,
|
||||||
|
#[strum(to_string = "allow-top-navigation")]
|
||||||
|
AllowTopNavigation,
|
||||||
|
#[strum(to_string = "allow-top-navigation-by-user-navigation")]
|
||||||
|
AllowTopNavigationByUserNavigation,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum_set_type! {
|
||||||
|
#[derive(EnumString, Display)]
|
||||||
|
pub enum TextDirection {
|
||||||
|
#[strum(to_string = "ltr")]
|
||||||
|
LeftToRight,
|
||||||
|
#[strum(to_string = "rtl")]
|
||||||
|
RightToLeft,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,228 @@
|
||||||
|
use std::fmt::{Debug, Display, Error, Formatter};
|
||||||
|
use std::iter::FromIterator;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct SpacedList<A>(Vec<A>);
|
||||||
|
|
||||||
|
impl<A> SpacedList<A> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
SpacedList(Vec::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> Default for SpacedList<A> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> FromIterator<A> for SpacedList<A> {
|
||||||
|
fn from_iter<I>(iter: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = A>,
|
||||||
|
{
|
||||||
|
SpacedList(iter.into_iter().collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, A: 'a + Clone> FromIterator<&'a A> for SpacedList<A> {
|
||||||
|
fn from_iter<I>(iter: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = &'a A>,
|
||||||
|
{
|
||||||
|
SpacedList(iter.into_iter().cloned().collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, A: FromStr> From<&'a str> for SpacedList<A>
|
||||||
|
where
|
||||||
|
<A as FromStr>::Err: Debug,
|
||||||
|
{
|
||||||
|
fn from(s: &'a str) -> Self {
|
||||||
|
Self::from_iter(s.split_whitespace().map(|s| FromStr::from_str(s).unwrap()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> Deref for SpacedList<A> {
|
||||||
|
type Target = Vec<A>;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> DerefMut for SpacedList<A> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Display> Display for SpacedList<A> {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||||
|
let mut it = self.0.iter().peekable();
|
||||||
|
while let Some(class) = it.next() {
|
||||||
|
Display::fmt(class, f)?;
|
||||||
|
if it.peek().is_some() {
|
||||||
|
Display::fmt(" ", f)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Debug> Debug for SpacedList<A> {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||||
|
f.debug_list().entries(self.0.iter()).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: FromStr> From<(&str, &str)> for SpacedList<A>
|
||||||
|
where
|
||||||
|
<A as FromStr>::Err: Debug,
|
||||||
|
{
|
||||||
|
fn from(s: (&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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: FromStr> From<(&str, &str, &str)> for SpacedList<A>
|
||||||
|
where
|
||||||
|
<A as FromStr>::Err: Debug,
|
||||||
|
{
|
||||||
|
fn from(s: (&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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: FromStr> From<(&str, &str, &str, &str)> for SpacedList<A>
|
||||||
|
where
|
||||||
|
<A as FromStr>::Err: Debug,
|
||||||
|
{
|
||||||
|
fn from(s: (&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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: FromStr> From<(&str, &str, &str, &str, &str)> for SpacedList<A>
|
||||||
|
where
|
||||||
|
<A as FromStr>::Err: Debug,
|
||||||
|
{
|
||||||
|
fn from(s: (&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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: FromStr> From<(&str, &str, &str, &str, &str, &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: FromStr> From<(&str, &str, &str, &str, &str, &str, &str)> for SpacedList<A>
|
||||||
|
where
|
||||||
|
<A as FromStr>::Err: Debug,
|
||||||
|
{
|
||||||
|
fn from(s: (&str, &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.push(FromStr::from_str(s.6).unwrap());
|
||||||
|
list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: FromStr> From<(&str, &str, &str, &str, &str, &str, &str, &str)> for SpacedList<A>
|
||||||
|
where
|
||||||
|
<A as FromStr>::Err: Debug,
|
||||||
|
{
|
||||||
|
fn from(s: (&str, &str, &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.push(FromStr::from_str(s.6).unwrap());
|
||||||
|
list.push(FromStr::from_str(s.7).unwrap());
|
||||||
|
list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! spacedlist_from_array {
|
||||||
|
($num:tt) => {
|
||||||
|
impl<A: FromStr> From<[&str; $num]> for SpacedList<A>
|
||||||
|
where
|
||||||
|
<A as FromStr>::Err: Debug,
|
||||||
|
{
|
||||||
|
fn from(s: [&str; $num]) -> Self {
|
||||||
|
Self::from_iter(s.into_iter().map(|s| FromStr::from_str(*s).unwrap()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
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);
|
|
@ -0,0 +1,229 @@
|
||||||
|
use std::collections::BTreeSet;
|
||||||
|
use std::fmt::{Debug, Display, Error, Formatter};
|
||||||
|
use std::iter::FromIterator;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct SpacedSet<A: Ord>(BTreeSet<A>);
|
||||||
|
|
||||||
|
impl<A: Ord> SpacedSet<A> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
SpacedSet(BTreeSet::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Ord> Default for SpacedSet<A> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Ord> FromIterator<A> for SpacedSet<A> {
|
||||||
|
fn from_iter<I>(iter: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = A>,
|
||||||
|
{
|
||||||
|
SpacedSet(iter.into_iter().collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, A: 'a + Ord + Clone> FromIterator<&'a A> for SpacedSet<A> {
|
||||||
|
fn from_iter<I>(iter: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = &'a A>,
|
||||||
|
{
|
||||||
|
SpacedSet(iter.into_iter().cloned().collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, A: Ord + FromStr> From<&'a str> for SpacedSet<A>
|
||||||
|
where
|
||||||
|
<A as FromStr>::Err: Debug,
|
||||||
|
{
|
||||||
|
fn from(s: &'a str) -> Self {
|
||||||
|
Self::from_iter(s.split_whitespace().map(|s| FromStr::from_str(s).unwrap()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Ord> Deref for SpacedSet<A> {
|
||||||
|
type Target = BTreeSet<A>;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Ord> DerefMut for SpacedSet<A> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Ord + Display> Display for SpacedSet<A> {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||||
|
let mut it = self.0.iter().peekable();
|
||||||
|
while let Some(class) = it.next() {
|
||||||
|
Display::fmt(class, f)?;
|
||||||
|
if it.peek().is_some() {
|
||||||
|
Display::fmt(" ", f)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Ord + Debug> Debug for SpacedSet<A> {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||||
|
f.debug_list().entries(self.0.iter()).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Ord + FromStr> From<(&str, &str)> for SpacedSet<A>
|
||||||
|
where
|
||||||
|
<A as FromStr>::Err: Debug,
|
||||||
|
{
|
||||||
|
fn from(s: (&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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Ord + FromStr> From<(&str, &str, &str)> for SpacedSet<A>
|
||||||
|
where
|
||||||
|
<A as FromStr>::Err: Debug,
|
||||||
|
{
|
||||||
|
fn from(s: (&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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Ord + FromStr> From<(&str, &str, &str, &str)> for SpacedSet<A>
|
||||||
|
where
|
||||||
|
<A as FromStr>::Err: Debug,
|
||||||
|
{
|
||||||
|
fn from(s: (&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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Ord + FromStr> From<(&str, &str, &str, &str, &str)> for SpacedSet<A>
|
||||||
|
where
|
||||||
|
<A as FromStr>::Err: Debug,
|
||||||
|
{
|
||||||
|
fn from(s: (&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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Ord + FromStr> From<(&str, &str, &str, &str, &str, &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: Ord + FromStr> From<(&str, &str, &str, &str, &str, &str, &str)> for SpacedSet<A>
|
||||||
|
where
|
||||||
|
<A as FromStr>::Err: Debug,
|
||||||
|
{
|
||||||
|
fn from(s: (&str, &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.insert(FromStr::from_str(s.6).unwrap());
|
||||||
|
list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Ord + FromStr> From<(&str, &str, &str, &str, &str, &str, &str, &str)> for SpacedSet<A>
|
||||||
|
where
|
||||||
|
<A as FromStr>::Err: Debug,
|
||||||
|
{
|
||||||
|
fn from(s: (&str, &str, &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.insert(FromStr::from_str(s.6).unwrap());
|
||||||
|
list.insert(FromStr::from_str(s.7).unwrap());
|
||||||
|
list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! spacedlist_from_array {
|
||||||
|
($num:tt) => {
|
||||||
|
impl<A: Ord + FromStr> From<[&str; $num]> for SpacedSet<A>
|
||||||
|
where
|
||||||
|
<A as FromStr>::Err: Debug,
|
||||||
|
{
|
||||||
|
fn from(s: [&str; $num]) -> Self {
|
||||||
|
Self::from_iter(s.into_iter().map(|s| FromStr::from_str(*s).unwrap()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
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);
|
Loading…
Reference in New Issue