You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
273 lines
8.3 KiB
Rust
273 lines
8.3 KiB
Rust
use std::rc::Rc;
|
|
use std::sync::{Arc,Mutex};
|
|
|
|
#[derive(Clone)]
|
|
struct LazyList<A: Clone> {
|
|
buffer: Rc<Vec<A>>,
|
|
index: usize
|
|
}
|
|
impl<A: Clone> LazyList<A> {
|
|
fn new(buf: Vec<A>) -> LazyList<A> {
|
|
LazyList {
|
|
buffer: Rc::new(buf),
|
|
index: 0
|
|
}
|
|
}
|
|
fn next(&self) -> Option<(LazyList<A>,A)> {
|
|
if self.index < self.buffer.len() {
|
|
let new_item = self.buffer[self.index].clone();
|
|
let new_index = self.index + 1;
|
|
Some((LazyList {
|
|
buffer: Rc::clone(&self.buffer),
|
|
index: new_index
|
|
},new_item))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
fn effects_bind<A,B,C,F,G>(f: F, g: G) -> impl Fn(A) -> C
|
|
where F: Fn(A) -> B,
|
|
G: Fn(B) -> C {
|
|
move |a| g(f(a))
|
|
}
|
|
|
|
fn launch_missiles(i: i32) -> i32 {
|
|
println!("launching {} missiles", i);
|
|
i
|
|
}
|
|
|
|
struct ReactiveUnit<St,A,B> {
|
|
state: Arc<Mutex<St>>,
|
|
event_handler: Arc<Fn(&mut St,A) -> B>
|
|
}
|
|
impl<St: 'static,A: 'static,B: 'static> ReactiveUnit<St,A,B> {
|
|
fn new<F>(st: St, f: F) -> ReactiveUnit<St,A,B>
|
|
where F: 'static + Fn(&mut St,A) -> B
|
|
{
|
|
ReactiveUnit {
|
|
state: Arc::new(Mutex::new(st)),
|
|
event_handler: Arc::new(f)
|
|
}
|
|
}
|
|
fn bind<G,C>(&self, g: G) -> ReactiveUnit<St,A,C>
|
|
where G: 'static + Fn(&mut St,B) -> C {
|
|
let ev = Arc::clone(&self.event_handler);
|
|
ReactiveUnit {
|
|
state: Arc::clone(&self.state),
|
|
event_handler: Arc::new(move |st: &mut St,a| {
|
|
let r = ev(st,a);
|
|
let r = g(st,r);
|
|
r
|
|
})
|
|
}
|
|
}
|
|
fn plus<St2: 'static,C: 'static>(&self, other: ReactiveUnit<St2,B,C>) -> ReactiveUnit<(Arc<Mutex<St>>,Arc<Mutex<St2>>),A,C> {
|
|
let ev1 = Arc::clone(&self.event_handler);
|
|
let st1 = Arc::clone(&self.state);
|
|
let ev2 = Arc::clone(&other.event_handler);
|
|
let st2 = Arc::clone(&other.state);
|
|
ReactiveUnit {
|
|
state: Arc::new(Mutex::new((st1,st2))),
|
|
event_handler: Arc::new(move |stst: &mut (Arc<Mutex<St>>,Arc<Mutex<St2>>),a| {
|
|
let mut st1 = stst.0.lock().unwrap();
|
|
let r = ev1(&mut st1, a);
|
|
let mut st2 = stst.1.lock().unwrap();
|
|
let r = ev2(&mut st2, r);
|
|
r
|
|
})
|
|
}
|
|
}
|
|
fn apply(&self, a: A) -> B {
|
|
let mut st = self.state.lock().unwrap();
|
|
(self.event_handler)(&mut st, a)
|
|
}
|
|
}
|
|
|
|
fn main()
|
|
{
|
|
|
|
2 + 3;
|
|
|
|
|| 2 + 3;
|
|
|
|
let ll = LazyList::new(vec![1,2,3]);
|
|
let (ll1,a1) = ll.next().expect("expect 1 item");
|
|
println!("lazy item 1: {}", a1);
|
|
let (ll2,a2) = ll1.next().expect("expect 2 item");
|
|
println!("lazy item 2: {}", a2);
|
|
let (ll3,a3) = ll2.next().expect("expect 3 item");
|
|
println!("lazy item 3: {}", a3);
|
|
let (ll2,a2) = ll1.next().expect("expect 2 item");
|
|
println!("lazy item 2: {}", a2);
|
|
|
|
let e1 = |i| { println!("before {}", i); i };
|
|
let e2 = |i| { launch_missiles(i) };
|
|
let e3 = |i| { println!("after {}", i); i };
|
|
let s = effects_bind(effects_bind(e1,e2),e3);
|
|
s(22);
|
|
|
|
println!("\nrender 1:");
|
|
let render1 = ReactiveUnit::new((),|(),()| {
|
|
let html = r###"$('body').innerHTML = '
|
|
<header>
|
|
<h3 data-section="1" class="active">Section 1</h3>
|
|
<h3 data-section="2">Section 2</h3>
|
|
<h3 data-section="3">Section 3</h3>
|
|
</header>
|
|
<div>page content</div>
|
|
<footer>Copyright</footer>
|
|
';"###;
|
|
html.to_string()
|
|
});
|
|
println!("{}", render1.apply(()));
|
|
|
|
println!("\nrender 2:");
|
|
let render2 = ReactiveUnit::new((),|(),section: usize| {
|
|
let section_1 = r###"$('body').innerHTML = '
|
|
<header>
|
|
<h3 data-section="1" class="active">Section 1</h3>
|
|
<h3 data-section="2">Section 2</h3>
|
|
<h3 data-section="3">Section 3</h3>
|
|
</header>
|
|
<div>section 1 content</div>
|
|
<footer>Copyright</footer>
|
|
';"###;
|
|
|
|
let section_2 = r###"$('body').innerHTML = '
|
|
<header>
|
|
<h3 data-section="1">Section 1</h3>
|
|
<h3 data-section="2" class="active">Section 2</h3>
|
|
<h3 data-section="3">Section 3</h3>
|
|
</header>
|
|
<div>section 2 content</div>
|
|
<footer>Copyright</footer>
|
|
';"###;
|
|
|
|
let section_3 = r###"$('body').innerHTML = '
|
|
<header>
|
|
<h3 data-section="1">Section 1</h3>
|
|
<h3 data-section="2">Section 2</h3>
|
|
<h3 data-section="3" class="active">Section 3</h3>
|
|
</header>
|
|
<div>section 3 content</div>
|
|
<footer>Copyright</footer>
|
|
';"###;
|
|
|
|
if section==1 {
|
|
section_1.to_string()
|
|
} else if section==2 {
|
|
section_2.to_string()
|
|
} else if section==3 {
|
|
section_3.to_string()
|
|
} else {
|
|
panic!("unknown section")
|
|
}
|
|
});
|
|
println!("{}", render2.apply(1));
|
|
println!("{}", render2.apply(2));
|
|
println!("{}", render2.apply(3));
|
|
|
|
let render3header = ReactiveUnit::new(None,|opsec: &mut Option<usize>,section: usize| {
|
|
let section_1 = r###"$('header').innerHTML = '
|
|
<h3 data-section="1" class="active">Section 1</h3>
|
|
<h3 data-section="2">Section 2</h3>
|
|
<h3 data-section="3">Section 3</h3>
|
|
';"###;
|
|
let section_2 = r###"$('header').innerHTML = '
|
|
<h3 data-section="1">Section 1</h3>
|
|
<h3 data-section="2" class="active">Section 2</h3>
|
|
<h3 data-section="3">Section 3</h3>
|
|
';"###;
|
|
let section_3 = r###"$('header').innerHTML = '
|
|
<h3 data-section="1">Section 1</h3>
|
|
<h3 data-section="2">Section 2</h3>
|
|
<h3 data-section="3" class="active">Section 3</h3>
|
|
';"###;
|
|
|
|
let changed = if section==1 {
|
|
section_1
|
|
} else if section==2 {
|
|
section_2
|
|
} else if section==3 {
|
|
section_3
|
|
} else {
|
|
panic!("invalid section")
|
|
};
|
|
|
|
if let Some(sec) = *opsec {
|
|
if sec==section { "" }
|
|
else {
|
|
*opsec = Some(section);
|
|
changed
|
|
}
|
|
} else {
|
|
*opsec = Some(section);
|
|
changed
|
|
}
|
|
});
|
|
|
|
let render3content = ReactiveUnit::new(None,|opsec: &mut Option<usize>,section: usize| {
|
|
let section_1 = r###"$('div#content').innerHTML = '
|
|
section 1 content
|
|
';"###;
|
|
let section_2 = r###"$('div#content').innerHTML = '
|
|
section 2 content
|
|
';"###;
|
|
let section_3 = r###"$('div#content').innerHTML = '
|
|
section 3 content
|
|
';"###;
|
|
|
|
let changed = if section==1 {
|
|
section_1
|
|
} else if section==2 {
|
|
section_2
|
|
} else if section==3 {
|
|
section_3
|
|
} else {
|
|
panic!("invalid section")
|
|
};
|
|
|
|
if let Some(sec) = *opsec {
|
|
if sec==section { "" }
|
|
else {
|
|
*opsec = Some(section);
|
|
changed
|
|
}
|
|
} else {
|
|
*opsec = Some(section);
|
|
changed
|
|
}
|
|
});
|
|
|
|
let render3 = ReactiveUnit::new((render3header,render3content), |(rheader,rcontent),section: usize| {
|
|
let header = rheader.apply(section);
|
|
let content = rcontent.apply(section);
|
|
format!("{}{}", header, content)
|
|
});
|
|
|
|
println!("section 1: {}", render3.apply(1));
|
|
println!("section 2: {}", render3.apply(2));
|
|
println!("section 2: {}", render3.apply(2));
|
|
println!("section 3: {}", render3.apply(3));
|
|
|
|
let database = ("hello world", 5, 2);
|
|
let react1 = ReactiveUnit::new((database,render3), |(database,render),evt:(&str,&str)| {
|
|
match evt {
|
|
("header button click",n) => render.apply(n.parse::<usize>().unwrap()),
|
|
("text submission",s) => { database.0 = s; format!("db.textfield1.set(\"{}\")",s) },
|
|
("number 1 submission",n) => { database.1 += n.parse::<i32>().unwrap(); format!("db.numfield1.set(\"{}\")",database.1) },
|
|
("number 2 submission",n) => { database.2 += n.parse::<i32>().unwrap(); format!("db.numfield2.set(\"{}\")",database.2) },
|
|
_ => "".to_string()
|
|
}
|
|
});
|
|
println!("react 1: {}", react1.apply(("header button click","2")));
|
|
println!("react 1: {}", react1.apply(("header button click","2")));
|
|
println!("react 1: {}", react1.apply(("text submission","abc def")));
|
|
println!("react 1: {}", react1.apply(("number 1 submission","123")));
|
|
println!("react 1: {}", react1.apply(("number 1 submission","234")));
|
|
println!("react 1: {}", react1.apply(("number 2 submission","333")));
|
|
println!("react 1: {}", react1.apply(("number 2 submission","222")));
|
|
}
|