Skip to content

Commit

Permalink
version 2.0 rewrite
Browse files Browse the repository at this point in the history
  • Loading branch information
clinuxrulz committed Apr 21, 2020
1 parent 61c601d commit bf14efa
Show file tree
Hide file tree
Showing 63 changed files with 4,003 additions and 5,119 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/target
**/*.rs.bk
Cargo.lock
/.vscode
/.idea
4 changes: 0 additions & 4 deletions Cargo.lock

This file was deleted.

10 changes: 8 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
[package]
name = "sodium-rust"
description = "Sodium FRP (Functional Reactive Programming)"
version = "1.0.1"
version = "2.0.0"
authors = ["Clinton Selke <[email protected]>"]
edition = "2018"
license = "BSD-3-Clause"
repository = "https:/SodiumFRP/sodium-rust"
keywords = ["frp"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
log = "0.4.8"

[dev-dependencies]
env_logger = "0.7.1"
49 changes: 1 addition & 48 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,10 @@
# Sodium
A Functional Reactive Programming (FRP) library for Rust

Avaliable on crates.io: https://crates.io/crates/sodium-rust
See tests under src/tests for example usage. Sodium objects within lambda expressions are traced via lambda1, lambda2, etc. just like the TypeScript version does.

## Pitfalls

### No Global State

You must create a SodiumCtx for your application and keep passing it around in order to create sodium objects.

### Memory Management

To allow for sodium objects (or structs containing them) to be sent through ```StreamSink``` / ```CellSink```, ```Trace``` and ```Finalize``` traits must be implemented for them. If you have a struct that you know will not contain any sodium objects, then you can wrap it in ```NoGc``` to avoid having to implement those ```Trace``` and ```Finalize``` traits for it.

E.g.
```
#[derive(Clone)]
struct MyStruct {
a: u32,
b: u32
}
impl MyStruct {
fn new(a: u32, b: u32) -> MyStruct {
MyStruct { a, b }
}
}
let s2: StreamSink<NoGc<MyStruct>> = sodium_ctx.new_stream_sink();
s2.send(&NoGc::new(MyStruct::new(1,2)));
```

A ```NoGc<A>``` can be turned into a ```&A``` using the derefering operator ```*```, E.g. ```*my_value```.

If you are however, passing a struct that does reference sodium objects, then you must implement the ```Trace``` and ```Finalize``` traces for it.

E.g.
```
#[derive(Clone)]
struct SS2 {
s: StreamSink<i32>
}
impl SS2 {
fn new(sodium_ctx: &SodiumCtx) -> SS2 {
SS2 {
s: sodium_ctx.new_stream_sink()
}
}
}
impl Finalize for SS2 {
fn finalize(&mut self) {}
}
impl Trace for SS2 {
fn trace(&self, f: &mut FnMut(&GcDep)) {
self.s.trace(f)
}
}
```
89 changes: 89 additions & 0 deletions src/cell.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use crate::impl_::cell::Cell as CellImpl;
use crate::impl_::lambda::IsLambda1;
use crate::impl_::lambda::IsLambda2;
use crate::impl_::lambda::IsLambda3;
use crate::impl_::lambda::IsLambda4;
use crate::impl_::lambda::IsLambda5;
use crate::impl_::lambda::IsLambda6;
use crate::impl_::lazy::Lazy;
use crate::listener::Listener;
use crate::sodium_ctx::SodiumCtx;
use crate::stream::Stream;
use crate::Dep;

pub struct Cell<A> {
pub impl_: CellImpl<A>
}

impl<A> Clone for Cell<A> {
fn clone(&self) -> Self {
Cell { impl_: self.impl_.clone() }
}
}

impl<A:Clone+Send+'static> Cell<A> {
pub fn new(sodium_ctx: &SodiumCtx, value: A) -> Cell<A> {
Cell { impl_: CellImpl::new(&sodium_ctx.impl_, value) }
}

pub fn sample(&self) -> A {
self.impl_.sample()
}

pub fn sample_lazy(&self) -> Lazy<A> {
self.impl_.sample_lazy()
}

// use as dependency to lambda1, lambda2, etc.
pub fn to_dep(&self) -> Dep {
self.impl_.to_dep()
}

pub fn updates(&self) -> Stream<A> {
Stream { impl_: self.impl_.updates() }
}

pub fn value(&self) -> Stream<A> {
Stream { impl_: self.impl_.value() }
}

pub fn map<B:Clone+Send+'static,FN:IsLambda1<A,B>+Send+Sync+'static>(&self, f: FN) -> Cell<B> {
Cell { impl_: self.impl_.map(f) }
}

pub fn lift2<B:Clone+Send+'static,C:Clone+Send+'static,FN:IsLambda2<A,B,C>+Send+'static>(&self, cb: &Cell<B>, f: FN) -> Cell<C> {
Cell { impl_: self.impl_.lift2(&cb.impl_, f) }
}

pub fn lift3<B:Clone+Send+'static,C:Clone+Send+'static,D:Clone+Send+'static,FN:IsLambda3<A,B,C,D>+Send+'static>(&self, cb: &Cell<B>, cc: &Cell<C>, f: FN) -> Cell<D> {
Cell { impl_: self.impl_.lift3(&cb.impl_, &cc.impl_, f) }
}

pub fn lift4<B:Clone+Send+'static,C:Clone+Send+'static,D:Clone+Send+'static,E:Clone+Send+'static,FN:IsLambda4<A,B,C,D,E>+Send+'static>(&self, cb: &Cell<B>, cc: &Cell<C>, cd: &Cell<D>, f: FN) -> Cell<E> {
Cell { impl_: self.impl_.lift4(&cb.impl_, &cc.impl_, &cd.impl_, f) }
}

pub fn lift5<B:Clone+Send+'static,C:Clone+Send+'static,D:Clone+Send+'static,E:Clone+Send+'static,F:Clone+Send+'static,FN:IsLambda5<A,B,C,D,E,F>+Send+'static>(&self, cb: &Cell<B>, cc: &Cell<C>, cd: &Cell<D>, ce: &Cell<E>, f: FN) -> Cell<F> {
Cell { impl_: self.impl_.lift5(&cb.impl_, &cc.impl_, &cd.impl_, &ce.impl_, f) }
}

pub fn lift6<B:Clone+Send+'static,C:Clone+Send+'static,D:Clone+Send+'static,E:Clone+Send+'static,F:Clone+Send+'static,G:Clone+Send+'static,FN:IsLambda6<A,B,C,D,E,F,G>+Send+'static>(&self, cb: &Cell<B>, cc: &Cell<C>, cd: &Cell<D>, ce: &Cell<E>, cf: &Cell<F>, f: FN) -> Cell<G> {
Cell { impl_: self.impl_.lift6(&cb.impl_, &cc.impl_, &cd.impl_, &ce.impl_, &cf.impl_, f) }
}

pub fn switch_s(csa: &Cell<Stream<A>>) -> Stream<A> {
Stream { impl_: CellImpl::switch_s(&csa.map(|sa: &Stream<A>| sa.impl_.clone()).impl_) }
}

pub fn switch_c(cca: &Cell<Cell<A>>) -> Cell<A> {
Cell { impl_: CellImpl::switch_c(&cca.map(|ca: &Cell<A>| ca.impl_.clone()).impl_) }
}

pub fn listen_weak<K: FnMut(&A)+Send+Sync+'static>(&self, k: K) -> Listener {
Listener { impl_: self.impl_.listen_weak(k) }
}

pub fn listen<K:IsLambda1<A,()>+Send+Sync+'static>(&self, k: K) -> Listener {
Listener { impl_: self.impl_.listen(k) }
}
}
32 changes: 32 additions & 0 deletions src/cell_loop.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use crate::Cell;
use crate::SodiumCtx;
use crate::impl_::cell_loop::CellLoop as CellLoopImpl;

pub struct CellLoop<A> {
impl_: CellLoopImpl<A>
}

impl<A> Clone for CellLoop<A> {
fn clone(&self) -> Self {
CellLoop {
impl_: self.impl_.clone()
}
}
}

impl<A:Send+Clone+'static> CellLoop<A> {

pub fn new(sodium_ctx: &SodiumCtx) -> CellLoop<A> {
CellLoop {
impl_: CellLoopImpl::new(&sodium_ctx.impl_)
}
}

pub fn cell(&self) -> Cell<A> {
Cell { impl_: self.impl_.cell() }
}

pub fn loop_(&self, ca: &Cell<A>) {
self.impl_.loop_(&ca.impl_);
}
}
29 changes: 29 additions & 0 deletions src/cell_sink.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use crate::impl_::cell_sink::CellSink as CellSinkImpl;
use crate::sodium_ctx::SodiumCtx;
use crate::cell::Cell;

pub struct CellSink<A> {
pub impl_: CellSinkImpl<A>
}

impl<A> Clone for CellSink<A> {
fn clone(&self) -> Self {
CellSink {
impl_: self.impl_.clone()
}
}
}

impl<A:Clone+Send+'static> CellSink<A> {
pub fn new(sodium_ctx: &SodiumCtx, a: A) -> CellSink<A> {
CellSink { impl_: CellSinkImpl::new(&sodium_ctx.impl_, a) }
}

pub fn cell(&self) -> Cell<A> {
Cell { impl_: self.impl_.cell() }
}

pub fn send(&self, a: A) {
self.impl_.send(a);
}
}
Loading

0 comments on commit bf14efa

Please sign in to comment.