Guess I should put this under version control LOL
This commit is contained in:
commit
2035318460
73 changed files with 8836 additions and 0 deletions
91
lifecycle/src/rsx/mod.rs
Normal file
91
lifecycle/src/rsx/mod.rs
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
//! This module holds pieces pertaining to `RSX` element(s), which are lightweight
|
||||
//! structs that represent how something should be flushed to the screen. Alchemy
|
||||
//! uses these to build and alter UI; they're typically returned from `render()`
|
||||
//! methods.
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::fmt::{Debug, Display};
|
||||
|
||||
mod virtual_node;
|
||||
pub use virtual_node::VirtualNode;
|
||||
|
||||
mod virtual_text;
|
||||
pub use virtual_text::VirtualText;
|
||||
|
||||
mod props;
|
||||
pub use props::Props;
|
||||
|
||||
mod style_keys;
|
||||
pub use self::style_keys::StyleKey;
|
||||
|
||||
mod spacedlist;
|
||||
pub use self::spacedlist::SpacedList;
|
||||
|
||||
mod spacedset;
|
||||
pub use self::spacedset::SpacedSet;
|
||||
|
||||
pub type StylesList = SpacedSet<StyleKey>;
|
||||
|
||||
use crate::traits::Component;
|
||||
|
||||
/// An enum representing the types of nodes that the
|
||||
/// system can work with. `None`, `VirtualText`, or `VirtualNode`.
|
||||
#[derive(Clone)]
|
||||
pub enum RSX {
|
||||
None,
|
||||
VirtualText(VirtualText),
|
||||
VirtualNode(VirtualNode)
|
||||
}
|
||||
|
||||
impl RSX {
|
||||
/// Shorthand method for creating a new `RSX::VirtualNode` instance. Rarely should you call
|
||||
/// this yourself; the `rsx! {}` macro handles this for you.
|
||||
pub fn node<F: Fn() -> Box<Component> + Send + Sync + 'static>(tag: &'static str, create_fn: F, props: Props) -> RSX {
|
||||
RSX::VirtualNode(VirtualNode {
|
||||
tag: tag,
|
||||
create_component_fn: Arc::new(create_fn),
|
||||
instance: None,
|
||||
layout_node: None,
|
||||
props: props,
|
||||
children: vec![]
|
||||
})
|
||||
}
|
||||
|
||||
/// Shorthand method for creating a new `RSX::VirtualText` instance. Rarely should you call
|
||||
/// this yourself; the `rsx! {}` and `text!()` macros handle this for you.
|
||||
pub fn text(s: String) -> RSX {
|
||||
RSX::VirtualText(VirtualText(s))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for RSX {
|
||||
type Item = RSX;
|
||||
type IntoIter = std::vec::IntoIter<RSX>;
|
||||
|
||||
/// Turn a single `RSX` node into an iterable instance.
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
vec![self].into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RSX {
|
||||
/// Specialized rendering for displaying RSX nodes.
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
match self {
|
||||
RSX::VirtualNode(node) => { std::fmt::Display::fmt(&node, f) },
|
||||
RSX::VirtualText(text) => { std::fmt::Display::fmt(&text, f) }
|
||||
RSX::None => { Ok(()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for RSX {
|
||||
/// Specialized rendering for debugging RSX nodes.
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
RSX::VirtualNode(node) => { std::fmt::Debug::fmt(&node, f) },
|
||||
RSX::VirtualText(text) => { std::fmt::Debug::fmt(&text, f) }
|
||||
RSX::None => { Ok(()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
52
lifecycle/src/rsx/props.rs
Normal file
52
lifecycle/src/rsx/props.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
//! Implements a Props struct that mostly acts as expected. For arbitrary primitive values,
|
||||
//! it shadows a `serde_json::Value`.
|
||||
|
||||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::rsx::{RSX, StylesList};
|
||||
|
||||
/// A value stored inside the `attributes` field on a `Props` instance.
|
||||
/// It shadows `serde_json::Value`, but also allows for some other value
|
||||
/// types common to Alchemy.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum AttributeType {
|
||||
Value(Value),
|
||||
//RSX(RSX)
|
||||
//EventHandler(Box<ComponentEventHandler>)
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for AttributeType {
|
||||
/// Converts a &str to a storable AttributeType.
|
||||
fn from(f: &str) -> Self {
|
||||
AttributeType::Value(Value::String(f.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Emulates props from React, in a sense. Common keys such as `children`, `key` and `styles`
|
||||
/// are extracted out for fast access, and everything else found gets put into the `attributes`
|
||||
/// HashMap.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Props {
|
||||
pub attributes: HashMap<&'static str, AttributeType>,
|
||||
pub children: Vec<RSX>,
|
||||
pub key: String,
|
||||
pub styles: StylesList
|
||||
}
|
||||
|
||||
impl Props {
|
||||
/// Returns a Vec of RSX nodes, which are really just cloned pointers for the most part.
|
||||
pub fn children(&self) -> Vec<RSX> {
|
||||
self.children.clone()
|
||||
}
|
||||
|
||||
/// Returns a Option<&AttributeType> from the `attributes` inner HashMap.
|
||||
pub fn get(&self, key: &str) -> Option<&AttributeType> {
|
||||
match key {
|
||||
"children" => { None },
|
||||
"key" => { None },
|
||||
"styles" => { None },
|
||||
_ => { None } //self.attributes.get(key) }
|
||||
}
|
||||
}
|
||||
}
|
||||
262
lifecycle/src/rsx/spacedlist.rs
Normal file
262
lifecycle/src/rsx/spacedlist.rs
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
//! A space separated list of values.
|
||||
//!
|
||||
//! This type represents a list of non-unique values represented as a string of
|
||||
//! values separated by spaces in HTML attributes. This is rarely used; a
|
||||
//! SpacedSet of unique values is much more common.
|
||||
|
||||
|
||||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
use std::iter::FromIterator;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::str::FromStr;
|
||||
|
||||
/// A space separated list of values.
|
||||
///
|
||||
/// This type represents a list of non-unique values represented as a string of
|
||||
/// values separated by spaces in HTML attributes. This is rarely used; a
|
||||
/// SpacedSet of unique values is much more common.
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct SpacedList<A>(Vec<A>);
|
||||
|
||||
impl<A> SpacedList<A> {
|
||||
/// Construct an empty `SpacedList`.
|
||||
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, 'b, A: FromStr> From<(&'a str, &'b 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, 'b, 'c, A: FromStr> From<(&'a str, &'b str, &'c 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, 'b, 'c, 'd, A: FromStr> From<(&'a str, &'b str, &'c str, &'d 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, 'b, 'c, 'd, 'e, A: FromStr> From<(&'a str, &'b str, &'c str, &'d str, &'e 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, '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<(
|
||||
&'a str,
|
||||
&'b str,
|
||||
&'c str,
|
||||
&'d str,
|
||||
&'e str,
|
||||
&'f str,
|
||||
&'g 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, 'b, 'c, 'd, 'e, 'f, 'g, 'h, A: FromStr>
|
||||
From<(
|
||||
&'a str,
|
||||
&'b str,
|
||||
&'c str,
|
||||
&'d str,
|
||||
&'e str,
|
||||
&'f str,
|
||||
&'g str,
|
||||
&'h 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, A: FromStr> From<[&'a 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);
|
||||
293
lifecycle/src/rsx/spacedset.rs
Normal file
293
lifecycle/src/rsx/spacedset.rs
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
//! A space separated set of unique values.
|
||||
//!
|
||||
//! This type represents a set of unique values represented as a string of
|
||||
//! values separated by spaces in HTML attributes.
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt::{Debug, Display, Error, Formatter};
|
||||
use std::iter::FromIterator;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::str::FromStr;
|
||||
|
||||
/// A space separated set of unique values.
|
||||
///
|
||||
/// This type represents a set of unique values represented as a string of
|
||||
/// values separated by spaces in HTML attributes.
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct SpacedSet<A: Ord>(pub BTreeSet<A>);
|
||||
|
||||
impl<A: Ord> SpacedSet<A> {
|
||||
/// Construct an empty `SpacedSet`.
|
||||
pub fn new() -> Self {
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
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> FromStr for SpacedSet<A>
|
||||
where
|
||||
<A as FromStr>::Err: Debug,
|
||||
{
|
||||
type Err = <A as FromStr>::Err;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let result: Result<Vec<A>, Self::Err> =
|
||||
s.split_whitespace().map(|s| FromStr::from_str(s)).collect();
|
||||
result.map(Self::from_iter)
|
||||
}
|
||||
}
|
||||
|
||||
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, A: Ord + FromStr> From<Vec<&'a str>> for SpacedSet<A>
|
||||
where
|
||||
<A as FromStr>::Err: Debug,
|
||||
{
|
||||
fn from(s: Vec<&'a str>) -> Self {
|
||||
let mut list = Self::new();
|
||||
|
||||
for key in s {
|
||||
list.insert(FromStr::from_str(key).unwrap());
|
||||
}
|
||||
|
||||
list
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, A: Ord + FromStr> From<(&'a str, &'b 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, 'b, 'c, A: Ord + FromStr> From<(&'a str, &'b str, &'c 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, 'b, 'c, 'd, A: Ord + FromStr> From<(&'a str, &'b str, &'c str, &'d 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, 'b, 'c, 'd, 'e, A: Ord + FromStr> From<(&'a str, &'b str, &'c str, &'d str, &'e 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, '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<(
|
||||
&'a str,
|
||||
&'b str,
|
||||
&'c str,
|
||||
&'d str,
|
||||
&'e str,
|
||||
&'f str,
|
||||
&'g 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, 'b, 'c, 'd, 'e, 'f, 'g, 'h, A: Ord + FromStr>
|
||||
From<(
|
||||
&'a str,
|
||||
&'b str,
|
||||
&'c str,
|
||||
&'d str,
|
||||
&'e str,
|
||||
&'f str,
|
||||
&'g str,
|
||||
&'h 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, A: Ord + FromStr> From<[&'a 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);
|
||||
83
lifecycle/src/rsx/style_keys.rs
Normal file
83
lifecycle/src/rsx/style_keys.rs
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
//! A valid CSS class.
|
||||
//!
|
||||
//! A CSS class is a non-empty string that starts with an alphanumeric character
|
||||
//! and is followed by any number of alphanumeric characters and the
|
||||
//! `_`, `-` and `.` characters.
|
||||
|
||||
use std::fmt::{Display, Error, Formatter};
|
||||
use std::ops::Deref;
|
||||
use std::str::FromStr;
|
||||
|
||||
/// A valid CSS class.
|
||||
///
|
||||
/// A CSS class is a non-empty string that starts with an alphanumeric character
|
||||
/// and is followed by any number of alphanumeric characters and the
|
||||
/// `_`, `-` and `.` characters.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
pub struct StyleKey(String);
|
||||
|
||||
impl StyleKey {
|
||||
/// Construct a new styles list 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("style keys cannot be empty"),
|
||||
Some(c) if !c.is_alphabetic() => {
|
||||
return Err("style keys must start with an alphabetic character")
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
for c in chars {
|
||||
if !c.is_alphanumeric() && c != '-' {
|
||||
return Err(
|
||||
"style keys can only contain alphanumerics (dash included)",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(StyleKey(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!(
|
||||
"alchemy::dom::types::StyleKey: {:?} is not a valid class name: {}",
|
||||
id, err
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for StyleKey {
|
||||
type Err = &'static str;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
StyleKey::try_new(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for StyleKey {
|
||||
fn from(str: &'a str) -> Self {
|
||||
StyleKey::from_str(str).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for StyleKey {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for StyleKey {
|
||||
type Target = String;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
59
lifecycle/src/rsx/virtual_node.rs
Normal file
59
lifecycle/src/rsx/virtual_node.rs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
//! Implements the `RSX::VirtualNode` struct, which is a bit of a recursive
|
||||
//! structure.
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::fmt::{Display, Debug};
|
||||
|
||||
use alchemy_styles::node::Node;
|
||||
|
||||
use crate::traits::Component;
|
||||
use crate::rsx::{RSX, Props};
|
||||
|
||||
/// A VirtualNode is akin to an `Element` in React terms. Here, we provide a way
|
||||
/// for lazy `Component` instantiation, along with storage for things like layout nodes,
|
||||
/// properties, children and so on.
|
||||
#[derive(Clone)]
|
||||
pub struct VirtualNode {
|
||||
/// Used in debugging/printing/etc.
|
||||
pub tag: &'static str,
|
||||
|
||||
/// `Component` instances are created on-demand, if the reconciler deems it be so. This
|
||||
/// is a closure that should return an instance of the correct type.
|
||||
pub create_component_fn: Arc<Fn() -> Box<Component> + Send + Sync + 'static>,
|
||||
|
||||
/// A cached component instance, which is transferred between trees. Since `Component`
|
||||
/// instances are lazily created, this is an `Option`, and defaults to `None`.
|
||||
pub instance: Option<Arc<Component>>,
|
||||
|
||||
/// A cached `Node` for computing `Layout` with `Stretch`. Some components may not have
|
||||
/// a need for layout (e.g, if they don't have a backing node), and thus this is optional.
|
||||
///
|
||||
/// The reconciler will handle bridging tree structures as necessary.
|
||||
pub layout_node: Option<Node>,
|
||||
|
||||
/// `Props`, which are to be passed to this `Component` at various lifecycle methods.
|
||||
pub props: Props,
|
||||
|
||||
/// Computed children get stored here.
|
||||
pub children: Vec<RSX>
|
||||
}
|
||||
|
||||
impl Display for VirtualNode {
|
||||
/// Special formatting for displaying nodes.
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
write!(f, "<{}>", self.tag)?;
|
||||
|
||||
for child in &self.children {
|
||||
write!(f, "{:?}", child)?;
|
||||
}
|
||||
|
||||
write!(f, "</{}>", self.tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for VirtualNode {
|
||||
/// Special formatting for debugging nodes.
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "VirtualNode({})", self.tag)
|
||||
}
|
||||
}
|
||||
29
lifecycle/src/rsx/virtual_text.rs
Normal file
29
lifecycle/src/rsx/virtual_text.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
//! Implements `RSX::VirtualText`, which holds data pertaining to <Text>, primarily.
|
||||
|
||||
use std::fmt::{Display, Debug};
|
||||
|
||||
/// Currently a wrapper for `String`, but could be something else down the road. Frees
|
||||
/// us from needing to change the public API later.
|
||||
#[derive(Clone)]
|
||||
pub struct VirtualText(pub String);
|
||||
|
||||
impl VirtualText {
|
||||
/// Given a `String`, returns a `VirtualText` node.
|
||||
pub fn new(s: String) -> VirtualText {
|
||||
VirtualText(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for VirtualText {
|
||||
/// Formatting for `VirtualText` display.
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for VirtualText {
|
||||
/// Formatting for `VirtualText` debugging.
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "VirtualText({})", self.0)
|
||||
}
|
||||
}
|
||||
Reference in a new issue