Implementation of optimization passes to the FRP engine. (https://github.com/enso-org/ide/pull/135)

Original commit: 675039a37d
This commit is contained in:
Wojciech Daniło 2020-02-05 22:13:37 +01:00 committed by GitHub
parent 3c95b1502f
commit adf6a10fb9
31 changed files with 2599 additions and 832 deletions

View File

@ -8,6 +8,7 @@ members = [
"lib/core/msdf-sys",
"lib/data",
"lib/eval-tt",
"lib/frp",
"lib/ide/ast/impl",
"lib/ide/ast/macros",
"lib/ide/file-manager",

View File

@ -25,6 +25,6 @@ module.exports = {
},
performance: {
hints: 'error',
maxAssetSize: 4.5 * mb,
maxAssetSize: 4.7 * mb,
},
};

View File

@ -19,6 +19,7 @@ enso-prelude = { version = "0.1.0" , path = "../prelude" }
basegl-system-web = { version = "0.1.0" , path = "../system/web" }
code-builder = { version = "0.1.0" , path = "../code-builder" }
data = { version = "0.1.0" , path = "../data" }
enso-frp = { version = "0.1.0" , path = "../frp" }
eval-tt = { version = "0.1.0" , path = "../eval-tt" }
logger = { version = "0.1.0" , path = "../logger" }
optics = { version = "0.1.0" , path = "../optics" }

View File

@ -2,7 +2,6 @@
pub mod callback;
pub mod event_loop;
pub mod frp;
pub mod io;
pub use event_loop::*;

View File

@ -1,790 +0,0 @@
//! This module implements an Functional Reactive Programming system. It is an advanced event
//! handling framework which allows describing events and actions by creating declarative event
//! flow diagrams.
//!
//! **WARNING**
//! Please note that this file is under heavy development so it may be missing proper docs here and
//! there and the API can drastically change day after day.
use crate::prelude::*;
// ==============
// === Macros ===
// ==============
macro_rules! alias {
($( $(#$meta:tt)* $name:ident = {$($tok:tt)*} )*) => {$(
$(#$meta)*
pub trait $name: $($tok)* {}
impl<T:$($tok)*> $name for T {}
)*}
}
// ===============
// === Wrapper ===
// ===============
/// Trait for objects which wrap values.
///
/// Please note that this implements safe wrappers, so the object - value relation must be
/// bijective.
pub trait Wrapper {
/// The wrapped value type.
type Content;
/// Wraps the value and returns the wrapped type.
fn wrap(t:Self::Content) -> Self;
/// Unwraps this type to get the inner value.
fn unwrap(&self) -> &Self::Content;
}
/// Accessor for the wrapped value.
pub type Unwrap<T> = <T as Wrapper>::Content;
/// Wraps the value and returns the wrapped type.
pub fn wrap<T:Wrapper>(t:T::Content) -> T {
T::wrap(t)
}
/// Unwraps this type to get the inner value.
pub fn unwrap<T:Wrapper>(t:&T) -> &T::Content {
T::unwrap(t)
}
// ===============
// === Message ===
// ===============
// === Types ===
alias! {
/// Message is a data send between FRP nodes.
/// There are two important message implementation the `BehaviorMessage` and `EventMessage`.
Message = { MessageValue + ValueWrapper + KnownNodeStorage }
/// Abstraction for a value carried by a message.
MessageValue = { Clone + Debug + Default + 'static }
}
/// Accessor to a value of a given message. For example, `Value<Behavior<i32>>` resolves to `i32`.
pub type Value<T> = Unwrap<T>;
/// Alias to `Wrapper` with the inner type being `Debug`.
pub trait ValueWrapper = Wrapper where Unwrap<Self>:Debug;
// === Definition ===
/// A newtype containing a value of an event.
#[derive(Clone,Copy,Debug,Default)]
pub struct EventMessage<T>(T);
/// A newtype containing a value of a behavior.
#[derive(Clone,Copy,Debug,Default)]
pub struct BehaviorMessage<T>(T);
// === API ===
impl<T:Clone> EventMessage<T> {
/// Get the unwrapped value of this message.
pub fn value(&self) -> T {
self.unwrap().clone()
}
}
impl<T:Clone> BehaviorMessage<T> {
/// Get the unwrapped value of this message.
pub fn value(&self) -> T {
self.unwrap().clone()
}
}
// === Wrappers ===
impl Wrapper for () {
type Content = ();
fn wrap (_:()) -> Self {}
fn unwrap (&self) -> &() { self }
}
impl<T> Wrapper for EventMessage<T> {
type Content = T;
fn wrap (t:T) -> Self { EventMessage(t) }
fn unwrap (&self) -> &T { &self.0 }
}
impl<T> Wrapper for BehaviorMessage<T> {
type Content = T;
fn wrap (t:T) -> Self { BehaviorMessage(t) }
fn unwrap (&self) -> &T { &self.0 }
}
// ======================
// === Input / Output ===
// ======================
/// Event input associated type. Please note that FRP nodes can have maximum one event input.
/// In such a case this trait points to it.
pub trait KnownEventInput {
/// The event input type.
type EventInput : Message;
}
/// Event input accessor.
pub type EventInput<T> = <T as KnownEventInput>::EventInput;
/// Each FRP node has a single node, which type is described by this trait.
pub trait KnownOutput {
/// The output type.
type Output : Message;
}
/// Node output accessor.
pub type Output<T> = <T as KnownOutput>::Output;
// ===================
// === NodeStorage ===
// ===================
/// Type level abstraction for node internal storage.
pub trait KnownNodeStorage {
/// The node storage type.
type NodeStorage: CloneRef + Debug;
}
/// Internal node storage type accessor.
pub type NodeStorage<T> = <T as KnownNodeStorage>::NodeStorage;
impl KnownNodeStorage for () {
type NodeStorage = ();
}
// === EventNodeStorage ===
/// Event node operations.
pub trait EventNodeStorage: KnownOutput + Debug {
/// Registers a new event target. Whenever a new event arrives it will be transmitted to all
/// registered targets.
fn add_event_target(&self, target:AnyEventConsumer<Output<Self>>);
}
impl<Out> KnownNodeStorage for EventMessage<Out> {
type NodeStorage = Rc<dyn EventNodeStorage<Output=EventMessage<Out>>>;
}
// === BehaviorNodeStorage ===
/// Behavior node operations.
pub trait BehaviorNodeStorage: KnownOutput + Debug {
/// Returns the current value of the behavior.
fn current_value(&self) -> Value<Output<Self>>;
}
impl<Out> KnownNodeStorage for BehaviorMessage<Out> {
type NodeStorage = Rc<dyn BehaviorNodeStorage<Output=BehaviorMessage<Out>>>;
}
// ============
// === Node ===
// ============
// === Types ===
/// The type of any FRP node which produces event messages. Having a reference to a node is like
/// having a reference to network endpoint which transmits messages of a given type. Thus, it is a
/// nice mental simplification to think about it just like about an event (stream).
pub type Event<T> = Node<EventMessage<T>>;
/// The type of any FRP node which can be queried for behavior value. Having a reference to a node
/// is like having a reference to network endpoint which transmits messages of a given type. Thus,
/// it is a nice mental simplification to think about it just like about a behavior.
pub type Behavior <T> = Node<BehaviorMessage<T>>;
// === Definition ===
/// Node is used as a common types for frp operations. For example, `Event<T>` is just an alias to
/// `Node<EventMessage<T>>`.
#[derive(Debug)]
pub struct Node<Out:KnownNodeStorage> {
storage: NodeStorage<Out>,
}
impl<Out:Message> Node<Out> {
/// Constructor.
pub fn new(storage:NodeStorage<Out>) -> Self {
Self {storage}
}
}
// === Instances ===
impl<Out:Message> KnownOutput for Node<Out> { type Output = Out; }
impl<Out:KnownNodeStorage> Deref for Node<Out> {
type Target = NodeStorage<Out>;
fn deref(&self) -> &Self::Target {
&self.storage
}
}
impl<Out:KnownNodeStorage> Clone for Node<Out> {
fn clone(&self) -> Self {
let storage = self.storage.clone();
Self {storage}
}
}
impl<Out:KnownNodeStorage> CloneRef for Node<Out> {
fn clone_ref(&self) -> Self {
let storage = self.storage.clone_ref();
Self {storage}
}
}
impl<Out:KnownNodeStorage> From<&Node<Out>> for Node<Out> {
fn from(t:&Node<Out>) -> Self {
t.clone_ref()
}
}
// === Construction ===
impl<Storage,Out> From<&Storage> for Node<BehaviorMessage<Out>>
where Storage : BehaviorNodeStorage<Output=BehaviorMessage<Out>> + Clone + 'static,
Out : MessageValue {
fn from(storage:&Storage) -> Self {
Self::new(Rc::new(storage.clone()))
}
}
impl<Storage,Out> From<&Storage> for Node<EventMessage<Out>>
where Storage : EventNodeStorage<Output=EventMessage<Out>> + Clone + 'static,
Out : MessageValue {
fn from(storage:&Storage) -> Self {
Self::new(Rc::new(storage.clone()))
}
}
// === AddTarget ===
/// Abstraction for adding a target to a given node. Nodes which carry behaviors do not need to
/// perform any operation here, while event streams want to register the nodes they want to send
/// notifications to.
pub trait AddTarget<T> {
/// Adds a node as a target of the current flow.
fn add_target(&self,t:&T);
}
impl<S,T> AddTarget<S> for Node<EventMessage<T>>
where for<'t> &'t S : Into<AnyEventConsumer<EventMessage<T>>> {
fn add_target(&self,t:&S) {
self.add_event_target(t.into())
}
}
impl<S,T> AddTarget<S> for Node<BehaviorMessage<T>> {
fn add_target(&self,_:&S) {}
}
// ===================
// === NodeWrapper ===
// ===================
// === NodeWrapper ===
/// `NodeWrapper` is an outer layer for every FRP node. For example, the `Source<Out>` node is just
/// an alias to `NodeWrapper<SourceData<Out>>`, where `SourceData` is it's internal representation.
/// This struct bundles each node with information about target edges. Although the edges are used
/// only to send events, they are bundled to every node type in order to keep the implementation
/// simple.
pub type NodeWrapper<Shape> = NodeWrapperTemplate<Shape,Output<Shape>>;
impl<Shape:KnownOutput> NodeWrapper<Shape> {
/// Constructor.
pub fn construct(shape:Shape) -> Self {
let data = NodeWrapperTemplateData::construct(shape);
let rc = Rc::new(RefCell::new(data));
Self {rc}
}
}
impl<Shape:KnownOutput> NodeWrapper<Shape> {
/// Sends an event to all the children.
pub fn emit_event(&self, event:&Output<Shape>) {
self.rc.borrow().targets.iter().for_each(|target| {
target.on_event(event)
})
}
}
impl<Shape:KnownOutput + Debug>
EventNodeStorage for NodeWrapper<Shape>
where Output<Self>:'static, Output<Shape>:Message {
fn add_event_target(&self, target:AnyEventConsumer<Output<Self>>) {
self.rc.borrow_mut().targets.push(target);
}
}
impl<Shape:BehaviorNodeStorage + Debug>
BehaviorNodeStorage for NodeWrapper<Shape>
where Output<Shape>:Message {
fn current_value(&self) -> Value<Output<Self>> {
self.rc.borrow().shape.current_value()
}
}
// === NodeWrapperTemplate ===
/// Internal representation for `NodeWrapper`.
#[derive(Debug,Derivative)]
#[derivative(Default(bound="Shape:Default"))]
#[derivative(Clone(bound=""))]
pub struct NodeWrapperTemplate<Shape,Out> {
rc: Rc<RefCell<NodeWrapperTemplateData<Shape,Out>>>,
}
impl<Shape,Out:Message> KnownOutput for NodeWrapperTemplate<Shape,Out> {
type Output = Out;
}
impl<Shape:KnownEventInput,Out> KnownEventInput for NodeWrapperTemplate<Shape,Out>
where Value<EventInput<Shape>> : Debug {
type EventInput = EventInput<Shape>;
}
impl<Shape,Out> CloneRef for NodeWrapperTemplate<Shape,Out> {}
// === NodeWrapperTemplateData ===
/// Internal representation for `NodeWrapperTemplate`.
#[derive(Debug,Derivative)]
#[derivative(Default(bound="Shape:Default"))]
pub struct NodeWrapperTemplateData<Shape,Out> {
shape : Shape,
targets : Vec<AnyEventConsumer<Out>>,
}
impl<Shape,Out> NodeWrapperTemplateData<Shape,Out> {
/// Constructor.
pub fn construct(shape:Shape) -> Self {
let targets = default();
Self {shape,targets}
}
}
// =====================
// === EventConsumer ===
// =====================
// === Definition ===
/// Abstraction for nodes which are able to consume events.
pub trait EventConsumer: KnownEventInput + Debug {
/// Function called on every new received event.
fn on_event(&self, input:&Self::EventInput);
}
// === AnyEventConsumer ===
/// Abstraction for any node which consumes events of a given type.
#[derive(Clone,Debug,Shrinkwrap)]
pub struct AnyEventConsumer<In> {
raw: Rc<dyn EventConsumer<EventInput=In>>,
}
impl<In:Message> AnyEventConsumer<In> {
/// Constructor.
pub fn new<A:EventConsumer<EventInput=In>+'static>(a:A) -> Self {
let raw = Rc::new(a);
Self {raw}
}
}
impl<T,In> From<&T> for AnyEventConsumer<In>
where T : EventConsumer<EventInput=In> + Clone + 'static,
In : Message {
fn from(t:&T) -> Self {
Self::new(t.clone())
}
}
// =========================
// === Inference Helpers ===
// =========================
/// Message product type-level inference guidance.
pub trait Infer<T> {
/// Inference results.
type Result;
}
/// Accessor for inferred type.
pub type Inferred<T,X> = <X as Infer<T>>::Result;
// === Rules ===
macro_rules! inference_rules {
($( $pat:tt => $result:ident )*) => {$(
inference_rule! { $pat => $result }
)*}
}
macro_rules! inference_rule {
( $t1:ident => $result:ident ) => {
impl<X,T1> Infer <$t1<T1>> for X { type Result = $result<X>; }
};
( ($t1:ident) => $result:ident ) => {
impl<X,T1> Infer <$t1<T1>> for X { type Result = $result<X>; }
};
( ($t1:ident, $t2:ident) => $result:ident ) => {
impl<X,T1,T2> Infer <($t1<T1>,$t2<T2>)> for X { type Result = $result<X>; }
};
( ($t1:ident, $t2:ident, $t3:ident) => $result:ident ) => {
impl<X,T1,T2,T3> Infer <($t1<T1>,$t2<T2>,$t3<T3>)> for X { type Result = $result<X>; }
};
}
inference_rules! {
EventMessage => EventMessage
BehaviorMessage => BehaviorMessage
(EventMessage , EventMessage ) => EventMessage
(BehaviorMessage , EventMessage ) => EventMessage
(EventMessage , BehaviorMessage) => EventMessage
(BehaviorMessage , BehaviorMessage) => EventMessage
}
// =================================================================================================
// === FRP Nodes ===================================================================================
// =================================================================================================
// ==============
// === Source ===
// ==============
// === Storage ===
/// Internal source storage accessor.
pub type SourceStorage<T> = <T as KnownSourceStorage>::SourceStorage;
/// Internal source storage type.
pub trait KnownSourceStorage {
/// The result type.
type SourceStorage : Default;
}
impl<T> KnownSourceStorage for EventMessage <T> {type SourceStorage = ();}
impl<T:Default> KnownSourceStorage for BehaviorMessage<T> {type SourceStorage = BehaviorMessage<T>;}
// === Definition ===
/// Source is a begin point in the FRP network. It is able to emit events or initialize behaviors.
type Source<Out> = NodeWrapper<SourceData<Out>>;
/// Internal definition of the source FRP node.
#[derive(Derivative)]
#[derivative(Default (bound="SourceStorage<Out>:Default"))]
#[derivative(Debug (bound="SourceStorage<Out>:Debug"))]
pub struct SourceData<Out:KnownSourceStorage> {
storage: SourceStorage<Out>
}
impl<Out> KnownOutput for SourceData<Out>
where Out : KnownSourceStorage + Message {
type Output = Out;
}
impl<Out> Source<Out>
where Out : KnownSourceStorage + Message {
/// Constructor.
pub fn new() -> Self {
default()
}
}
impl<Out> BehaviorNodeStorage for SourceData<BehaviorMessage<Out>>
where Out : MessageValue {
fn current_value(&self) -> Out {
self.storage.value()
}
}
// ==============
// === Lambda ===
// ==============
/// Transforms input data with the provided function. Lambda accepts a single input and outputs
/// message of the same type as the input message.
pub type Lambda<In,Out> = NodeWrapper<LambdaShape<In,Out>>;
/// Internal representation of `Lambda`.
#[derive(Derivative)]
#[derivative(Debug)]
pub struct LambdaShape<In:Message,Out:Message> {
source : Node<In>,
#[derivative(Debug="ignore")]
func : Rc<dyn Fn(&Value<In>) -> Out>,
}
// === Instances ===
impl<In:Message,Out:Message> KnownEventInput for LambdaShape<In,Out> { type EventInput = In; }
impl<In:Message,Out:Message> KnownOutput for LambdaShape<In,Out> { type Output = Out; }
// === Constructor ===
/// Constructor abstraction. Used only to satisfy Rust type system.
pub trait LambdaNew<Source,Func> {
/// Constructor.
fn new(source:Source,f:Func) -> Self;
}
impl<In,OutVal,Func,Source> LambdaNew<Source,Func> for Lambda<In,Inferred<In,OutVal>>
where In : Message,
OutVal : Infer<In>,
Func : 'static + Fn(&Value<In>) -> OutVal,
Source : Into<Node<In>>,
Node<In> : AddTarget<Self>,
Inferred<In,OutVal> : Message<Content=OutVal> {
fn new (source:Source, f:Func) -> Self {
let source = source.into();
let source_ref = source.clone();
let shape = LambdaShape::new(source,f);
let this = Self::construct(shape);
source_ref.add_target(&this);
this
}
}
impl<In:Message,Out:Message> LambdaShape<In,Out> {
/// Constructor.
pub fn new<Func,Source>(source:Source, f:Func) -> Self
where Func : 'static + Fn(&Value<In>) -> Value<Out>,
Source : Into<Node<In>> {
let source = source.into();
let func = Rc::new(move |t:&Value<In>| { wrap(f(t)) });
Self {source,func}
}
}
impl<In:Message,Out:Message> EventConsumer for Lambda<In,Out> {
fn on_event(&self, input:&Self::EventInput) {
println!("GOT {:?}",input);
let output = (self.rc.borrow().shape.func)(unwrap(input));
self.emit_event(&output);
}
}
// ===============
// === Lambda2 ===
// ===============
/// Transforms input data with the provided function. `Lambda2` accepts two inputs. If at least one
/// of the inputs was event, the output message will be event as well. In case both inputs were
/// behavior, a new behavior will be produced.
pub type Lambda2<In1,In2,Out> = NodeWrapper<Lambda2Shape<In1,In2,Out>>;
/// Internal representation for `Lambda2`.
#[derive(Derivative)]
#[derivative(Debug)]
pub struct Lambda2Shape<In1:Message,In2:Message,Out:Message> {
source1 : Node<In1>,
source2 : Node<In2>,
#[derivative(Debug="ignore")]
func : Rc<dyn Fn(&Value<In1>,&Value<In2>) -> Out>,
}
impl<In1:Message,In2:Message,Out:Message>
Lambda2Shape<In1,In2,Out> {
/// Constructor.
pub fn new
< F:'static + Fn(&Value<In1>,&Value<In2>) -> Value<Out>
, Source1:Into<Node<In1>>
, Source2:Into<Node<In2>>
>
(source1:Source1, source2:Source2, f:F) -> Self {
let source1 = source1.into();
let source2 = source2.into();
let func = Rc::new(move |a:&Value<In1>,b:&Value<In2>| { wrap(f(a,b)) });
Self {source1,source2,func}
}
}
// === Instances ===
impl<In1,In2,Out> KnownEventInput for Lambda2Shape<EventMessage<In1>,BehaviorMessage<In2>,Out>
where In1:MessageValue,In2:MessageValue,Out:Message {
type EventInput = EventMessage<In1>;
}
impl<In1,In2,Out> KnownEventInput for Lambda2Shape<BehaviorMessage<In1>,EventMessage<In2>,Out>
where In1:MessageValue,In2:MessageValue,Out:Message {
type EventInput = EventMessage<In2>;
}
impl<In1,In2,Out> KnownOutput for Lambda2Shape<In1,In2,Out>
where In1:Message,In2:Message,Out:Message {
type Output = Out;
}
// === Construction ===
/// Constructor abstraction. Used only to satisfy Rust type system.
pub trait Lambda2New<Source1,Source2,Function> {
/// Constructor.
fn new(source:Source1, source2:Source2,f:Function) -> Self;
}
impl<In1,In2,OutVal,Source1,Source2,Function>
Lambda2New<Source1,Source2,Function> for Lambda2<In1,In2,Inferred<(In1,In2),OutVal>>
where In1 : Message,
In2 : Message,
OutVal : Infer<(In1,In2)>,
Source1 : Into<Node<In1>>,
Source2 : Into<Node<In2>>,
Function : 'static + Fn(&Value<In1>,&Value<In2>) -> OutVal,
Node<In1> : AddTarget<Self>,
Node<In2> : AddTarget<Self>,
Inferred<(In1,In2),OutVal> : Message<Content=OutVal> {
fn new (source1:Source1, source2:Source2, f:Function) -> Self {
let source1 = source1.into();
let source2 = source2.into();
let source1_ref = source1.clone();
let source2_ref = source2.clone();
let shape = Lambda2Shape::new(source1,source2,f);
let this = Self::construct(shape);
source1_ref.add_target(&this);
source2_ref.add_target(&this);
this
}
}
impl<In1,In2,Out> EventConsumer for Lambda2<EventMessage<In1>,BehaviorMessage<In2>,Out>
where In1:MessageValue, In2:MessageValue, Out:Message {
fn on_event(&self, event:&Self::EventInput) {
println!("GOT {:?}",event);
let value2 = self.rc.borrow().shape.source2.current_value();
let output = (self.rc.borrow().shape.func)(&event.value(),&value2);
self.emit_event(&output);
}
}
impl<In1,In2,Out> EventConsumer for Lambda2<BehaviorMessage<In1>,EventMessage<In2>,Out>
where In1:MessageValue, In2:MessageValue, Out:Message {
fn on_event(&self, event:&Self::EventInput) {
println!("GOT {:?}",event);
let value1 = self.rc.borrow().shape.source1.current_value();
let output = (self.rc.borrow().shape.func)(&value1,&event.value());
self.emit_event(&output);
}
}
// =================================================================================================
// === Examples ====================================================================================
// =================================================================================================
#[allow(missing_docs)]
mod tests {
use super::*;
// ================
// === Position ===
// ================
#[derive(Clone,Copy,Debug,Default)]
pub struct Position {
x:i32,
y:i32,
}
impl Position {
pub fn new(x:i32, y:i32) -> Self {
Self {x,y}
}
}
// ============
// === Test ===
// ============
#[allow(unused_variables)]
pub fn test () {
println!("\n\n\n--- FRP ---\n");
let mouse_position = Source::<BehaviorMessage<Position>>::new();
let e1 = Source::<EventMessage<i32>>::new();
let n1 = Lambda::new(&e1, |i| { i+1 });
let nn1: Event<i32> = (&n1).into();
let n2 = Lambda::new(&nn1, |i| { i*2 });
let n3: Lambda<BehaviorMessage<Position>, BehaviorMessage<Position>> =
Lambda::new(&mouse_position, |t| { *t });
let n3 = Lambda2::new(&n1,&mouse_position, |e,b| { *e });
// let n3 = Lambda2::new(&n1,&n2,|i,j| {i * j});
e1.emit_event(&EventMessage(7));
}
}
pub use tests::*;

View File

@ -15,7 +15,13 @@ use wasm_bindgen::prelude::*;
use crate::display::shape::primitive::def::*;
use crate::display::navigation::navigator::Navigator;
use crate::control::frp;
use crate::prelude::*;
use enso_frp::*;
use crate::system::web;
use crate::control::io::mouse2;
use crate::control::io::mouse2::MouseManager;
#[wasm_bindgen]
@ -47,18 +53,24 @@ fn init(world: &World) {
t.y += screen.height / 2.0;
});
let sprite2 = sprite.clone();
world.add_child(&shape_system);
let out = frp_test(Box::new(move|x:f32,y:f32| {
sprite2.set_position(Vector3::new(x,y,0.0));
}));
let mut iter:i32 = 0;
let mut time:i32 = 0;
world.on_frame(move |_| {
let _keep_alive = &navigator;
let _keep_alive = &out;
on_frame(&mut time,&mut iter,&sprite,&shape_system)
}).forget();
frp::test();
}
#[allow(clippy::too_many_arguments)]
@ -71,3 +83,52 @@ pub fn on_frame
*iter += 1;
shape_system.display_object().update();
}
// ================
// === FRP Test ===
// ================
#[allow(unused_variables)]
pub fn frp_test (callback: Box<dyn Fn(f32,f32)>) -> MouseManager {
let document = web::document().unwrap();
let mouse_manager = MouseManager::new(&document);
let mouse = Mouse::new();
frp! {
mouse_down_position = mouse.position.sample (&mouse.down);
mouse_position_if_down = mouse.position.gate (&mouse.is_down);
final_position_ref = recursive::<Position> ();
pos_diff_on_down = mouse_down_position.map2 (&final_position_ref,|m,f|{m-f});
final_position = mouse_position_if_down.map2 (&pos_diff_on_down ,|m,f|{m-f});
debug = final_position.sample (&mouse.position);
}
final_position_ref.initialize(&final_position);
// final_position.event.display_graphviz();
trace("X" , &debug.event);
final_position.map("foo",move|p| {callback(p.x as f32,-p.y as f32)});
let target = mouse.position.event.clone_ref();
let handle = mouse_manager.on_move.add(move |event:&mouse2::event::OnMove| {
target.emit(Position::new(event.client_x(),event.client_y()));
});
handle.forget();
let target = mouse.down.event.clone_ref();
let handle = mouse_manager.on_down.add(move |event:&mouse2::event::OnDown| {
target.emit(());
});
handle.forget();
let target = mouse.up.event.clone_ref();
let handle = mouse_manager.on_up.add(move |event:&mouse2::event::OnUp| {
target.emit(());
});
handle.forget();
mouse_manager
}

View File

@ -54,19 +54,19 @@ pub trait InternalFormat : Default + Into<AnyInternalFormat> + 'static {
type Sampler: Sampler;
/// Checks if the texture format can be rendered as color.
type ColorRenderable: Value<Type=bool>;
type ColorRenderable: KnownTypeValue<Value=bool>;
/// Checks it he texture can be filtered.
type Filterable: Value<Type=bool>;
type Filterable: KnownTypeValue<Value=bool>;
/// Checks if the texture format can be rendered as color.
fn color_renderable() -> bool {
<Self::ColorRenderable as Value>::value()
<Self::ColorRenderable as KnownTypeValue>::value()
}
/// Checks it he texture can be filtered.
fn filterable() -> bool {
<Self::Filterable as Value>::value()
<Self::Filterable as KnownTypeValue>::value()
}
}

12
gui/lib/frp/Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "enso-frp"
version = "0.1.0"
authors = ["Enso Team <contact@luna-lang.org>"]
edition = "2018"
[lib]
[dependencies]
enso-prelude = { version = "0.1.0" , path = "../prelude" }
basegl-system-web = { version = "0.1.0" , path = "../system/web" }
percent-encoding = { version = "2.1.0" }

10
gui/lib/frp/src/core.rs Normal file
View File

@ -0,0 +1,10 @@
//! Root module for core FRP types and abstractions.
pub mod node;
pub mod nodes;
pub use node::*;
pub use nodes::*;
// Fixes Derivative macro names aliasing.
pub use ::core::{fmt,default,clone};

View File

@ -0,0 +1,11 @@
//! Root module for FRP node related abstractions.
pub mod class;
pub mod id;
pub mod label;
pub mod wrapper;
pub use class::*;
pub use id::*;
pub use label::*;
pub use wrapper::*;

View File

@ -0,0 +1,305 @@
//! Defines FRP node related abstractions.
use crate::prelude::*;
use crate::debug::*;
use crate::node::id::*;
use crate::node::label::*;
use crate::data::*;
// =============
// === Types ===
// =============
alias! { no_docs
NodeReflection = { HasInputs + HasLabel + KnownOutputType }
NodeDebug = { Debug + GraphvizBuilder }
AnyNode = { NodeDebug + NodeReflection + HasId + HasDisplayId }
AnyNodeWithKnownOutput = { AnyNode + KnownOutput }
AnyBehaviorNode = { AnyNodeWithKnownOutput + HasCurrentValue }
AnyEventNode = { AnyNodeWithKnownOutput + HasEventTargets + EventEmitter }
}
// =========================
// === NodeAsTraitObject ===
// =========================
/// Type level association between FRP data type and a node's trait object. The associated type
/// differs depending on whether it is an event or behavior node, as they provide different APIs.
/// For example, behaviors allow lookup for the current value, which does not make sense in case
/// of events.
pub trait NodeAsTraitObjectForData {
/// The trait object representing the node.
type NodeAsTraitObject: AnyNodeWithKnownOutput + CloneRef;
}
/// Accessor. See docs of `NodeAsTraitObjectForData` to learn more.
pub type NodeAsTraitObject<T> = <T as NodeAsTraitObjectForData>::NodeAsTraitObject;
// === EventDynNode ===
/// Newtype wrapper for any event node.
#[derive(Debug,Derivative,Shrinkwrap)]
#[derivative(Clone(bound=""))]
pub struct EventDynNode<Out> {
rc: Rc<dyn AnyEventNode<Output=EventData<Out>>>,
}
impl<Out:Value> NodeAsTraitObjectForData for EventData<Out> {
type NodeAsTraitObject = EventDynNode<Out>;
}
impl<Out> Unwrap for EventDynNode<Out> {}
impl<Out> CloneRef for EventDynNode<Out> {}
impl<Out> HasContent for EventDynNode<Out> {
// TODO: Simplify after fixing https://github.com/rust-lang/rust/issues/68776
type Content = <EventDynNode<Out> as Deref>::Target;
}
impl<Out:Value> KnownOutput for EventDynNode<Out> {
type Output = EventData<Out>;
}
// === AnyBehaviorNode ===
/// Newtype wrapper for any behavior node.
#[derive(Debug,Derivative,Shrinkwrap)]
#[derivative(Clone(bound=""))]
pub struct BehaviorDynNode<Out> {
rc: Rc<dyn AnyBehaviorNode<Output=BehaviorData<Out>>>,
}
impl<Out:Value> NodeAsTraitObjectForData for BehaviorData<Out> {
type NodeAsTraitObject = BehaviorDynNode<Out>;
}
impl<Out> Unwrap for BehaviorDynNode<Out> {}
impl<Out> CloneRef for BehaviorDynNode<Out> {}
impl<Out> HasContent for BehaviorDynNode<Out> {
// TODO: Simplify after fixing https://github.com/rust-lang/rust/issues/68776
type Content = <BehaviorDynNode<Out> as Deref>::Target;
}
impl<Out:Value> KnownOutput for BehaviorDynNode<Out> {
type Output = BehaviorData<Out>;
}
// ============
// === Node ===
// ============
// === Types ===
/// Events represents discrete point in time. At a specific time, there can be at most one event.
/// Typical examples are mouse clicks, keyboard presses, status changes of the network connection.
pub type Event<T> = Node<EventData<T>>;
/// Behaviours represent a value over time that is always available. For example, mouse coordinates
/// vary in time and always have some value.
pub type Behavior <T> = Node<BehaviorData<T>>;
// === Definition ===
/// Node is used as a common types for frp operations. For example, `Event<T>` is just an alias to
/// `Node<EventData<T>>`.
#[derive(Derivative)]
#[derivative(Clone(bound=""))]
#[derivative(Debug(bound=""))]
pub struct Node<Out:NodeAsTraitObjectForData> {
storage: NodeAsTraitObject<Out>,
}
impl<Out:Data> Node<Out> {
/// Constructor.
pub fn new(storage:NodeAsTraitObject<Out>) -> Self {
Self {storage}
}
}
// === Type Deps ===
impl<Out:Data> KnownOutput for Node<Out> { type Output = Out; }
impl<Out:Data> HasContent for Node<Out> { type Content = NodeAsTraitObject<Out>; }
impl<Out:Data> Unwrap for Node<Out> {
fn unwrap(&self) -> &Self::Content {
&self.storage
}
}
// === Instances ===
impl<Out:Data> Deref for Node<Out> {
type Target = NodeAsTraitObject<Out>;
fn deref(&self) -> &Self::Target {
&self.storage
}
}
impl<Out:Data> CloneRef for Node<Out> {
fn clone_ref(&self) -> Self {
let storage = self.storage.clone_ref();
Self {storage}
}
}
// === Construction ===
impl<Out:Data> From<&Node<Out>> for Node<Out> {
fn from(t:&Node<Out>) -> Self {
t.clone_ref()
}
}
impl<Storage,Out:Value>
From<&Storage> for Behavior<Out>
where Storage : AnyBehaviorNode<Output=BehaviorData<Out>> + Clone + 'static {
fn from(storage:&Storage) -> Self {
Self::new(BehaviorDynNode{rc:Rc::new(storage.clone())})
}
}
impl<Storage,Out:Value>
From<&Storage> for Event<Out>
where Storage : AnyEventNode<Output=EventData<Out>> + Clone + 'static {
fn from(storage:&Storage) -> Self {
Self::new(EventDynNode{rc:Rc::new(storage.clone())})
}
}
// === AddTarget ===
/// Abstraction for adding a target to a given node. Nodes which carry behaviors do not need to
/// perform any operation here, while event streams want to register the nodes they want to send
/// notifications to.
pub trait AddTarget<T> {
/// Adds a node as a target of the current flow.
fn add_target(&self,t:&T);
}
impl<S,T:Value> AddTarget<S> for Event<T>
where for<'t> &'t S : Into<AnyEventConsumer<EventData<T>>> {
fn add_target(&self,t:&S) {
self.storage.add_event_target(t.into())
}
}
impl<S,T:Value> AddTarget<S> for Behavior<T> {
fn add_target(&self,_:&S) {}
}
// =========================
// === NodeWithAnyOutput ===
// =========================
/// A type for any possible node type. It hides the result type of a node, which makes it the most
/// generic node type out there.
#[derive(Debug,Shrinkwrap)]
pub struct NodeWithAnyOutput {
rc: Rc<dyn AnyNode>,
}
// === Instances ===
impls! { [Out:Data+'static] From <&Node<Out>> for NodeWithAnyOutput { |t| t.clone_ref().into() } }
impls! { [Out:Data+'static] From <Node<Out>> for NodeWithAnyOutput { |t| Self {rc:Rc::new(t)} } }
impl KnownOutputType for NodeWithAnyOutput {
fn output_type(&self) -> DataType {
self.rc.output_type()
}
fn output_type_value_name(&self) -> String {
self.rc.output_type_value_name()
}
}
// =====================
// === EventConsumer ===
// =====================
// === Definition ===
/// Abstraction for nodes which are able to consume events.
pub trait EventConsumer: KnownEventInput + Debug {
/// Function called on every new received event.
fn on_event(&self, input:&Content<Self::EventInput>);
}
// === AnyEventConsumer ===
/// Abstraction for any node which consumes events of a given type.
#[derive(Clone,Debug,Shrinkwrap)]
pub struct AnyEventConsumer<In> {
raw: Rc<dyn EventConsumer<EventInput=In>>,
}
impl<In:Data> AnyEventConsumer<In> {
/// Constructor.
pub fn new<A:EventConsumer<EventInput=In>+'static>(a:A) -> Self {
let raw = Rc::new(a);
Self {raw}
}
}
impl<T,In> From<&T> for AnyEventConsumer<In>
where T : EventConsumer<EventInput=In> + Clone + 'static,
In : Data {
fn from(t:&T) -> Self {
Self::new(t.clone())
}
}
// ====================
// === EventEmitter ===
// ====================
// === Definition ===
/// Abstraction for nodes which are able to emit events.
pub trait EventEmitter: KnownOutput {
/// Function for emitting new events.
fn emit_event(&self, event:&Content<Self::Output>);
}
impl<T> EventEmitter for T
where T:Unwrap+KnownOutput, Content<T>:EventEmitter<Output=Output<Self>> {
fn emit_event(&self, event:&Content<Self::Output>) {
self.unwrap().emit_event(event)
}
}
// === EventEmitterPoly ===
/// Polymorphic version of `EventEmitter`. Please note that `EventEmitter` could not be implemented
/// this way as we want to use it in a trait object, so all its methods have to be monomorphic.
pub trait EventEmitterPoly : KnownOutput where Output<Self>:HasContent {
/// Function for emitting new events.
fn emit<E:ToRef<Content<Self::Output>>>(&self, event:E);
}
impl<T:EventEmitter> EventEmitterPoly for T {
fn emit<E:ToRef<Content<Self::Output>>>(&self, event:E) {
self.emit_event(event.to_ref())
}
}

View File

@ -0,0 +1,49 @@
//! This module defines FRP node identifiers. They are mainly used for debugging purposes.
use crate::prelude::*;
// =============
// === HasId ===
// =============
/// Each FRP node is assigned with an unique ID. This is currently used mainly for debugging
/// purposes.
pub trait HasId {
/// Id of the entity.
fn id(&self) -> usize;
}
impl<T:Unwrap> HasId for T
where Content<T> : HasId {
default fn id(&self) -> usize {
self.unwrap().id()
}
}
// ====================
// === HasDisplayId ===
// ====================
/// Each FRP node can also be assigned with a `display_id`. Unlike `id`, the `display_id` does not
/// have to be unique. Nodes with the same `display_id` are displayed as a single node in the graph
/// view. Note that `display_id` defaults to `id` if not set explicitly to other value.
pub trait HasDisplayId {
/// Getter.
fn display_id(&self) -> usize;
/// Setter.
fn set_display_id(&self, id:usize);
}
impl<T> HasDisplayId for T
where T:Unwrap, Content<T> : HasDisplayId {
default fn display_id(&self) -> usize {
self.unwrap().display_id()
}
default fn set_display_id(&self, id:usize) {
self.unwrap().set_display_id(id)
}
}

View File

@ -0,0 +1,22 @@
//! This module defines FRP node labels. They are mainly used for debugging purposes.
use crate::prelude::*;
// =============
// === Label ===
// =============
/// Abstraction for labeled entities. Used mainly for debugging purposes.
pub trait HasLabel {
/// Label of the entity.
fn label(&self) -> &CowString;
}
impl<T:Unwrap> HasLabel for T
where Content<T> : HasLabel {
default fn label(&self) -> &CowString {
self.unwrap().label()
}
}

View File

@ -0,0 +1,189 @@
//! This module defines a common template structure used to define FRP nodes.
use crate::prelude::*;
use crate::data::*;
use crate::debug::*;
use crate::node::class::*;
use crate::node::id::*;
use crate::node::label::*;
// ===================
// === NodeWrapper ===
// ===================
// === NodeWrapper ===
/// `NodeWrapper` is an outer layer for every FRP node. For example, the `Source<Out>` node is just
/// an alias to `NodeWrapper<SourceShape<Out>>`, where `SourceShape` defines the data kept by the
/// node. This struct bundles each node with information about target edges. Although the edges are
/// used only to send events, they are bundled to every node type in order to keep the
/// implementation simple.
pub type NodeWrapper<Shape> = NodeWrapperTemplate<Shape,Output<Shape>>;
impl<Shape:KnownOutput> NodeWrapper<Shape> {
/// Constructor.
pub fn construct<Label>(label:Label, shape:Shape) -> Self
where Label : Into<CowString> {
let data = NodeWrapperTemplateMutable::new();
let config = Rc::new(RefCell::new(data));
let immutable = Rc::new(NodeWrapperTemplateImmutable::new(label,shape));
let this = Self {config,immutable};
this.set_display_id(this.id());
this
}
}
impl<Shape,Out:Data> NodeWrapperTemplate<Shape,Out> {
/// Sends an event to all the children.
pub fn emit_event_raw(&self, event:&Content<Out>) {
self.config.borrow().targets.iter().for_each(|target| {
target.on_event(event)
})
}
}
impl<Shape,T:Value>
HasEventTargets for NodeWrapperTemplate<Shape,EventData<T>> {
fn add_event_target(&self, target:AnyEventConsumer<EventData<T>>) {
self.config.borrow_mut().targets.push(target);
}
}
// === NodeWrapperTemplate ===
/// Internal representation for `NodeWrapper`. Please note that we define this structure and the
/// `NodeWrapper` alias instead of just single struct in order not to keep bounds on struct
/// definition (which is bad and you should never do it).
#[derive(Debug,Derivative,Shrinkwrap)]
#[derivative(Default(bound="Shape:Default"))]
#[derivative(Clone(bound=""))]
#[allow(missing_docs)]
pub struct NodeWrapperTemplate<Shape,Out> {
#[shrinkwrap(main_field)]
pub immutable : Rc<NodeWrapperTemplateImmutable<Shape>>,
pub config : Rc<RefCell<NodeWrapperTemplateMutable<Out>>>,
}
impl<Shape,Out> CloneRef for NodeWrapperTemplate<Shape,Out> {}
impl<Shape,Out>
HasId for NodeWrapperTemplate<Shape,Out> {
fn id(&self) -> usize {
Rc::downgrade(&self.config).as_raw() as *const() as usize
}
}
impl<Shape,Out>
HasDisplayId for NodeWrapperTemplate<Shape,Out> {
fn display_id (&self) -> usize { self.config.borrow().display_id }
fn set_display_id (&self, id:usize) { self.config.borrow_mut().display_id = id; }
}
impl<Shape,Out:Data>
KnownOutput for NodeWrapperTemplate<Shape,Out> {
type Output = Out;
}
impl<Shape,Out>
KnownEventInput for NodeWrapperTemplate<Shape,Out>
where Shape:KnownEventInput, EventInput<Shape>:Data {
type EventInput = EventInput<Shape>;
}
impl<Shape,T:Value>
EventEmitter for NodeWrapperTemplate<Shape,EventData<T>> {
fn emit_event(&self, event:&T) {
self.emit_event_raw(event);
}
}
impl<Shape:HasInputs,Out>
HasInputs for NodeWrapperTemplate<Shape,Out> {
fn inputs(&self) -> Vec<NodeWithAnyOutput> {
self.immutable.inputs()
}
}
impl<Shape,Out>
HasLabel for NodeWrapperTemplate<Shape,Out> {
fn label(&self) -> &CowString {
&self.label
}
}
impl<Shape:HasInputs,Out>
GraphvizBuilder for NodeWrapperTemplate<Shape,Out> {
fn graphviz_build(&self, builder:&mut Graphviz) {
let type_name = base_type_name::<Shape>();
let label = &self.label;
let id = self.id();
let display_id = self.display_id();
if !builder.contains(id) {
builder.add_node(id,display_id,type_name,label);
for input in &self.inputs() {
let input_display_id = input.display_id();
let input_type = input.output_type();
let input_type_name = input.output_type_value_name();
input.graphviz_build(builder);
builder.add_link(input_display_id,display_id,input_type,&input_type_name);
}
}
}
}
// === NodeWrapperTemplateImmutable ===
/// Internal representation for `NodeWrapperTemplate`.
#[derive(Debug,Default,Shrinkwrap)]
pub struct NodeWrapperTemplateImmutable<Shape> {
#[shrinkwrap(main_field)]
/// The shape of the node.
pub shape : Shape,
/// The label of the node. Used for debugging purposes.
pub label : CowString,
}
impl<Shape> NodeWrapperTemplateImmutable<Shape> {
/// Constructor.
pub fn new<Label>(label:Label, shape:Shape) -> Self
where Label : Into<CowString> {
let label = label.into();
Self {label,shape}
}
}
// === NodeWrapperTemplateMutable ===
/// Internal representation for `NodeWrapperTemplate`.
#[derive(Debug,Derivative)]
#[derivative(Default(bound=""))]
pub struct NodeWrapperTemplateMutable<Out> {
/// The display id of the node. Used to group nodes together in the visualization view.
pub display_id : usize,
/// Event targets of the node.
pub targets : Vec<AnyEventConsumer<Out>>,
}
impl<Out> NodeWrapperTemplateMutable<Out> {
/// Constructor.
pub fn new() -> Self {
default()
}
}
// === Utils ===
fn base_type_name<T>() -> String {
let qual_name = type_name::<T>();
let base_name = qual_name.split('<').collect::<Vec<_>>()[0];
let name = base_name.rsplit("::").collect::<Vec<_>>()[0];
let name = name.split("Shape").collect::<Vec<_>>()[0];
name.into()
}

View File

@ -0,0 +1,11 @@
//! Root module for FRP node definitions.
pub mod dynamic;
pub mod inference;
pub mod lambda;
pub mod prim;
pub use dynamic::*;
pub use inference::*;
pub use lambda::*;
pub use prim::*;

View File

@ -0,0 +1,319 @@
//! Root module for FRP Dynamic node types. The Dynamic type is a generalization of Event and
//! Behavior and is very easy to work with. You should use this type in most (all?) cases in your
//! FRP flows.
use crate::prelude::*;
use crate::data::*;
use crate::node::*;
use crate::nodes::prim::*;
use crate::nodes::lambda::*;
// ======================
// === RefinedDynamic ===
// ======================
/// Similar to `Dynamic` but with a known type of the `event` component. In most cases using
/// `Dynamic` is just fine. Sometimes however, you want to use a non-generic utilities of nodes,
/// like initializing a recursive one. By using `RefinedDynamic` you do not lose the information
/// about the specific shape of the node and you can access all of its methods directly.
#[derive(Debug,Derivative)]
#[derivative(Clone(bound="Event:Clone"))]
pub struct RefinedDynamic<Event>
where Event : KnownOutput,
Output<Event> : HasContent,
Content<Output<Event>> : Value {
/// The underlying dynamic.
pub dynamic : Dynamic<Content<Output<Event>>>,
/// The event with a known type. This is the same event as `dynamic.event`.
pub event : Event,
}
impl<Event> Deref for RefinedDynamic<Event>
where Event : KnownOutput,
Output<Event> : HasContent,
Content<Output<Event>> : Value {
type Target = Dynamic<Content<Output<Event>>>;
fn deref(&self) -> &Self::Target {
&self.dynamic
}
}
impl<E> From<&E> for RefinedDynamic<E>
where E : CloneRef + KnownOutput,
for <'t> &'t E : Into<Event<Content<Output<E>>>>,
Output<E> : HasContent,
Content<Output<E>> : Value {
fn from(event:&E) -> Self {
let event2 = event.into();
let event = event.clone_ref();
let dynamic = event2.into();
Self {event,dynamic}
}
}
impl<Out:Value> RefinedDynamic<Recursive<EventData<Out>>> {
/// Initialize the recursive `Dynamic` with a value. You need to perform this operation before
/// running the FRP graph.
pub fn initialize(&self, target:&Dynamic<Out>) {
self.event.initialize(&target.event);
self.event.set_display_id(target.event.display_id());
self.behavior.set_display_id(target.event.display_id());
}
}
// ===============
// === Dynamic ===
// ===============
/// The `Dynamic` type is an `Event` with an associated `Behavior`. You can assume that the
/// behavior just always holds the last event value.
#[derive(Debug,Derivative)]
#[derivative(Clone(bound=""))]
pub struct Dynamic<Out:Value> {
/// The `Event` component.
pub event : Event<Out>,
/// The `Behavior` component.
pub behavior : Behavior<Out>,
}
// === Constructors ===
impl<Out:Value> Dynamic<Out> {
/// Constructor.
pub fn new<E,B>(event:E, behavior:B) -> Self
where E:Into<Event<Out>>, B:Into<Behavior<Out>> {
let event = event.into();
let behavior = behavior.into();
Self {event,behavior}
}
/// Creates a new FRP source node.
pub fn source<Label>(label:Label) -> Self
where Label : Into<CowString> {
let event = Source::<EventData<Out>>::new_named(label);
(&event).into()
}
/// Create a new node which will be a placeholder (reference) to another node. Please note that
/// this node has to be initialized before the FRP network is run.
pub fn recursive<Label>(label:Label) -> RefinedDynamic<Recursive<EventData<Out>>>
where Label : Into<CowString> {
(&Recursive::<EventData<Out>>::new_named(label)).into()
}
}
// === Modifiers ===
impl<Out:Value> Dynamic<Out> {
/// Create a new node which drops the incoming event and emits a new event with the constant
/// value.
pub fn constant<Label,T>(&self, label:Label, value:T) -> Dynamic<T>
where Label:Into<CowString>, T:Value {
self.map(label,move |_| value.clone())
}
/// Creates a new node which merges two event streams. The output event will be emitted
/// whenever one of the streams emit an event.
pub fn merge<Label>(&self, label:Label, that:&Dynamic<Out>) -> Self
where Label:Into<CowString> {
(&Merge::new_named(label,&self.event,&that.event)).into()
}
/// Creates a new node which emits `true`, `false`, `true`, `false`, ... on every incoming
/// event.
pub fn toggle<Label>(&self, label:Label) -> Dynamic<bool>
where Label:Into<CowString> {
(&Toggle::new_named(label,&self.event)).into()
}
/// Creates a new node which passes the incoming event only if its second input is `true`.
pub fn gate<Label>(&self, label:Label, that:&Dynamic<bool>) -> Self
where Label:Into<CowString> {
(&Gate::new_named(label,that,self)).into()
}
/// Creates a node which samples this behavior on every incoming argument event. The incoming
/// event is dropped and a new event with the behavior value is emitted.
pub fn sample<Label,T>(&self, label:Label, that:&Dynamic<T>) -> Self
where Label : Into<CowString>,
T : Value {
(&Sample::new_named(label,&self.behavior,that)).into()
}
/// Creates a node which maps the current value with the provided lambda. This is one of the
/// most powerful utilities, however, you should try not to use it too often. The reason is that
/// it also makes optimizations impossible, as lambdas are like "black-boxes" for the FRP
/// engine.
pub fn map<Label,F,R>(&self, label:Label, f:F) -> Dynamic<R>
where Label : Into<CowString>,
R : Value,
F : 'static + Fn(&Out) -> R {
(&Lambda::new_named(label,&self.event,f)).into()
}
/// Creates a node which maps the current value with the provided lambda. This is one of the
/// most powerful utilities, however, you should try not to use it too often. The reason is that
/// it also makes optimizations impossible, as lambdas are like "black-boxes" for the FRP
/// engine.
pub fn map2<Label,T,F,R>(&self, label:Label, that:&Dynamic<T>, f:F) -> Dynamic<R>
where Label : Into<CowString>,
T : Value,
R : Value,
F : 'static + Fn(&Out,&T) -> R {
(&Lambda2::new_named(label,&self.event,that,f)).into()
}
}
// === Debug ===
impl<Out:Value+Eq> Dynamic<Out> {
/// Creates a new node which passes the incoming event trough and panics if it was not equal to
/// the given value.
pub fn assert_eq<Label>(&self, label:Label) -> RefinedDynamic<AssertEq<EventData<Out>>>
where Label:Into<CowString> {
(&AssertEq::new_named(label,&self.event)).into()
}
}
// === Instances ===
impl<Out:Value> CloneRef for Dynamic<Out> {
fn clone_ref(&self) -> Self {
let event = self.event.clone_ref();
let behavior = self.behavior.clone_ref();
Self {event,behavior}
}
}
impl<Out:Value, T:Into<Event<Out>>> From<T> for Dynamic<Out> {
fn from(t:T) -> Self {
let event = t.into();
let behavior = Hold :: new_named(event.label(),&event);
behavior.set_display_id(event.display_id());
let event = (&event).into();
let behavior = (&behavior).into();
Dynamic {event,behavior}
}
}
impl<Out:Value> From<&Dynamic<Out>> for Event<Out> {
fn from(t:&Dynamic<Out>) -> Self {
t.event.clone_ref()
}
}
impl<Out:Value> From<&Dynamic<Out>> for Behavior<Out> {
fn from(t:&Dynamic<Out>) -> Self {
t.behavior.clone_ref()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::frp_def;
#[test]
#[should_panic]
fn assert() {
frp_def! { source = source::<i32>() }
frp_def! { check = source.assert_eq() }
check.event.expect(1);
source.event.emit(2);
}
#[test]
fn constant() {
frp_def! { source = source::<i32>() }
frp_def! { constant = source.constant(7) }
frp_def! { check = constant.assert_eq() }
check.event.expect(7);
source.event.emit(0);
source.event.emit(7);
source.event.emit(1);
assert_eq!(check.event.success_count(),3);
}
#[test]
fn merge() {
frp_def! { source1 = source::<i32>() }
frp_def! { source2 = source::<i32>() }
frp_def! { merge = source1.merge(&source2) }
frp_def! { check = merge.assert_eq() }
check.event.expect(1);
source1.event.emit(1);
source2.event.emit(1);
check.event.expect(2);
source1.event.emit(2);
source2.event.emit(2);
assert_eq!(check.event.success_count(),4);
}
#[test]
fn toggle() {
frp_def! { source = source::<i32>() }
frp_def! { toggle = source.toggle() }
frp_def! { check = toggle.assert_eq() }
check.event.expect(true);
source.event.emit(0);
check.event.expect(false);
source.event.emit(0);
check.event.expect(true);
source.event.emit(0);
assert_eq!(check.event.success_count(),3);
}
#[test]
fn gate() {
frp_def! { source1 = source::<i32>() }
frp_def! { source2 = source::<bool>() }
frp_def! { gate = source1.gate(&source2) }
frp_def! { check = gate.assert_eq() }
source1.event.emit(0);
assert_eq!(check.event.success_count(),0);
source2.event.emit(true);
source1.event.emit(0);
assert_eq!(check.event.success_count(),1);
source2.event.emit(false);
source1.event.emit(0);
assert_eq!(check.event.success_count(),1);
}
#[test]
fn sample() {
frp_def! { source1 = source::<i32>() }
frp_def! { source2 = source::<i32>() }
frp_def! { sample = source1.sample(&source2) }
frp_def! { check = sample.assert_eq() }
check.event.expect(1);
source1.event.emit(1);
assert_eq!(check.event.success_count(),0);
source2.event.emit(0);
assert_eq!(check.event.success_count(),1);
source2.event.emit(0);
assert_eq!(check.event.success_count(),2);
}
#[test]
fn map() {
frp_def! { source = source::<i32>() }
frp_def! { map = source.map(|t| {t+1}) }
frp_def! { check = map.assert_eq() }
check.event.expect(1);
source.event.emit(0);
check.event.expect(2);
source.event.emit(1);
assert_eq!(check.event.success_count(),2);
}
}

View File

@ -0,0 +1,127 @@
//! This module defines inference helpers allowing for writing more general code in FRP node
//! generation macros.
use crate::data::*;
// =========================
// === Inference Helpers ===
// =========================
/// Data product type-level inference guidance. For a given input, it infers the product of FRP
/// data types. For example, for the input of `(BehaviorData<T1>,BehaviorData<T2>)`, the output
/// will be `BehaviorData<X>`. In case there is a single `EventData`, it will become the result.
/// For input `(BehaviorData<T1>,EventData<T2>)` it will resolve to `EventData<X>`.
pub trait InferProductType<T> {
/// Inference results.
type ProductType;
}
/// Accessor for inferred type.
pub type ProductType<T,X> = <X as InferProductType<T>>::ProductType;
// === Rules ===
/// Defines product type-level inference rules. To learn more, see the expanded version of the
/// usage below.
macro_rules! inference_rules {
($( $pat:tt => $result:ident )*) => {$(
inference_rule! { $pat => $result }
)*}
}
/// Internal utility for the `inference_rules` macro.
macro_rules! inference_rule {
( $t1:ident => $result:ident ) => {
impl<X,T1> InferProductType <$t1<T1>> for X {
type ProductType = $result<X>;
}
};
( ($t1:ident) => $result:ident ) => {
impl<X,T1> InferProductType <$t1<T1>> for X {
type ProductType = $result<X>;
}
};
( ($t1:ident, $t2:ident) => $result:ident ) => {
impl<X,T1,T2> InferProductType <($t1<T1>,$t2<T2>)> for X {
type ProductType = $result<X>;
}
};
( ($t1:ident, $t2:ident, $t3:ident) => $result:ident ) => {
impl<X,T1,T2,T3> InferProductType <($t1<T1>,$t2<T2>,$t3<T3>)> for X {
type ProductType = $result<X>;
}
};
}
inference_rules! {
EventData => EventData
BehaviorData => BehaviorData
(EventData , EventData ) => EventData
(BehaviorData , EventData ) => EventData
(EventData , BehaviorData) => EventData
(BehaviorData , BehaviorData) => EventData
}
// =========================
// === ContainsEventData ===
// =========================
// === Definition ===
/// From the given set of FRP data selects the first occurrence of `EventData` if any. For example,
/// `SelectEventData<(BehaviorData<T1>,EventData<T2>,EventData<T3>)>` resolves to `EventData<T2>`.
pub type SelectEventData<T> = <T as ContainsEventData>::Result;
/// From the given set of FRP data selects the first occurrence of `EventData` if any.
pub trait ContainsEventData {
/// The selected `EventData` type.
type Result : Data;
}
// === Instances ===
/// Defines instances for `ContainsEventData`. See the expanded version of the usages below to
/// learn more.
macro_rules! define_contains_event_data_impls {
($( $pat:tt => $result:ident<$result_type:ident> )*) => {$(
define_contains_event_data_impls_item! { $pat => $result<$result_type> }
)*}
}
/// Internal utility for the `define_contains_event_data_impls` macro.
macro_rules! define_contains_event_data_impls_item {
($( ($($pat:tt<$pat_type:ident>),*) => $result:ident<$result_type:ident> )*) => {$(
#[allow(unused_parens)]
impl<$($pat_type),*> ContainsEventData for ($($pat<$pat_type>),*)
where $result<$result_type> : Data {
type Result = $result<$result_type>;
}
)*}
}
define_contains_event_data_impls! {
( EventData <T1> ) => EventData<T1>
( EventData <T1> , EventData <T2> ) => EventData <T1>
( EventData <T1> , BehaviorData <T2> ) => EventData <T1>
( BehaviorData <T1> , EventData <T2> ) => EventData <T2>
( EventData <T1> , EventData <T2> , EventData <T3> ) => EventData <T1>
( BehaviorData <T1> , EventData <T2> , EventData <T3> ) => EventData <T2>
( EventData <T1> , BehaviorData <T2> , EventData <T3> ) => EventData <T1>
( EventData <T1> , EventData <T2> , BehaviorData <T3> ) => EventData <T1>
( BehaviorData <T1> , BehaviorData <T2> , EventData <T3> ) => EventData <T3>
( BehaviorData <T1> , EventData <T2> , BehaviorData <T3> ) => EventData <T2>
( EventData <T1> , BehaviorData <T2> , BehaviorData <T3> ) => EventData <T1>
}

View File

@ -0,0 +1,208 @@
//! This module defines a set of complex FRP building blocks. They allow you to run arbitrary Rust
//! code on the input data. You should rather not need to often use these.
use crate::prelude::*;
use crate::data::*;
use crate::node::*;
use crate::nodes::inference::*;
// ==============
// === Macros ===
// ==============
/// Similar to `deinfe_node` but specialized for lambda definitions.
///
/// Generates a ot of boilerplate for a new node definition. It generates the node struct, the
/// constructor, input / output relations, etc. In order to learn more, see the expanded version
/// of this macro used below.
macro_rules! define_lambda_node {
(
$(#$meta:tt)*
pub struct $name:ident $shape_name:ident [$($poly_input:ident)*]
{ $( $field:ident : $field_type:ty ),* }
) => {
$(#$meta)*
#[allow(non_camel_case_types)]
pub type $name<$($poly_input,)* Out> = NodeWrapper<$shape_name<$($poly_input,)* Out>>;
$(#$meta)*
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct $shape_name<$($poly_input:Data,)* Out:Data> {
$( $poly_input : Node<$poly_input> ),* ,
$( $field : $field_type ),*
}
#[allow(non_camel_case_types)]
impl<$($poly_input:Data,)* Out:Data>
KnownOutput for $shape_name<$($poly_input,)* Out> {
type Output = Out;
}
#[allow(non_camel_case_types,unused_parens)]
impl<$($poly_input:Data,)* Out:Data>
KnownEventInput for $shape_name<$($poly_input,)* Out>
where ($($poly_input),*) : ContainsEventData,
SelectEventData<($($poly_input),*)> : Data {
type EventInput = SelectEventData<($($poly_input),*)>;
}
paste::item! {
/// A constructor trait. Used only in order to make Rust type checker happy.
#[allow(non_camel_case_types)]
pub trait [<$name New>]<$($poly_input,)* Func> {
/// Constructor.
fn new_named<Label:Into<CowString>>
(label:Label, $($poly_input:$poly_input,)* f:Func) -> Self;
}
#[allow(non_camel_case_types,unused_parens)]
impl<$($poly_input,)* OutVal, $([<T $poly_input>],)* Function>
[<$name New>]<$([<T $poly_input>],)* Function>
for $name<$($poly_input,)* ProductType<($($poly_input),*),OutVal>>
where $($poly_input : Data,)*
$([<T $poly_input>] : Into<Node<$poly_input>>,)*
$(Node<$poly_input> : AddTarget<Self>,)*
OutVal : InferProductType<($($poly_input),*)>,
Function : 'static + Fn($(&Content<$poly_input>),*) -> OutVal,
ProductType<($($poly_input),*),OutVal> : Data<Content=OutVal> {
fn new_named<Label>
(label:Label, $($poly_input:[<T $poly_input>],)* func:Function) -> Self
where Label : Into<CowString> {
$(let $poly_input = $poly_input.into();)*
let func = func.into();
let shape = $shape_name{$($poly_input,)* func};
let this = Self::construct(label,shape);
{
$(this.$poly_input.add_target(&this);)*
}
this
}
}
}
#[allow(non_camel_case_types)]
impl<$($poly_input:Data,)* Out:Data> HasInputs for $shape_name<$($poly_input,)* Out> {
fn inputs(&self) -> Vec<NodeWithAnyOutput> {
vec![$((&self.$poly_input).into()),*]
}
}
}
}
// ==============
// === Lambda ===
// ==============
define_lambda_node! {
/// Transforms input data with the provided function. Lambda accepts a single input and outputs
/// message of the same type as the input message.
pub struct Lambda LambdaShape [source] {
func : Lambda1Func<source,Out>
}
}
// === LambdaFunc ===
/// Newtype wrapper for function stored in the `Lambda` node.
#[derive(Derivative)]
#[derivative(Debug)]
pub struct Lambda1Func<In1:Data,Out:Data> {
#[derivative(Debug="ignore")]
raw : Rc<dyn Fn(&Content<In1>) -> Out>
}
impl<In1,Out,Func> From<Func> for Lambda1Func<In1,Out>
where In1 : Data,
Out : Data,
Func : 'static + Fn(&Content<In1>) -> Content<Out> {
fn from(func:Func) -> Self {
let raw = Rc::new(move |a:&Content<In1>| { wrap(func(a)) });
Self {raw}
}
}
impl<In:Value,Out:Data> EventConsumer for Lambda<EventData<In>,Out> {
fn on_event(&self, input:&Content<Self::EventInput>) {
let output = (self.func.raw)(input);
self.emit_event_raw(unwrap(&output));
}
}
// ===============
// === Lambda2 ===
// ===============
define_lambda_node! {
/// Transforms input data with the provided function. `Lambda2` accepts two inputs. If at least
/// one of the inputs was event, the output message will be event as well. In case both inputs
/// were behavior, a new behavior will be produced.
pub struct Lambda2 Lambda2Shape [source1 source2] {
func : Lambda2Func<source1,source2,Out>
}
}
// === LambdaFunc ===
/// Newtype wrapper for function stored in the `Lambda2` node.
#[derive(Derivative)]
#[derivative(Debug)]
pub struct Lambda2Func<In1:Data,In2:Data,Out:Data> {
#[derivative(Debug="ignore")]
raw : Rc<dyn Fn(&Content<In1>,&Content<In2>) -> Out>
}
impl<In1,In2,Out,Func> From<Func> for Lambda2Func<In1,In2,Out>
where In1:Data, In2:Data, Out:Data,
Func : 'static + Fn(&Content<In1>,&Content<In2>) -> Content<Out> {
fn from(func:Func) -> Self {
let raw = Rc::new(move |a:&Content<In1>,b:&Content<In2>| { wrap(func(a,b)) });
Self {raw}
}
}
impl<In1,In2,Out> EventConsumer for Lambda2<EventData<In1>,BehaviorData<In2>,Out>
where In1:Value, In2:Value, Out:Data {
fn on_event(&self, event:&Content<Self::EventInput>) {
let value2 = self.source2.current_value();
let output = (self.func.raw)(event,&value2);
self.emit_event_raw(unwrap(&output));
}
}
impl<In1,In2,Out> EventConsumer for Lambda2<BehaviorData<In1>,EventData<In2>,Out>
where In1:Value, In2:Value, Out:Data {
fn on_event(&self, event:&Content<Self::EventInput>) {
let value1 = self.source1.current_value();
let output = (self.func.raw)(&value1,event);
self.emit_event_raw(unwrap(&output));
}
}
// =============
// === Utils ===
// =============
/// A debug trace utility. Prints every incoming event to the console.
pub fn trace<T,Label,Source>(label:Label, source:Source) -> Lambda<T,T>
where T : Data,
Label : Str,
Source : Into<Node<T>>,
Content<T> : Value + InferProductType<T,ProductType=T>,
Node<T> : AddTarget<Lambda<T,T>> {
let label = label.into();
Lambda::new_named("trace",source, move |t| {
println!("TRACE [{}]: {:?}", label, t);
t.clone()
})
}

View File

@ -0,0 +1,383 @@
//! This module defines a set of primitive FRP building blocks.
use crate::prelude::*;
use crate::data::*;
use crate::node::*;
use crate::nodes::inference::*;
// ==============
// === Macros ===
// ==============
/// Generates a ot of boilerplate for a new node definition. It generates the node struct, the
/// constructor, input / output relations, etc. In order to learn more, see the expanded version
/// of this macro used below.
macro_rules! define_node {
(
$(#$meta:tt)*
$name:ident $shape_name:ident [$($poly_input:ident)*] $(-> [$($out:tt)*])?
{ $( $field:ident : $field_type:ty ),* $(,)? }
) => {
/// The main type definition.
$(#$meta)*
#[allow(non_camel_case_types)]
pub type $name<$($poly_input,)*> = NodeWrapper<$shape_name<$($poly_input,)*>>;
/// Shape definition.
$(#$meta)*
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct $shape_name<$($poly_input:Data,)*> {
$( $poly_input : Node<$poly_input>,)*
$( $field : $field_type ),*
}
define_node_output! { $shape_name [$($poly_input)*] $(-> [$($out)*])? }
#[allow(non_camel_case_types,unused_parens)]
impl<$($poly_input:Data,)*>
KnownEventInput for $shape_name<$($poly_input,)*>
where ($($poly_input),*) : ContainsEventData,
SelectEventData<($($poly_input),*)> : Data {
type EventInput = SelectEventData<($($poly_input),*)>;
}
paste::item! {
#[allow(non_camel_case_types)]
impl<$($poly_input:Data,)*> $name<$($poly_input,)*>
where $shape_name<$($poly_input),*> : KnownOutput,
$(Node<$poly_input> : AddTarget<Self>,)*
$(Content<$poly_input> : Value,)*
{
/// Constructor.
pub fn new_named<Label,$([<T $poly_input>],)*>
(label:Label, $($poly_input:[<T $poly_input>],)*) -> Self
where Label : Into<CowString>,
$([<T $poly_input>] : Into<Node<$poly_input>>),*
{
$(let $poly_input = $poly_input.into();)*
$(let $field = default();)*
let shape = $shape_name { $($poly_input,)* $($field,)* };
let this = Self::construct(label,shape);
{
$(this.$poly_input.add_target(&this);)*
}
this
}
}
}
#[allow(non_camel_case_types)]
impl<$($poly_input:Data),*> HasInputs for $shape_name<$($poly_input),*> {
fn inputs(&self) -> Vec<NodeWithAnyOutput> {
vec![$((&self.$poly_input).into()),*]
}
}
}
}
/// Internal utility for the `define_node` macro.
macro_rules! define_node_output {
( $shape_name:ident [$($poly_input:ident)*] -> [$($out:tt)*] ) => {
#[allow(non_camel_case_types)]
impl<$($poly_input:Data,)*>
KnownOutput for $shape_name<$($poly_input,)*>
where $($out)* : Data {
type Output = $($out)*;
}
};
( $($t:tt)* ) => {};
}
// ==============
// === Source ===
// ==============
// === Storage ===
/// Internal source storage accessor.
pub type SourceStorage<T> = <T as KnownSourceStorage>::SourceStorage;
/// Internal source storage type.
pub trait KnownSourceStorage {
/// The result type.
type SourceStorage : Default;
}
impl<T> KnownSourceStorage for EventData <T> {type SourceStorage = ();}
impl<T:Default> KnownSourceStorage for BehaviorData<T> {type SourceStorage = BehaviorData<T>;}
// === Definition ===
/// Source is a begin point in the FRP network. It is able to emit events or initialize behaviors.
pub type Source<Out> = NodeWrapper<SourceShape<Out>>;
/// Internal definition of the source FRP node.
#[derive(Derivative)]
#[derivative(Default (bound="SourceStorage<Out>:Default"))]
#[derivative(Debug (bound="SourceStorage<Out>:Debug"))]
pub struct SourceShape<Out:KnownSourceStorage> {
storage: SourceStorage<Out>
}
impl<Out> KnownOutput for SourceShape<Out>
where Out : KnownSourceStorage + Data {
type Output = Out;
}
impl<Out> Source<Out>
where Out : KnownSourceStorage + Data {
/// Constructor.
pub fn new_named<Label:Into<CowString>>(label:Label) -> Self {
Self::construct(label,default())
}
}
impl<Out> HasCurrentValue for Source<BehaviorData<Out>>
where Out : Value {
fn current_value(&self) -> Out {
self.storage.value()
}
}
impl<Out:KnownSourceStorage> HasInputs for SourceShape<Out> {
fn inputs(&self) -> Vec<NodeWithAnyOutput> {
default()
}
}
// =============
// === Merge ===
// =============
define_node! {
Merge MergeShape [source1 source2] -> [source1] {}
}
impl<T1:Data,T2:Data> EventConsumer for Merge<T1,T2>
where MergeShape<T1,T2> : KnownEventInput<EventInput=Output<Self>> {
fn on_event(&self, event:&Content<Self::EventInput>) {
self.emit_event_raw(event);
}
}
// ==============
// === Toggle ===
// ==============
define_node! {
Toggle ToggleShape [source] -> [EventData<bool>] {
status : Cell<bool>
}
}
impl<T:Value> EventConsumer for Toggle<EventData<T>> {
fn on_event(&self, _:&Content<Self::EventInput>) {
let val = !self.status.get();
self.status.set(val);
self.emit_event_raw(&val);
}
}
// ================
// === AssertEq ===
// ================
define_node! {
AssertEq AssertEqShape [source] -> [source] {
expected_value : RefCell<Content<source>>,
success_count : Cell<usize>
}
}
impl<Out:Data> AssertEq<Out> {
/// Asserts that the next event value will be equal to this value. In other case, it will
/// panic after next even occurs and it will behave just as `asser_eq`.
pub fn expect(&self, value:Content<Out>) {
*self.expected_value.borrow_mut() = value;
}
/// Provides the count of successful events which went trough this node.
pub fn success_count(&self) -> usize {
self.success_count.get()
}
}
impl<T:Value> EventConsumer for AssertEq<EventData<T>>
where for<'t> &'t T : Eq {
fn on_event(&self, event:&Content<Self::EventInput>) {
assert_eq!(event,&self.expected_value.borrow());
let success_count = self.success_count.get();
self.success_count.set(success_count + 1);
self.emit_event_raw(event);
}
}
// ============
// === Hold ===
// ============
define_node! {
Hold HoldShape [source] -> [BehaviorData<Content<source>>] {
last_val : RefCell<Content<source>>
}
}
impl<T:Value> EventConsumer for Hold<EventData<T>> {
fn on_event(&self, event:&Content<Self::EventInput>) {
*self.last_val.borrow_mut() = event.clone();
}
}
impl<T> HasCurrentValue for Hold<EventData<T>>
where T : Value {
fn current_value(&self) -> T {
self.last_val.borrow().clone()
}
}
// ==============
// === Sample ===
// ==============
define_node! {
Sample SampleShape [source1 source2] {}
}
impl<In1,In2> KnownOutput for SampleShape<EventData<In1>,BehaviorData<In2>>
where In1:Value, In2:Value {
type Output = EventData<In2>;
}
impl<In1,In2> KnownOutput for SampleShape<BehaviorData<In1>,EventData<In2>>
where In1:Value, In2:Value {
type Output = EventData<In1>;
}
impl<In1,In2> EventConsumer for Sample<BehaviorData<In1>,EventData<In2>>
where In1:Value, In2:Value {
fn on_event(&self, _:&Content<Self::EventInput>) {
let value = self.source1.current_value();
self.emit_event_raw(&value);
}
}
impl<In1,In2> EventConsumer for Sample<EventData<In1>,BehaviorData<In2>>
where In1:Value, In2:Value {
fn on_event(&self, _:&Content<Self::EventInput>) {
let value = self.source2.current_value();
self.emit_event_raw(&value);
}
}
// ============
// === Gate ===
// ============
define_node! {
Gate GateShape [source1 source2] {}
}
impl<In1,In2> KnownOutput for GateShape<EventData<In1>,BehaviorData<In2>>
where In1:Value, In2:Value {
type Output = EventData<In1>;
}
impl<In1,In2> KnownOutput for GateShape<BehaviorData<In1>,EventData<In2>>
where In1:Value, In2:Value {
type Output = EventData<In2>;
}
impl<In:Value> EventConsumer for Gate<BehaviorData<bool>,EventData<In>> {
fn on_event(&self, event:&Content<Self::EventInput>) {
let check = self.source1.current_value();
if check { self.emit_event_raw(event); }
}
}
// =================
// === Recursive ===
// =================
/// A very special FRP node. It allows the definition of recursive FRP flows. Please note that it
/// has to be initialized with a target node before it can be evaluated. See the examples to learn
/// more.
pub type Recursive<T> = NodeWrapper<RecursiveShape<T>>;
/// Shape definition.
#[derive(Debug)]
#[allow(non_camel_case_types)]
pub struct RecursiveShape<T:Data> {
source : RefCell<Option<Node<T>>>,
}
impl<T:Data> KnownOutput for RecursiveShape<T> {
type Output = T;
}
impl<T:Data> KnownEventInput for RecursiveShape<T> {
type EventInput = T;
}
// === Constructor ===
impl<T:Data> Recursive<T> {
/// Constructor.
pub fn new_named<Label>(label:Label) -> Self
where Label : Into<CowString> {
let source = default();
Self::construct(label,RecursiveShape{source})
}
/// Initializes this node with a target node. Note that this node could not be evaluated before
/// the initialization.
pub fn initialize<S>(&self, t:S)
where S : Into<Node<T>>,
Node<T> : AddTarget<Self> {
let node = t.into();
node.add_target(self);
self.set_display_id(node.display_id());
*self.source.borrow_mut() = Some(node);
}
}
impl<T:Data> EventConsumer for Recursive<T> {
fn on_event(&self, event:&Content<T>) {
self.emit_event_raw(event);
}
}
impl<T:Value> HasCurrentValue for Recursive<BehaviorData<T>> {
fn current_value(&self) -> T {
self.source.borrow().as_ref().unwrap().current_value()
}
}
impl<T:Data> HasInputs for RecursiveShape<T> {
fn inputs(&self) -> Vec<NodeWithAnyOutput> {
vec![self.source.borrow().as_ref().unwrap().clone_ref().into()]
}
}

177
gui/lib/frp/src/data.rs Normal file
View File

@ -0,0 +1,177 @@
//! This module defines abstraction for FRP data types.
use crate::prelude::*;
use crate::NodeAsTraitObjectForData;
use crate::AnyEventConsumer;
use crate::NodeWithAnyOutput;
// =============
// === Value ===
// =============
alias! {
/// Abstraction for a value carried by the data sent between FRP nodes.
Value = { Clone + Debug + Default + 'static }
}
/// Trait for every FRP data which contains valid FRP value.
pub trait KnownValue : HasContent {
/// The raw value of the data.
fn value(&self) -> Content<Self>;
}
// ============
// === Data ===
// ============
// === Types ===
alias! {
/// Data is information sent between FRP nodes. There are two possible data types:
/// `BehaviorData` and `EventData`.
Data = { Value + DebugWrapper + NodeAsTraitObjectForData + PhantomInto<DataType> }
}
/// A newtype containing a value of an event.
#[derive(Clone,Copy,Debug,Default)]
pub struct EventData<T>(pub T);
/// A newtype containing a value of a behavior.
#[derive(Clone,Copy,Debug,Default)]
pub struct BehaviorData<T>(pub T);
/// Alias to `Wrapper` with the inner type being `Debug`.
pub trait DebugWrapper = Wrapper where Content<Self> : Default + Debug;
// === DataType ===
/// A value-level information about the data type.
#[derive(Clone,Debug,Copy)]
#[allow(missing_docs)]
pub enum DataType {Event,Behavior}
impls!{[T] PhantomFrom<EventData<T>> for DataType { Self::Event }}
impls!{[T] PhantomFrom<BehaviorData<T>> for DataType { Self::Behavior }}
// === Instances ===
impl<T:Clone> KnownValue for EventData<T> {
fn value(&self) -> T {
self.unwrap().clone()
}
}
impl<T:Clone> KnownValue for BehaviorData<T> {
fn value(&self) -> T {
self.unwrap().clone()
}
}
// === Wrappers ===
impl<T> HasContent for EventData<T> { type Content = T; }
impl<T> Wrap for EventData<T> { fn wrap (t:T) -> Self { EventData(t) } }
impl<T> Unwrap for EventData<T> { fn unwrap (&self) -> &T { &self.0 } }
impl<T> HasContent for BehaviorData<T> { type Content = T; }
impl<T> Wrap for BehaviorData<T> { fn wrap (t:T) -> Self { BehaviorData(t) } }
impl<T> Unwrap for BehaviorData<T> { fn unwrap (&self) -> &T { &self.0 } }
// =============
// === Input ===
// =============
/// Event input associated type. Please note that FRP nodes can have maximum one event input.
/// In such a case this trait points to it.
pub trait KnownEventInput {
/// The event input type.
type EventInput : Data;
}
/// Event input accessor.
pub type EventInput<T> = <T as KnownEventInput>::EventInput;
/// Provides a list of all inputs to a node.
pub trait HasInputs {
/// Accessor.
fn inputs(&self) -> Vec<NodeWithAnyOutput>;
}
impl<T> HasInputs for T
where T:Unwrap, Content<T>:HasInputs {
fn inputs(&self) -> Vec<NodeWithAnyOutput> {
self.unwrap().inputs()
}
}
// ==============
// === Output ===
// ==============
// === Definition ===
/// Each FRP node has a single node, which type is described by this trait.
pub trait KnownOutput {
/// The output type.
type Output : Data;
}
/// Node output accessor.
pub type Output<T> = <T as KnownOutput>::Output;
impl<T:?Sized+KnownOutput> KnownOutput for Rc<T>
where Output<T> : Data {
type Output = Output<T>;
}
// === Traits ===
/// Trait for nodes which can register an event target.
pub trait HasEventTargets : KnownOutput {
/// Registers a new event target.
fn add_event_target(&self, target:AnyEventConsumer<Output<Self>>);
}
/// Trait for nodes which remember the current value.
pub trait HasCurrentValue : KnownOutput {
/// Gets the current value of the node.
fn current_value(&self) -> Content<Output<Self>>;
}
// === KnownOutputType ===
/// Value-level information about the node output type. Used mainly for debugging purposes.
#[allow(missing_docs)]
pub trait KnownOutputType {
fn output_type (&self) -> DataType;
fn output_type_value_name (&self) -> String;
}
impl<T:KnownOutput> KnownOutputType for T
where Output<Self> : Data {
fn output_type(&self) -> DataType {
PhantomData::<Output<Self>>.into()
}
fn output_type_value_name(&self) -> String {
let qual = type_name::<Output<Self>>();
let param = qual.split('<').skip(1).collect::<String>();
let param = &param[0..param.len()-1];
let param = param.rsplit("::").collect::<Vec<_>>()[0];
param.into()
}
}

5
gui/lib/frp/src/debug.rs Normal file
View File

@ -0,0 +1,5 @@
//! Root module for debugging utilities.
pub mod graphviz;
pub use graphviz::*;

View File

@ -0,0 +1,184 @@
//! This module defines FRP Graphviz bindings. It allows visualizing the FRP network as Graphviz
//! diagram.
use crate::prelude::*;
use crate::DataType;
// ================
// === Graphviz ===
// ================
/// Visualization data for a nodes.
#[derive(Debug,Clone)]
pub struct VizNode {
display_id : usize,
variant : String,
label : String,
}
impl VizNode {
/// Constructor
pub fn new(display_id:usize, variant:String, label:String) -> Self {
VizNode {display_id,variant,label}
}
}
/// Visualization data for a link between nodes.
#[derive(Debug,Clone)]
pub struct VizLink {
source_display_id : usize,
target_display_id : usize,
message_type : DataType,
data_type : String,
}
impl VizLink {
/// Constructor.
pub fn new
(source_display_id:usize, target_display_id:usize, message_type:DataType, data_type:String)
-> Self {
Self {source_display_id,target_display_id,message_type,data_type}
}
}
/// Graphviz FRP system visualizer.
#[derive(Debug,Default)]
pub struct Graphviz {
nodes : HashMap<usize,VizNode>,
labels : HashMap<usize,String>,
links : Vec<VizLink>,
}
impl Graphviz {
/// Defines a new node.
pub fn add_node<Tp:Str,Label:Str>
(&mut self, id:usize, display_id:usize, tp:Tp, label:Label) {
let tp = tp.into();
let label = label.into();
self.nodes.insert(id,VizNode::new(display_id,tp,label.clone()));
self.labels.insert(id,label);
}
/// Defines a new link between nodes.
pub fn add_link<S:Str>
(&mut self, source:usize, target:usize, message_type:DataType, data_type:S) {
let link = VizLink::new(source,target,message_type,data_type.into());
self.links.push(link);
}
/// Checks if a node with the given id is already registered in the node map.
pub fn contains(&mut self, id:usize) -> bool {
self.nodes.contains_key(&id)
}
/// Takes a set of nodes and outputs a map from `display_id` to a particular node. In case the
/// `display_id` points to several nodes, the node types `Hold` and `Recursive` has weaker
/// preference.
fn create_node_map(&self) -> HashMap<usize,VizNode> {
let mut node_map : HashMap<usize,VizNode> = default();
for node in self.nodes.values() {
let entry = node_map.entry(node.display_id);
let merged_entry = entry.and_modify(|node2|{
let variant = &node2.variant;
if variant == "Hold" || variant == "Recursive" {
*node2 = node.clone();
}
});
merged_entry.or_insert_with(|| node.clone());
}
node_map
}
/// Outputs a Graphviz Dot code.
pub fn to_code(&self) -> String {
let mut code = String::default();
let node_map = self.create_node_map();
for node in node_map.values() {
let color = match node.variant.as_str() {
"Toggle" => "534666",
"Gate" => "e69d45",
"Hold" => "308695",
"Lambda" => "d45769",
"Lambda2" => "d45769",
_ => "455054",
};
let fill = iformat!("[fillcolor=\"#{color}\"]");
let spacing = "<br/><FONT POINT-SIZE=\"5\"> </FONT><br/>";
let variant = iformat!("<FONT POINT-SIZE=\"9\">{node.variant}</FONT>");
let label = iformat!("[label=< {node.label} {spacing} {variant} >]");
let line = iformat!("\n{node.display_id} {fill} {label}");
code.push_str(&line);
}
for link in &self.links {
let source = &link.source_display_id;
let target = &link.target_display_id;
let data_type = &link.data_type;
let not_loop = source != target;
if not_loop {
let style = match link.message_type {
DataType::Behavior => "[style=\"dashed\"]",
_ => ""
};
let label = if data_type == "()" { "" } else { &data_type };
let label = iformat!("[label=\" {label}\"]");
let line = iformat!("\n{source} -> {target} {style} {label}");
code.push_str(&line);
}
}
let fonts = "[fontname=\"Helvetica Neue\" fontsize=11]";
let node_shape = "[shape=box penwidth=0 margin=0.12 style=\"rounded,filled\"]";
let node_style = "[fontcolor=white fillcolor=\"#5397dc\"]";
let edge_style = "[arrowsize=.7 fontcolor=\"#555555\"]";
let graph_cfg = iformat!("rankdir=TD; graph {fonts};");
let nodes_cfg = iformat!("node {fonts} {node_shape} {node_style};");
let edges_cfg = iformat!("edge {fonts} {edge_style};");
iformat!("digraph G {{ \n{graph_cfg} \n{nodes_cfg} \n{edges_cfg} \n{code} \n}}")
}
}
impl From<Graphviz> for String {
fn from(cfg:Graphviz) -> String {
cfg.to_code()
}
}
// =======================
// === GraphvizBuilder ===
// =======================
/// Trait for every node which can be visualized.
pub trait GraphvizBuilder {
/// Adds the current object to the builder.
fn graphviz_build(&self, builder:&mut Graphviz);
/// Converts the current object to Graphviz Dot syntax.
fn to_graphviz(&self) -> String {
let mut builder = Graphviz::default();
self.graphviz_build(&mut builder);
builder.into()
}
/// Converts the current object to Graphviz and displays it in a new tab in a web browser.
fn display_graphviz(&self) {
let code = self.to_graphviz();
let url = percent_encoding::utf8_percent_encode(&code,percent_encoding::NON_ALPHANUMERIC);
let url = format!("https://dreampuf.github.io/GraphvizOnline/#{}",url);
crate::web::window().open_with_url_and_target(&url,"_blank").unwrap();
}
}
impl<T> GraphvizBuilder for T
where T:Unwrap, Content<T>:GraphvizBuilder {
default fn graphviz_build(&self, builder:&mut Graphviz) {
self.unwrap().graphviz_build(builder)
}
}

5
gui/lib/frp/src/io.rs Normal file
View File

@ -0,0 +1,5 @@
//! Root module for Input / Output FRP bindings
pub mod mouse;
pub use mouse::*;

View File

@ -0,0 +1,74 @@
//! Mouse FRP bindings.
use crate::prelude::*;
use crate::nodes::*;
use crate::frp_def;
// ================
// === Position ===
// ================
/// A 2-dimensional position. Used for storing the mouse position on the screen.
#[derive(Clone,Copy,Debug,Default,PartialEq,Eq)]
#[allow(missing_docs)]
pub struct Position {
pub x:i32,
pub y:i32,
}
impl Position {
/// Constructor.
pub fn new(x:i32, y:i32) -> Self {
Self {x,y}
}
}
impl std::ops::Sub<&Position> for &Position {
type Output = Position;
fn sub(self, rhs: &Position) -> Self::Output {
let x = self.x - rhs.x;
let y = self.y - rhs.y;
Position {x,y}
}
}
// =============
// === Mouse ===
// =============
/// Mouse FRP bindings.
#[derive(Debug)]
pub struct Mouse {
/// The mouse up event.
pub up : Dynamic<()>,
/// The mouse down event.
pub down : Dynamic<()>,
/// Mouse button press status.
pub is_down : Dynamic<bool>,
/// Current mouse position.
pub position : Dynamic<Position>,
}
impl Default for Mouse {
fn default() -> Self {
frp_def! { mouse.up = source() }
frp_def! { mouse.down = source() }
frp_def! { mouse.position = source() }
frp_def! { mouse.down_bool = down.constant(true) }
frp_def! { mouse.up_bool = up.constant(false) }
frp_def! { mouse.is_down = down_bool.merge(&up_bool) }
Self {up,down,is_down,position}
}
}
impl Mouse {
/// Constructor.
pub fn new() -> Self {
default()
}
}

78
gui/lib/frp/src/lib.rs Normal file
View File

@ -0,0 +1,78 @@
//! This module implements an Functional Reactive Programming system. It is an advanced event
//! handling framework which allows describing events and actions by creating declarative event
//! flow diagrams.
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unsafe_code)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![feature(specialization)]
#![feature(trait_alias)]
#![feature(weak_into_raw)]
#![feature(associated_type_defaults)]
pub mod data;
pub mod debug;
pub mod io;
pub mod macros;
pub mod core;
pub use data::*;
pub use debug::*;
pub use io::*;
pub use macros::*;
pub use crate::core::*;
use enso_prelude as prelude;
use basegl_system_web as web;
// =============
// === Tests ===
// =============
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn drag_and_drop() {
let mouse = Mouse::new();
frp_def! { mouse_down_position = mouse.position.sample (&mouse.down) }
frp_def! { mouse_position_if_down = mouse.position.gate (&mouse.is_down) }
let final_position_ref_event = Recursive::<EventData<Position>>::new_named("final_position_ref");
let final_position_ref = Dynamic::from(&final_position_ref_event);
frp_def! { pos_diff_on_down = mouse_down_position.map2 (&final_position_ref,|m,f|{m-f}) }
frp_def! { final_position = mouse_position_if_down.map2 (&pos_diff_on_down ,|m,f|{m-f}) }
final_position_ref_event.initialize(&final_position);
final_position_ref.event.set_display_id(final_position.event.display_id());
final_position_ref.behavior.set_display_id(final_position.event.display_id());
assert_eq!(final_position.behavior.current_value(),Position::new(0,0));
mouse.position.event.emit(Position::new(3,4));
assert_eq!(final_position.behavior.current_value(),Position::new(0,0));
mouse.down.event.emit(());
assert_eq!(final_position.behavior.current_value(),Position::new(0,0));
mouse.position.event.emit(Position::new(4,6));
assert_eq!(final_position.behavior.current_value(),Position::new(1,2));
mouse.position.event.emit(Position::new(4,7));
assert_eq!(final_position.behavior.current_value(),Position::new(1,3));
mouse.up.event.emit(());
mouse.position.event.emit(Position::new(4,0));
assert_eq!(final_position.behavior.current_value(),Position::new(1,3));
mouse.down.event.emit(());
mouse.position.event.emit(Position::new(0,0));
assert_eq!(final_position.behavior.current_value(),Position::new(-3,3));
}
}

69
gui/lib/frp/src/macros.rs Normal file
View File

@ -0,0 +1,69 @@
//! This module defines common macros for FRP netwrok definition.
/// Utility for easy definition of the FRP network. In order to keep the network easy to debug and
/// reason about, each node constructor consumes a label. Providing labels manually is time
/// consuming and error prone. This utility infers the name from the assignment shape and provides
/// it automatically to the FRP node constructor.
#[macro_export]
macro_rules! frp {
($($ts:tt)*) => { split_on_terminator! { [[frp_lines]] [] [] $($ts)* } };
}
/// Utility for easy definition of the FRP network definition. Read docs of `frp` macro to learn
/// more.
#[macro_export]
macro_rules! frp_def {
($var:ident = $fn:ident $(::<$ty:ty>)? ($($args:tt)*)) => {
let $var = Dynamic $(::<$ty>)? :: $fn
( stringify!{$var}, $($args)* );
};
($scope:ident . $var:ident = $fn:ident $(::<$ty:ty>)? ($($args:tt)*)) => {
let $var = Dynamic $(::<$ty>)? :: $fn
( concat! {stringify!{$scope},".",stringify!{$var}}, $($args)* );
};
($var:ident = $fn:ident $(.$fn2:ident)* $(::<$ty:ty>)? ($($args:tt)*)) => {
let $var = $fn $(.$fn2)* $(::<$ty>)?
( concat! {stringify!{$var}}, $($args)* );
};
($scope:ident . $var:ident = $fn1:ident . $fn2:ident $(.$fn3:ident)* $(::<$ty:ty>)? ($($args:tt)*)) => {
let $var = $fn1 . $fn2 $(.$fn3)* $(::<$ty>)?
( concat! {stringify!{$scope},".",stringify!{$var}}, $($args)* );
};
}
/// Internal helper for the `frp` macro.
#[macro_export]
macro_rules! frp_lines {
([ $([$($line:tt)*])* ]) => {
$( frp_def! { $($line)* } )*
};
}
/// Splits the token stream on terminators.
#[macro_export]
macro_rules! split_on_terminator {
([[$($f:tt)*] $args:tt] $out:tt []) => {
$($f)*! { $args $out }
};
([[$($f:tt)*]] $out:tt []) => {
$($f)*! { $out }
};
($f:tt [$($out:tt)*] $current:tt ; $($ts:tt)*) => {
split_on_terminator! { $f [$($out)* $current] [] $($ts)* }
};
($f:tt $out:tt [$($current:tt)*] $t:tt $($ts:tt)*) => {
split_on_terminator! { $f $out [$($current)* $t] $($ts)* }
};
([[$($f:tt)*] $($args:tt)?] [$($out:tt)*] $current:tt) => {
split_on_terminator! { [[$($f)*] $($args)?] [$($out)* $current] [] }
};
}

View File

@ -0,0 +1,53 @@
//! This module defines copy-on-write String implementation.
use std::borrow::Cow;
use crate::impls;
use std::ops::Deref;
// =================
// === CowString ===
// =================
// === Definition ===
/// A copy-on-write String implementation. It is a newtype wrapper for `Cow<'static,str>` and
/// provides many useful impls for efficient workflow. Use it whenever you want to store a string
/// but you are not sure if the string will be allocated or not. This way you can store a static
/// slice as long as you can and switch to allocated String on demand.
#[derive(Clone,Debug,Default)]
pub struct CowString(Cow<'static,str>);
// === Conversions From CowString ===
impls!{ From <&CowString> for String { |t| t.clone().into() } }
impls!{ From <CowString> for String { |t| t.0.into() } }
// === Conversions To CowString ===
impls!{ From <Cow<'static,str>> for CowString { |t| Self(t) } }
impls!{ From <&Cow<'static,str>> for CowString { |t| Self(t.clone()) } }
impls!{ From <&'static str> for CowString { |t| Self(t.into()) } }
impls!{ From <String> for CowString { |t| Self(t.into()) } }
impls!{ From <&String> for CowString { |t| t.to_string().into() } }
impls!{ From <&CowString> for CowString { |t| t.clone() } }
// === Instances ===
impl Deref for CowString {
type Target = str;
fn deref(&self) -> &str {
self.0.deref()
}
}
impl AsRef<str> for CowString {
fn as_ref(&self) -> &str {
self.deref()
}
}

View File

@ -9,6 +9,16 @@
#![feature(specialization)]
#![feature(trait_alias)]
pub mod cow_string;
pub mod macros;
pub mod std_reexports;
pub mod wrapper;
pub use cow_string::*;
pub use macros::*;
pub use std_reexports::*;
pub use wrapper::*;
pub use boolinator::Boolinator;
pub use core::any::type_name;
pub use core::fmt::Debug;
@ -23,31 +33,7 @@ pub use num::Num;
pub use paste;
pub use shrinkwraprs::Shrinkwrap;
pub use smallvec::SmallVec;
pub use std::any::Any;
pub use std::cell::Ref;
pub use std::cell::RefCell;
pub use std::cell::RefMut;
pub use std::collections::BTreeMap;
pub use std::collections::HashMap;
pub use std::collections::HashSet;
pub use std::convert::identity;
pub use std::convert::TryFrom;
pub use std::convert::TryInto;
pub use std::fmt::Display;
pub use std::fmt;
pub use std::hash::Hash;
pub use std::iter::FromIterator;
pub use std::iter;
pub use std::marker::PhantomData;
pub use std::ops::Add;
pub use std::ops::Deref;
pub use std::ops::DerefMut;
pub use std::ops::Index;
pub use std::ops::IndexMut;
pub use std::rc::Rc;
pub use std::rc::Weak;
pub use std::slice::SliceIndex;
pub use std::slice;
use nalgebra::Matrix;
use nalgebra::DimName;
@ -118,6 +104,19 @@ impl<T> OptionOps for Option<T> {
// =============
// === ToRef ===
// =============
/// Similar to `AsRef` but more specific and automatically implemented for every type. Allows for
/// conversion `&T` to `&T` (identity) and `T` to `&T` for any type `T`. In contrast, `AsRef`
/// requires explicit impls, so for example you cannot do `let t:&() = ().as_ref()`
pub trait ToRef<T> where T:?Sized { fn to_ref(&self) -> &T; }
impl<T> ToRef<T> for T where T:?Sized { fn to_ref(&self) -> &T { self } }
impl<T> ToRef<T> for &T where T:?Sized { fn to_ref(&self) -> &T { self } }
// ================
// === CloneRef ===
// ================
@ -430,15 +429,17 @@ impl<T:Deref> WithContent for T
// =============
/// Defines relation between types and values, like between `True` and `true`.
pub trait Value {
pub trait KnownTypeValue {
/// The value-level counterpart of this type-value.
type Type;
type Value;
/// The value of this type-value.
fn value() -> Self::Type;
fn value() -> Self::Value;
}
pub type TypeValue<T> = <T as KnownTypeValue>::Value;
// =======================
@ -453,16 +454,16 @@ pub struct True {}
#[derive(Clone,Copy,Debug)]
pub struct False {}
impl Value for True {
type Type = bool;
fn value() -> Self::Type {
impl KnownTypeValue for True {
type Value = bool;
fn value() -> Self::Value {
true
}
}
impl Value for False {
type Type = bool;
fn value() -> Self::Type {
impl KnownTypeValue for False {
type Value = bool;
fn value() -> Self::Value {
false
}
}

View File

@ -0,0 +1,61 @@
//! This macro defines set of common macros which are useful across different projects.
/// Allows for nicer definition of impls, similar to what Haskell or Scala does. Reduces the needed
/// boilerplate. For example, the following usage:
///
/// ```compile_fail
/// struct A { name:String };
/// impls! { From<A> for String { |t| t.name.clone() } }
/// ```
///
/// compiles to:
/// ```
/// struct A { name:String };
/// impl From<A> for String {
/// fn from(t:A) -> Self {
/// t.name.clone()
/// }
/// }
/// ```
///
/// This macro is meant to support many standard traits (like From) and should grow in the future.
#[macro_export]
macro_rules! impls {
($([$($impl_params:tt)*])? From<$ty:ty> for $target:ty {
|$arg:tt| $($result:tt)*
} ) => {
#[allow(clippy::redundant_closure_call)]
impl <$($($impl_params)*)?> From <$ty> for $target {
fn from (arg:$ty) -> Self {
(|$arg:$ty| $($result)*)(arg)
}
}
};
($([$($impl_params:tt)*])? PhantomFrom<$ty:ty> for $target:ty {
$($result:tt)*
} ) => {
impl <$($($impl_params)*)?> From <PhantomData<$ty>> for $target {
fn from (_:PhantomData<$ty>) -> Self {
$($result)*
}
}
};
}
#[macro_export]
macro_rules! alias {
($( $(#$meta:tt)* $name:ident = {$($tok:tt)*} )*) => {$(
$(#$meta)*
pub trait $name: $($tok)* {}
impl<T:$($tok)*> $name for T {}
)*};
(no_docs $( $(#$meta:tt)* $name:ident = {$($tok:tt)*} )*) => {$(
$(#$meta)*
#[allow(missing_docs)]
pub trait $name: $($tok)* {}
impl<T:$($tok)*> $name for T {}
)*};
}

View File

@ -0,0 +1,29 @@
//! This module reexports several commonly used types defined in the standard library.
pub use std::any::Any;
pub use std::borrow::Cow;
pub use std::cell::Cell;
pub use std::cell::Ref;
pub use std::cell::RefCell;
pub use std::cell::RefMut;
pub use std::collections::BTreeMap;
pub use std::collections::HashMap;
pub use std::collections::HashSet;
pub use std::convert::identity;
pub use std::convert::TryFrom;
pub use std::convert::TryInto;
pub use std::fmt::Display;
pub use std::fmt;
pub use std::hash::Hash;
pub use std::iter::FromIterator;
pub use std::iter;
pub use std::marker::PhantomData;
pub use std::ops::Add;
pub use std::ops::Deref;
pub use std::ops::DerefMut;
pub use std::ops::Index;
pub use std::ops::IndexMut;
pub use std::rc::Rc;
pub use std::rc::Weak;
pub use std::slice::SliceIndex;
pub use std::slice;

View File

@ -0,0 +1,113 @@
//! This type defines Wrap / Unwrap utilities. Unwrap is like `Deref` but does not implement
//! `impl<'a, T> Unwrap for &'a T` in order to make it less error prone. `Wrap` is like `pure` in
//! applicative functors if lifts a value to the specific type.
use crate::std_reexports::*;
// ===============
// === Wrapper ===
// ===============
/// Trait for any type which wraps other type. See docs of `Wrapper` to learn more.
pub trait HasContent {
type Content : ?Sized;
}
/// Accessor for the wrapped value.
pub type Content<T> = <T as HasContent>::Content;
/// Trait which enables `Sized` super-bound on the `Content` type.
pub trait SizedContent = HasContent where Content<Self> : Sized;
/// Trait for objects which wrap values. Please note that this implements safe wrappers, so the
/// object - value relation must be bijective.
pub trait Wrapper = Wrap + Unwrap;
/// Wrapping utility for values.
pub trait Wrap : HasContent + SizedContent {
/// Wraps the value and returns the wrapped type.
fn wrap(t:Self::Content) -> Self;
}
/// Unwrapping utility for wrapped types.
///
/// Please note that this trait is very similar to the Deref trait. However, there is a very
/// important difference. Unlike `Deref`, there is no `impl<'a, T> Unwrap for &'a T` defined. The
/// existence of such impl is very error prone when writing complex impls. The `Deref` docs warn
/// about it explicitly: "[...] Because of this, Deref should only be implemented for smart pointers
/// to avoid confusion.". As an example, consider the following code which contains infinite loop:
///
/// ```compile_fail
/// pub trait HasId {
/// fn id(&self) -> usize;
/// }
///
/// // Notice the lack of bound `<T as Deref>::Target : HasId`
/// impl<T:Deref> HasId for T {
/// fn id(&self) -> usize {
/// self.deref().id()
/// }
/// }
/// ```
///
/// And the correct version:
///
/// ```compile_fail
/// pub trait HasId {
/// fn id(&self) -> usize;
/// }
///
/// // Notice the lack of bound `<T as Deref>::Target : HasId`
/// impl<T:Deref> HasId for T where <T as Deref>::Target : HasId {
/// fn id(&self) -> usize {
/// self.deref().id()
/// }
/// }
/// ```
///
/// Both versions compile fine, but the former loops for ever.
pub trait Unwrap : HasContent {
/// Unwraps this type to get the inner value.
fn unwrap(&self) -> &Self::Content;
}
// === Utils ===
/// Wraps the value and returns the wrapped type.
pub fn wrap<T:Wrap>(t:T::Content) -> T {
T::wrap(t)
}
/// Unwraps this type to get the inner value.
pub fn unwrap<T:Unwrap>(t:&T) -> &T::Content {
T::unwrap(t)
}
// === Default Impls ===
// FIXME: https://github.com/rust-lang/rust/issues/68776
//default impl<T:Deref> HasContent for T {
// type Content = <Self as Deref>::Target;
//}
default impl<T> Unwrap for T
where T:Deref<Target=Content<T>> {
fn unwrap (&self) -> &Self::Content {
self.deref()
}
}
// === Impls ===
impl<T:?Sized> HasContent for Rc<T> { type Content = T; }
impl<T> Wrap for Rc<T> { fn wrap(t:T) -> Self { Rc::new(t) } }
impl<T:?Sized> Unwrap for Rc<T> {}
impl HasContent for String { type Content = char; }
impl Wrap for String { fn wrap(t:char) -> Self { t.to_string() } }
impl<T> HasContent for Vec<T> { type Content = T; }
impl<T> Wrap for Vec<T> { fn wrap(t:T) -> Self { vec![t] } }