diff --git a/packages/uischema/src/config.rs b/packages/uischema/src/config.rs index 0b27fb2..b70b0b8 100644 --- a/packages/uischema/src/config.rs +++ b/packages/uischema/src/config.rs @@ -1,3 +1,5 @@ + + use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -80,3 +82,10 @@ pub enum UISchemable { #[derive(Debug, Deserialize, Serialize, JsonSchema)] pub struct UISchema(UISchemable); + +enum ScopePath { + One, + Many, // when we need to zoom in on an array +} + +// fn get_scope_paths(uischemable: UISchemable) -> Vec {} diff --git a/packages/uischema/src/lib.rs b/packages/uischema/src/lib.rs index 076117e..c501c1b 100644 --- a/packages/uischema/src/lib.rs +++ b/packages/uischema/src/lib.rs @@ -1,4 +1,5 @@ mod config; +mod optics; mod output; mod utils; diff --git a/packages/uischema/src/optics.rs b/packages/uischema/src/optics.rs new file mode 100644 index 0000000..6db5688 --- /dev/null +++ b/packages/uischema/src/optics.rs @@ -0,0 +1,168 @@ +pub type Get = Box A>; +pub type Apply = Box S>; +pub type Set = Box S>; +pub type GetOption = Box Option>; + +pub struct Iso { + get: Get, + apply: Apply, +} + +impl Iso { + pub fn id() -> Self { + Self { + get: Box::new(|s| s), + apply: Box::new(|s| s), + } + } +} + +impl Iso +where + S: 'static, + A: 'static, +{ + pub fn map_invariant( + self, + covariant: impl Fn(A) -> B + 'static, + contravariant: impl Fn(B) -> A + 'static, + ) -> Iso { + let Self { get, apply } = self; + Iso { + get: Box::new(move |s| covariant(get(s))), + apply: Box::new(move |b| apply(contravariant(b))), + } + } + + pub fn lens(self) -> Lens { + let Self { get, apply } = self; + Lens { + get, + set: Box::new(move |_s, a| apply(a)), + } + } +} + +pub struct Lens { + get: Get, + set: Set, +} + +impl Lens { + pub fn id() -> Self { + Self { + get: Box::new(|s| s), + set: Box::new(|_s, a| a), + } + } +} + +impl Lens +where + S: 'static, + A: 'static, +{ + pub fn map_invariant( + self, + covariant: impl Fn(A) -> B + 'static, + contravariant: impl Fn(B) -> A + 'static, + ) -> Lens { + let Self { get, set } = self; + Lens { + get: Box::new(move |s| covariant(get(s))), + set: Box::new(move |s, b| set(s, contravariant(b))), + } + } + + pub fn prism(self) -> Prism { + let Self { get, set } = self; + Prism { + get_option: Box::new(move |s| Some(get(s))), + set, + } + } +} + +pub struct Prism { + get_option: GetOption, + set: Set, +} + +impl Prism { + pub fn id() -> Self { + Self { + get_option: Box::new(|s| Some(s)), + set: Box::new(|_s, a| a), + } + } +} + +impl Prism +where + S: 'static, + A: 'static, +{ + pub fn map_invariant( + self, + covariant: impl Fn(A) -> B + 'static, + contravariant: impl Fn(B) -> A + 'static, + ) -> Prism { + let Self { get_option, set } = self; + Prism { + get_option: Box::new(move |s| get_option(s).map(&covariant)), + set: Box::new(move |s, b| set(s, contravariant(b))), + } + } + + pub fn optional(self) -> Optional { + let Self { get_option, set } = self; + Optional { + get_option, + replace: set, + } + } +} + +pub struct Optional { + get_option: GetOption, + replace: Set, +} + +impl Optional { + pub fn id() -> Self { + Self { + get_option: Box::new(|s| Some(s)), + replace: Box::new(|_s, a| a), + } + } +} + +impl Optional +where + S: 'static, + A: 'static, +{ + pub fn map_invariant( + self, + covariant: impl Fn(A) -> B + 'static, + contravariant: impl Fn(B) -> A + 'static, + ) -> Optional { + let Self { + get_option, + replace, + } = self; + Optional { + get_option: Box::new(move |s| get_option(s).map(&covariant)), + replace: Box::new(move |s, b| replace(s, contravariant(b))), + } + } +} + +pub trait Traversal { + type Traversable: Iterator; + + fn get_all(s: S) -> Self::Traversable; + fn modify_all(f: F) -> fn(S) -> S + where + F: Fn(A) -> A; +} diff --git a/packages/uischema/src/output.rs b/packages/uischema/src/output.rs new file mode 100644 index 0000000..fa5286d --- /dev/null +++ b/packages/uischema/src/output.rs @@ -0,0 +1,19 @@ +// first thing I think of is JS values go in, js values come out +// a hashmap + +use std::collections::HashMap; + +use wasm_bindgen::JsValue; + +use crate::{optics::Optional}; + +// #/**/* +pub struct Scope(String); + +// so we send this map back to the client, how will the client like that? +pub struct OptionalsByScope(HashMap>); + +// need Schema to get the scopes +// Validate Schema against UISchema +// fn UISchema -> (Scope, Value) -> Data -> Data +// fn (UISchema -> Scopes) -> (Scope, Value) -> Data -> Data