From 64106c4d3d4ddba8c7bc2af75376e6d3d3d75601 Mon Sep 17 00:00:00 2001
From:
Date: Mon, 29 Jun 2015 20:16:15 +0000
Subject: Update documentation
---
src/carboxyl/lib.rs.html | 419 ++++++++++
src/carboxyl/lift.rs.html | 605 ++++++++++++++
src/carboxyl/pending.rs.html | 271 +++++++
src/carboxyl/readonly.rs.html | 173 ++++
src/carboxyl/signal.rs.html | 1601 +++++++++++++++++++++++++++++++++++++
src/carboxyl/source.rs.html | 359 +++++++++
src/carboxyl/stream.rs.html | 1645 ++++++++++++++++++++++++++++++++++++++
src/carboxyl/transaction.rs.html | 459 +++++++++++
8 files changed, 5532 insertions(+)
create mode 100644 src/carboxyl/lib.rs.html
create mode 100644 src/carboxyl/lift.rs.html
create mode 100644 src/carboxyl/pending.rs.html
create mode 100644 src/carboxyl/readonly.rs.html
create mode 100644 src/carboxyl/signal.rs.html
create mode 100644 src/carboxyl/source.rs.html
create mode 100644 src/carboxyl/stream.rs.html
create mode 100644 src/carboxyl/transaction.rs.html
(limited to 'src/carboxyl')
diff --git a/src/carboxyl/lib.rs.html b/src/carboxyl/lib.rs.html
new file mode 100644
index 0000000..912fa0d
--- /dev/null
+++ b/src/carboxyl/lib.rs.html
@@ -0,0 +1,419 @@
+
+
+
+
+
+
+
+
+
+ lib.rs.html -- source
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#! [feature (arc_weak , fnbox )]
+#! [cfg_attr (test , feature (test , scoped ))]
+#! [warn (missing_docs )]
+
+#[cfg (test )]
+extern crate test ;
+#[cfg (test )]
+extern crate rand ;
+#[cfg (test )]
+extern crate quickcheck ;
+#[macro_use (lazy_static )]
+extern crate lazy_static ;
+
+pub use stream ::{ Sink , Stream };
+pub use signal ::{ Signal , SignalMut };
+
+mod transaction ;
+mod source ;
+mod pending ;
+mod readonly ;
+mod stream ;
+mod signal ;
+#[macro_use ]
+pub mod lift ;
+#[cfg (test )]
+mod testing ;
+
+
+
+
+
+
+
+
+
Keyboard shortcuts
+
+ ?
+ Show this help dialog
+ S
+ Focus the search field
+ ⇤
+ Move up in search results
+ ⇥
+ Move down in search results
+ ⏎
+ Go to active search result
+
+
+
+
Search tricks
+
+ Prefix searches with a type followed by a colon (e.g.
+ fn:
) to restrict the search to a given type.
+
+
+ Accepted types are: fn
, mod
,
+ struct
, enum
,
+ trait
, typedef
(or
+ tdef
).
+
+
+ Search functions by type signature (e.g.
+ vec -> usize
)
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/carboxyl/lift.rs.html b/src/carboxyl/lift.rs.html
new file mode 100644
index 0000000..224dbe8
--- /dev/null
+++ b/src/carboxyl/lift.rs.html
@@ -0,0 +1,605 @@
+
+
+
+
+
+
+
+
+
+ lift.rs.html -- source
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+use std ::sync ::Arc ;
+use signal ::{ Signal , SignalFn , signal_build , signal_current , signal_source , reg_signal , sample_raw };
+use transaction ::commit ;
+
+
+#[macro_export ]
+macro_rules ! lift {
+ ($ f : expr )
+ => ( $ crate ::lift ::lift0 ($ f ) );
+
+ ($ f : expr , $ a : expr )
+ => ( $ crate ::lift ::lift1 ($ f , $ a ) );
+
+ ($ f : expr , $ a : expr , $ b : expr )
+ => ( $ crate ::lift ::lift2 ($ f , $ a , $ b ) );
+
+ ($ f : expr , $ a : expr , $ b : expr , $ c : expr )
+ => ( $ crate ::lift ::lift3 ($ f , $ a , $ b , $ c ) );
+
+ ($ f : expr , $ a : expr , $ b : expr , $ c : expr , $ d : expr )
+ => ( $ crate ::lift ::lift4 ($ f , $ a , $ b , $ c , $ d ) );
+}
+
+
+
+pub fn lift0 < A , F > (f : F ) -> Signal < A >
+ where F : Fn () -> A + Send + Sync + 'static
+{
+ commit (|| signal_build (SignalFn ::from_fn (f ), ()))
+}
+
+
+
+pub fn lift1 < A , B , F > (f : F , sa : & Signal < A > ) -> Signal < B >
+ where A : Send + Sync + Clone + 'static ,
+ B : Send + Sync + Clone + 'static ,
+ F : Fn (A ) -> B + Send + Sync + 'static ,
+{
+ fn make_callback < A , B , F > (f : & Arc < F > , parent : & Signal < A > ) -> SignalFn < B >
+ where A : Send + Sync + Clone + 'static ,
+ B : Send + Sync + Clone + 'static ,
+ F : Fn (A ) -> B + Send + Sync + 'static ,
+ {
+ let pclone = parent .clone ();
+ let f = f .clone ();
+ match * signal_current (& parent ).read ().unwrap ().future () {
+ SignalFn ::Const (ref a ) => SignalFn ::Const (f (a .clone ())),
+ SignalFn ::Func (_) => SignalFn ::from_fn (move || f (sample_raw (& pclone ))),
+ }
+ }
+
+ commit (|| {
+ let f = Arc ::new (f );
+ let signal = signal_build (make_callback (& f , & sa ), ());
+ let sa_clone = sa .clone ();
+ reg_signal (& mut signal_source (& sa ).write ().unwrap (), & signal ,
+ move | _| make_callback (& f , & sa_clone ));
+ signal
+ })
+}
+
+
+
+pub fn lift2 < A , B , C , F > (f : F , sa : & Signal < A > , sb : & Signal < B > ) -> Signal < C >
+ where A : Send + Sync + Clone + 'static ,
+ B : Send + Sync + Clone + 'static ,
+ C : Send + Sync + Clone + 'static ,
+ F : Fn (A , B ) -> C + Send + Sync + 'static ,
+{
+ fn make_callback < A , B , C , F > (f : & Arc < F > , sa : & Signal < A > , sb : & Signal < B > ) -> SignalFn < C >
+ where A : Send + Sync + Clone + 'static ,
+ B : Send + Sync + Clone + 'static ,
+ C : Send + Sync + Clone + 'static ,
+ F : Fn (A , B ) -> C + Send + Sync + 'static ,
+ {
+ use signal ::SignalFn ::{ Const , Func };
+ let sa_clone = sa .clone ();
+ let sb_clone = sb .clone ();
+ let f = f .clone ();
+ match (
+ signal_current (& sa ).read ().unwrap ().future (),
+ signal_current (& sb ).read ().unwrap ().future (),
+ ) {
+ (& Const (ref a ), & Const (ref b )) => Const (f (a .clone (), b .clone ())),
+ (& Const (ref a ), & Func (_)) => {
+ let a = a .clone ();
+ SignalFn ::from_fn (move || f (a .clone (), sample_raw (& sb_clone )))
+ },
+ (& Func (_), & Const (ref b )) => {
+ let b = b .clone ();
+ SignalFn ::from_fn (move || f (sample_raw (& sa_clone ), b .clone ()))
+ },
+ (& Func (_), & Func (_)) => SignalFn ::from_fn (
+ move || f (sample_raw (& sa_clone ), sample_raw (& sb_clone ))
+ ),
+ }
+ }
+
+ commit (move || {
+ let f = Arc ::new (f );
+ let signal = signal_build (make_callback (& f , & sa , & sb ), ());
+ reg_signal (& mut signal_source (& sa ).write ().unwrap (), & signal , {
+ let sa_clone = sa .clone ();
+ let sb_clone = sb .clone ();
+ let f = f .clone ();
+ move | _| make_callback (& f , & sa_clone , & sb_clone )
+ });
+ reg_signal (& mut signal_source (& sb ).write ().unwrap (), & signal , {
+ let sa_clone = sa .clone ();
+ let sb_clone = sb .clone ();
+ move | _| make_callback (& f , & sa_clone , & sb_clone )
+ });
+ signal
+ })
+}
+
+
+pub fn lift3 < F , A , B , C , Ret > (f : F , ca : & Signal < A > , cb : & Signal < B > , cc : & Signal < C > )
+ -> Signal < Ret >
+where F : Fn (A , B , C ) -> Ret + Send + Sync + 'static ,
+ A : Send + Sync + Clone + 'static ,
+ B : Send + Sync + Clone + 'static ,
+ C : Send + Sync + Clone + 'static ,
+ Ret : Send + Sync + Clone + 'static ,
+{
+ lift2 (move | (a , b ), c | f (a , b , c ), & lift2 (| a , b | (a , b ), ca , cb ), cc )
+}
+
+
+pub fn lift4 < F , A , B , C , D , Ret > (f : F , ca : & Signal < A > , cb : & Signal < B > , cc : & Signal < C > , cd : & Signal < D > )
+ -> Signal < Ret >
+where F : Fn (A , B , C , D ) -> Ret + Send + Sync + 'static ,
+ A : Send + Sync + Clone + 'static ,
+ B : Send + Sync + Clone + 'static ,
+ C : Send + Sync + Clone + 'static ,
+ D : Send + Sync + Clone + 'static ,
+ Ret : Send + Sync + Clone + 'static ,
+{
+ lift2 (
+ move | (a , b ), (c , d )| f (a , b , c , d ),
+ & lift2 (| a , b | (a , b ), ca , cb ),
+ & lift2 (| c , d | (c , d ), cc , cd )
+ )
+}
+
+
+#[cfg (test )]
+mod test {
+ use stream ::Sink ;
+ use signal ::Signal ;
+
+ #[test ]
+ fn lift0 () {
+ let signal = lift ! (|| 3 );
+ assert_eq ! (signal .sample (), 3 );
+ }
+
+ #[test ]
+ fn lift1 () {
+ let sig2 = lift ! (| n | n + 2 , & Signal ::new (3 ));
+ assert_eq ! (sig2 .sample (), 5 );
+ }
+
+ #[test ]
+ fn lift2 () {
+ let sink1 = Sink ::new ();
+ let sink2 = Sink ::new ();
+ let lifted = lift ! (| a , b | a + b , & sink1 .stream ().hold (0 ),
+ & sink2 .stream ().hold (3 ));
+ assert_eq ! (lifted .sample (), 3 );
+ sink1 .send (1 );
+ assert_eq ! (lifted .sample (), 4 );
+ sink2 .send (11 );
+ assert_eq ! (lifted .sample (), 12 );
+ }
+
+ #[test ]
+ fn lift2_identical () {
+ let sig = Signal ::new (16 );
+ let sig2 = lift ! (| a , b | a + b , & sig , & sig );
+ assert_eq ! (sig2 .sample (), 32 );
+ }
+
+ #[test ]
+ fn lift3 () {
+ let sink = Sink ::new ();
+ assert_eq ! (
+ lift ! (| x , y , z | x + 2 * y + z ,
+ & sink .stream ().hold (5 ),
+ & sink .stream ().hold (3 ),
+ & sink .stream ().hold (- 4 )
+ ).sample (),
+ 7
+ );
+ }
+
+ #[test ]
+ fn lift4 () {
+ let sink = Sink ::new ();
+ assert_eq ! (
+ lift ! (| w , x , y , z | 4 * w + x + 2 * y + z ,
+ & sink .stream ().hold (- 2 ),
+ & sink .stream ().hold (5 ),
+ & sink .stream ().hold (3 ),
+ & sink .stream ().hold (- 4 )
+ ).sample (),
+ - 1
+ );
+ }
+
+ #[test ]
+ fn lift0_equal_within_transaction () {
+ use rand ::random ;
+
+ let rnd = lift ! (random ::< i64 > );
+
+ let gather = lift ! (| a , b | (a , b ), & rnd , & rnd );
+
+ let (a , b ) = gather .sample ();
+ assert_eq ! (a , b );
+ }
+}
+
+
+
+
+
+
+
+
+
Keyboard shortcuts
+
+ ?
+ Show this help dialog
+ S
+ Focus the search field
+ ⇤
+ Move up in search results
+ ⇥
+ Move down in search results
+ ⏎
+ Go to active search result
+
+
+
+
Search tricks
+
+ Prefix searches with a type followed by a colon (e.g.
+ fn:
) to restrict the search to a given type.
+
+
+ Accepted types are: fn
, mod
,
+ struct
, enum
,
+ trait
, typedef
(or
+ tdef
).
+
+
+ Search functions by type signature (e.g.
+ vec -> usize
)
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/carboxyl/pending.rs.html b/src/carboxyl/pending.rs.html
new file mode 100644
index 0000000..6e0f11f
--- /dev/null
+++ b/src/carboxyl/pending.rs.html
@@ -0,0 +1,271 @@
+
+
+
+
+
+
+
+
+
+ pending.rs.html -- source
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+
+
+
+use std ::ops ::Deref ;
+
+
+
+
+
+pub struct Pending < T > {
+ current : T ,
+ update : Option < T > ,
+}
+
+impl < T > Pending < T > {
+
+ pub fn new (t : T ) -> Pending < T > {
+ Pending { current : t , update : None }
+ }
+
+
+ pub fn queue (& mut self , new : T ) {
+ self .update = Some (new );
+ }
+
+
+ pub fn update (& mut self ) {
+ if let Some (t ) = self .update .take () {
+ self .current = t ;
+ }
+ }
+
+
+ pub fn future (& self ) -> & T {
+ self .update .as_ref ().unwrap_or (& self .current )
+ }
+}
+
+impl < T > Deref for Pending < T > {
+ type Target = T ;
+ fn deref (& self ) -> & T { & self .current }
+}
+
+
+#[cfg (test )]
+mod test {
+ use super ::* ;
+
+ #[test ]
+ fn new_derefs_identical () {
+ assert_eq ! (* Pending ::new (3 ), 3 );
+ }
+
+ #[test ]
+ fn queue_does_not_affect_deref () {
+ let mut p = Pending ::new (2 );
+ p .queue (4 );
+ assert_eq ! (* p , 2 );
+ }
+
+ #[test ]
+ fn new_future_identical () {
+ assert_eq ! (* Pending ::new (5 ).future (), 5 );
+ }
+
+ #[test ]
+ fn queue_affects_future () {
+ let mut p = Pending ::new (10 );
+ p .queue (6 );
+ assert_eq ! (* p .future (), 6 );
+ }
+
+ #[test ]
+ fn updated_deref () {
+ let mut p = Pending ::new (- 2 );
+ p .queue (2 );
+ p .update ();
+ assert_eq ! (* p , 2 );
+ }
+
+ #[test ]
+ fn updated_future () {
+ let mut p = Pending ::new (- 7 );
+ p .queue (0 );
+ p .update ();
+ assert_eq ! (* p .future (), 0 );
+ }
+}
+
+
+
+
+
+
+
+
+
Keyboard shortcuts
+
+ ?
+ Show this help dialog
+ S
+ Focus the search field
+ ⇤
+ Move up in search results
+ ⇥
+ Move down in search results
+ ⏎
+ Go to active search result
+
+
+
+
Search tricks
+
+ Prefix searches with a type followed by a colon (e.g.
+ fn:
) to restrict the search to a given type.
+
+
+ Accepted types are: fn
, mod
,
+ struct
, enum
,
+ trait
, typedef
(or
+ tdef
).
+
+
+ Search functions by type signature (e.g.
+ vec -> usize
)
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/carboxyl/readonly.rs.html b/src/carboxyl/readonly.rs.html
new file mode 100644
index 0000000..84fce7f
--- /dev/null
+++ b/src/carboxyl/readonly.rs.html
@@ -0,0 +1,173 @@
+
+
+
+
+
+
+
+
+
+ readonly.rs.html -- source
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+
+
+
+use std ::sync ::{ Arc , RwLock , RwLockReadGuard };
+use std ::ops ::Deref ;
+
+
+pub struct ReadOnlyGuard < 'a , T : 'a > {
+ guard : RwLockReadGuard < 'a , T > ,
+}
+
+impl < 'a , T > Deref for ReadOnlyGuard < 'a , T > {
+ type Target = T ;
+ fn deref (& self ) -> & T { & self .guard }
+}
+
+
+pub struct ReadOnly < T > {
+ ptr : Arc < RwLock < T >> ,
+}
+
+impl < T > Clone for ReadOnly < T > {
+ fn clone (& self ) -> ReadOnly < T > {
+ ReadOnly { ptr : self .ptr .clone () }
+ }
+}
+
+
+pub fn create < T > (ptr : Arc < RwLock < T >> ) -> ReadOnly < T > { ReadOnly { ptr : ptr } }
+
+impl < T > ReadOnly < T > {
+
+
+
+
+ pub fn read (& self ) -> Option < ReadOnlyGuard < T >> {
+ self .ptr .read ().ok ().map (| g | ReadOnlyGuard { guard : g })
+ }
+}
+
+
+
+
+
+
+
+
+
Keyboard shortcuts
+
+ ?
+ Show this help dialog
+ S
+ Focus the search field
+ ⇤
+ Move up in search results
+ ⇥
+ Move down in search results
+ ⏎
+ Go to active search result
+
+
+
+
Search tricks
+
+ Prefix searches with a type followed by a colon (e.g.
+ fn:
) to restrict the search to a given type.
+
+
+ Accepted types are: fn
, mod
,
+ struct
, enum
,
+ trait
, typedef
(or
+ tdef
).
+
+
+ Search functions by type signature (e.g.
+ vec -> usize
)
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/carboxyl/signal.rs.html b/src/carboxyl/signal.rs.html
new file mode 100644
index 0000000..659a0a7
--- /dev/null
+++ b/src/carboxyl/signal.rs.html
@@ -0,0 +1,1601 @@
+
+
+
+
+
+
+
+
+
+ signal.rs.html -- source
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+
+
+
+use std ::sync ::{ Arc , Mutex , RwLock };
+use std ::ops ::Deref ;
+use std ::fmt ;
+#[cfg (test )]
+use quickcheck ::{ Arbitrary , Gen };
+
+use source ::{ Source , with_weak , CallbackError };
+use stream ::{ self , BoxClone , Stream };
+use transaction ::{ commit , end };
+use pending ::Pending ;
+use readonly ::{ self , ReadOnly };
+use lift ;
+#[cfg (test )]
+use testing ::ArcFn ;
+
+
+
+struct FuncSignal < A > {
+ func : Box < Fn () -> A + Send + Sync + 'static > ,
+ cache : Arc < Mutex < Option < A >> > ,
+}
+
+impl < A > FuncSignal < A > {
+ pub fn new < F : Fn () -> A + Send + Sync + 'static > (f : F ) -> FuncSignal < A > {
+ FuncSignal {
+ func : Box ::new (f ),
+ cache : Arc ::new (Mutex ::new (None )),
+ }
+ }
+}
+
+impl < A : Clone + 'static > FuncSignal < A > {
+
+ pub fn call (& self ) -> A {
+ let mut cached = self .cache .lock ().unwrap ();
+ match & mut * cached {
+ & mut Some (ref value ) => value .clone (),
+ cached => {
+
+ let cache = self .cache .clone ();
+ end (move || {
+ let mut live = cache .lock ().unwrap ();
+ * live = None ;
+ });
+
+ let value = (self .func )();
+ * cached = Some (value .clone ());
+ value
+ },
+ }
+ }
+}
+
+
+pub enum SignalFn < A > {
+ Const (A ),
+ Func (FuncSignal < A > ),
+}
+
+impl < A > SignalFn < A > {
+ pub fn from_fn < F : Fn () -> A + Send + Sync + 'static > (f : F ) -> SignalFn < A > {
+ SignalFn ::Func (FuncSignal ::new (f ))
+ }
+}
+
+impl < A : Clone + 'static > SignalFn < A > {
+ pub fn call (& self ) -> A {
+ match * self {
+ SignalFn ::Const (ref a ) => a .clone (),
+ SignalFn ::Func (ref f ) => f .call (),
+ }
+ }
+}
+
+
+
+pub fn reg_signal < A , B , F > (parent_source : & mut Source < A > , signal : & Signal < B > , handler : F )
+ where A : Send + Sync + 'static ,
+ B : Send + Sync + 'static ,
+ F : Fn (A ) -> SignalFn < B > + Send + Sync + 'static ,
+{
+ let weak_source = signal .source .downgrade ();
+ let weak_current = signal .current .downgrade ();
+ parent_source .register (move | a |
+ weak_current .upgrade ().map (| cur | end (
+ move || { let _ = cur .write ().map (| mut cur | cur .update ()); }))
+ .ok_or (CallbackError ::Disappeared )
+ .and (with_weak (& weak_current , | cur | cur .queue (handler (a ))))
+ .and (with_weak (& weak_source , | src | src .send (())))
+ );
+}
+
+
+
+pub fn signal_build < A , K > (func : SignalFn < A > , keep_alive : K ) -> Signal < A >
+ where K : Send + Sync + Clone + 'static
+{
+ Signal ::build (func , keep_alive )
+}
+
+
+pub fn signal_current < A > (signal : & Signal < A > ) -> & Arc < RwLock < Pending < SignalFn < A >> >> {
+ & signal .current
+}
+
+
+pub fn signal_source < A > (signal : & Signal < A > ) -> & Arc < RwLock < Source < ()>> > {
+ & signal .source
+}
+
+
+pub fn sample_raw < A : Clone + 'static > (signal : & Signal < A > ) -> A {
+ signal .current .read ().unwrap ().call ()
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+pub struct Signal < A > {
+ current : Arc < RwLock < Pending < SignalFn < A >> >> ,
+ source : Arc < RwLock < Source < ()>> > ,
+ #[allow (dead_code )]
+ keep_alive : Box < BoxClone > ,
+}
+
+impl < A > Clone for Signal < A > {
+ fn clone (& self ) -> Signal < A > {
+ Signal {
+ current : self .current .clone (),
+ source : self .source .clone (),
+ keep_alive : self .keep_alive .box_clone (),
+ }
+ }
+}
+
+impl < A > Signal < A > {
+ fn build < K > (func : SignalFn < A > , keep_alive : K ) -> Signal < A >
+ where K : Send + Sync + Clone + 'static
+ {
+ Signal {
+ current : Arc ::new (RwLock ::new (Pending ::new (func ))),
+ source : Arc ::new (RwLock ::new (Source ::new ())),
+ keep_alive : Box ::new (keep_alive ),
+ }
+ }
+}
+
+impl < A : Clone + 'static > Signal < A > {
+
+ pub fn new (a : A ) -> Signal < A > {
+ Signal ::build (SignalFn ::Const (a ), ())
+ }
+
+
+ pub fn sample (& self ) -> A {
+ commit (|| sample_raw (self ))
+ }
+}
+
+impl < A : Clone + Send + Sync + 'static > Signal < A > {
+
+
+
+
+
+
+
+
+
+
+
+ pub fn cyclic < F > (def : F ) -> Signal < A >
+ where F : FnOnce (& Signal < A > ) -> Signal < A >
+ {
+ commit (|| {
+ let cycle = SignalCycle ::new ();
+ let finished = def (& cycle );
+ cycle .define (finished )
+ })
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pub fn snapshot < B , C , F > (& self , stream : & Stream < B > , f : F ) -> Stream < C >
+ where B : Clone + Send + Sync + 'static ,
+ C : Clone + Send + Sync + 'static ,
+ F : Fn (A , B ) -> C + Send + Sync + 'static ,
+ {
+ stream ::snapshot (self , stream , f )
+ }
+}
+
+impl < A : Clone + Send + Sync + 'static > Signal < Signal < A >> {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pub fn switch (& self ) -> Signal < A > {
+ fn make_callback < A > (parent : & Signal < Signal < A >> ) -> SignalFn < A >
+ where A : Send + Clone + Sync + 'static ,
+ {
+
+ let current_signal = parent .current .clone ();
+ SignalFn ::from_fn (move ||
+ sample_raw (& current_signal .read ().unwrap ().call ())
+ )
+ }
+ commit (|| {
+ let signal = Signal ::build (make_callback (self ), ());
+ let parent = self .clone ();
+ reg_signal (& mut self .source .write ().unwrap (), & signal ,
+ move | _| make_callback (& parent ));
+ signal
+ })
+ }
+}
+
+#[cfg (test )]
+impl < A , B > Signal < ArcFn < A , B >>
+ where A : Clone + Send + Sync + 'static ,
+ B : Clone + Send + Sync + 'static ,
+{
+
+
+ fn apply (& self , signal : & Signal < A > ) -> Signal < B > {
+ lift ::lift2 (| f , a | f (a ), self , signal )
+ }
+}
+
+#[cfg (test )]
+impl < A : Arbitrary + Sync + Clone + 'static > Arbitrary for Signal < A > {
+ fn arbitrary < G : Gen > (g : & mut G ) -> Signal < A > {
+ let values = Vec ::< A > ::arbitrary (g );
+ if values .is_empty () {
+ Signal ::new (Arbitrary ::arbitrary (g ))
+ } else {
+ let n = Mutex ::new (0 );
+ lift ::lift0 (move || {
+ let mut n = n .lock ().unwrap ();
+ * n += 1 ;
+ if * n >= values .len () { * n = 0 }
+ values [* n ].clone ()
+ })
+ }
+ }
+}
+
+impl < A : fmt ::Debug + Clone + 'static > fmt ::Debug for Signal < A > {
+ fn fmt (& self , fmt : & mut fmt ::Formatter ) -> Result < (), fmt ::Error > {
+ commit (|| match * * self .current .read ().unwrap () {
+ SignalFn ::Const (ref a ) =>
+ fmt .debug_struct ("Signal::const" ).field ("value" , & a ).finish (),
+ SignalFn ::Func (ref f ) =>
+ fmt .debug_struct ("Signal::fn" ).field ("current" , & f .call ()).finish (),
+ })
+ }
+}
+
+
+
+struct SignalCycle < A > {
+ signal : Signal < A > ,
+}
+
+impl < A : Send + Sync + Clone + 'static > SignalCycle < A > {
+
+ pub fn new () -> SignalCycle < A > {
+ const ERR : & 'static str = "sampled on forward-declaration of signal" ;
+ SignalCycle { signal : Signal ::build (SignalFn ::from_fn (|| panic ! (ERR )), ()) }
+ }
+
+
+ pub fn define (self , definition : Signal < A > ) -> Signal < A > {
+
+ fn make_callback < A > (current_def : & Arc < RwLock < Pending < SignalFn < A >> >> ) -> SignalFn < A >
+ where A : Send + Sync + Clone + 'static
+ {
+ match * current_def .read ().unwrap ().future () {
+ SignalFn ::Const (ref a ) => SignalFn ::Const (a .clone ()),
+ SignalFn ::Func (_) => SignalFn ::from_fn ({
+ let sig = current_def .downgrade ();
+ move || {
+ let strong = sig .upgrade ().unwrap ();
+ let ret = strong .read ().unwrap ().call ();
+ ret
+ }
+ }),
+ }
+ }
+ commit (move || {
+ * self .signal .current .write ().unwrap () = Pending ::new (make_callback (& definition .current ));
+ let weak_parent = definition .current .downgrade ();
+ reg_signal (& mut definition .source .write ().unwrap (), & self .signal ,
+ move | _| make_callback (& weak_parent .upgrade ().unwrap ()));
+ Signal { keep_alive : Box ::new (definition ), ..self .signal }
+ })
+ }
+}
+
+impl < A > Deref for SignalCycle < A > {
+ type Target = Signal < A > ;
+ fn deref (& self ) -> & Signal < A > { & self .signal }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+pub struct SignalMut < A > {
+ inner : Signal < ReadOnly < A >> ,
+}
+
+impl < A : Send + Sync + 'static > SignalMut < A > {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pub fn snapshot < B , C , F > (& self , stream : & Stream < B > , f : F ) -> Stream < C >
+ where B : Clone + Send + Sync + 'static ,
+ C : Clone + Send + Sync + 'static ,
+ F : Fn (& A , B ) -> C + Send + Sync + 'static ,
+ {
+ self .inner .snapshot (stream , move | a , b | f (& a .read ().unwrap (), b ))
+ }
+
+
+
+ pub fn combine < B , C , F > (& self , signal : & Signal < B > , f : F ) -> Signal < C >
+ where B : Clone + Send + Sync + 'static ,
+ C : Clone + Send + Sync + 'static ,
+ F : Fn (& A , B ) -> C + Send + Sync + 'static ,
+ {
+ lift ::lift2 (
+ move | a , b | f (& a .read ().unwrap (), b ),
+ & self .inner , & signal
+ )
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pub fn combine_mut < B , C , F > (& self , other : & SignalMut < B > , f : F ) -> Signal < C >
+ where B : Clone + Send + Sync + 'static ,
+ C : Clone + Send + Sync + 'static ,
+ F : Fn (& A , & B ) -> C + Send + Sync + 'static ,
+ {
+ lift ::lift2 (
+ move | a , b | f (& a .read ().unwrap (), & b .read ().unwrap ()),
+ & self .inner , & other .inner
+ )
+ }
+}
+
+
+
+pub fn hold < A > (initial : A , stream : & Stream < A > ) -> Signal < A >
+ where A : Send + Sync + 'static ,
+{
+ commit (|| {
+ let signal = Signal ::build (SignalFn ::Const (initial ), stream .clone ());
+ reg_signal (& mut stream ::source (& stream ).write ().unwrap (), & signal , SignalFn ::Const );
+ signal
+ })
+}
+
+
+
+pub fn scan_mut < A , B , F > (stream : & Stream < A > , initial : B , f : F ) -> SignalMut < B >
+ where A : Send + Sync + 'static ,
+ B : Send + Sync + 'static ,
+ F : Fn (& mut B , A ) + Send + Sync + 'static ,
+{
+ commit (move || {
+ let state = Arc ::new (RwLock ::new (initial ));
+ let signal = Signal ::build (SignalFn ::Const (readonly ::create (state .clone ())), stream .clone ());
+ reg_signal (& mut stream ::source (& stream ).write ().unwrap (), & signal ,
+ move | a | { f (& mut state .write ().unwrap (), a ); SignalFn ::Const (readonly ::create (state .clone ())) });
+ SignalMut { inner : signal }
+ })
+}
+
+
+#[cfg (test )]
+mod test {
+ use quickcheck ::quickcheck ;
+
+ use ::stream ::Sink ;
+ use ::signal ::{ self , Signal , SignalCycle };
+ use ::lift ::lift1 ;
+ use ::testing ::{ ArcFn , signal_eq , id , pure_fn , partial_comp };
+
+ #[test ]
+ fn functor_identity () {
+ fn check (signal : Signal < i32 > ) -> bool {
+ let eq = signal_eq (& signal , & lift1 (id , & signal ));
+ (0 ..10 ).all (| _| eq .sample ())
+ }
+ quickcheck (check as fn (Signal < i32 > ) -> bool );
+ }
+
+ #[test ]
+ fn functor_composition () {
+ fn check (signal : Signal < i32 > ) -> bool {
+ fn f (n : i32 ) -> i32 { 3 * n }
+ fn g (n : i32 ) -> i32 { n + 2 }
+ let eq = signal_eq (
+ & lift1 (| n | f (g (n )), & signal ),
+ & lift1 (f , & lift1 (g , & signal ))
+ );
+ (0 ..10 ).all (| _| eq .sample ())
+ }
+ quickcheck (check as fn (Signal < i32 > ) -> bool );
+ }
+
+ #[test ]
+ fn applicative_identity () {
+ fn check (signal : Signal < i32 > ) -> bool {
+ let eq = signal_eq (& pure_fn (id ).apply (& signal ), & signal );
+ (0 ..10 ).all (| _| eq .sample ())
+ }
+ quickcheck (check as fn (Signal < i32 > ) -> bool );
+ }
+
+ #[test ]
+ fn applicative_composition () {
+ fn check (signal : Signal < i32 > ) -> bool {
+ fn f (n : i32 ) -> i32 { n * 4 }
+ fn g (n : i32 ) -> i32 { n - 3 }
+ let u = pure_fn (f );
+ let v = pure_fn (g );
+ let eq = signal_eq (
+ & pure_fn (partial_comp ).apply (& u ).apply (& v ).apply (& signal ),
+ & u .apply (& v .apply (& signal ))
+ );
+ (0 ..10 ).all (| _| eq .sample ())
+ }
+ quickcheck (check as fn (Signal < i32 > ) -> bool );
+ }
+
+ #[test ]
+ fn applicative_homomorphism () {
+ fn check (x : i32 ) -> bool {
+ fn f (x : i32 ) -> i32 { x * (- 5 ) }
+ let eq = signal_eq (
+ & pure_fn (f ).apply (& Signal ::new (x )),
+ & Signal ::new (f (x ))
+ );
+ (0 ..10 ).all (| _| eq .sample ())
+ }
+ quickcheck (check as fn (i32 ) -> bool );
+ }
+
+ #[test ]
+ fn applicative_interchange () {
+ fn check (x : i32 ) -> bool {
+ fn f (x : i32 ) -> i32 { x * 2 - 7 }
+ let u = pure_fn (f );
+ let eq = signal_eq (
+ & u .apply (& Signal ::new (x )),
+ & pure_fn (move | f : ArcFn < i32 , i32 > | f (x )).apply (& u )
+ );
+ (0 ..10 ).all (| _| eq .sample ())
+ }
+ quickcheck (check as fn (i32 ) -> bool );
+ }
+
+ #[test ]
+ fn clone () {
+ let b = Signal ::new (3 );
+ assert_eq ! (b .clone ().sample (), 3 );
+ }
+
+ #[test ]
+ fn hold () {
+ let sink = Sink ::new ();
+ let signal = sink .stream ().hold (3 );
+ assert_eq ! (signal .sample (), 3 );
+ sink .send (4 );
+ assert_eq ! (signal .sample (), 4 );
+ }
+
+ #[test ]
+ fn hold_implicit_stream () {
+ let sink = Sink ::new ();
+ let signal = signal ::hold (0 , & sink .stream ().map (| n | 2 * n ));
+ assert_eq ! (signal .sample (), 0 );
+ sink .send (4 );
+ assert_eq ! (signal .sample (), 8 );
+ }
+
+ #[test ]
+ fn snapshot () {
+ let sink1 : Sink < i32 > = Sink ::new ();
+ let sink2 : Sink < f64 > = Sink ::new ();
+ let mut snap_events = sink1 .stream ().hold (1 )
+ .snapshot (& sink2 .stream ().map (| x | x + 3.0 ), | a , b | (a , b ))
+ .events ();
+ sink2 .send (4.0 );
+ assert_eq ! (snap_events .next (), Some ((1 , 7.0 )));
+ }
+
+ #[test ]
+ fn snapshot_2 () {
+ let ev1 = Sink ::new ();
+ let beh1 = ev1 .stream ().hold (5 );
+ let ev2 = Sink ::new ();
+ let snap = beh1 .snapshot (& ev2 .stream (), | a , b | (a , b ));
+ let mut events = snap .events ();
+ ev2 .send (4 );
+ assert_eq ! (events .next (), Some ((5 , 4 )));
+ ev1 .send (- 2 );
+ ev2 .send (6 );
+ assert_eq ! (events .next (), Some ((- 2 , 6 )));
+ }
+
+ #[test ]
+ fn cyclic_snapshot_accum () {
+ let sink = Sink ::new ();
+ let stream = sink .stream ();
+ let accum = SignalCycle ::new ();
+ let def = accum .snapshot (& stream , | a , s | a + s ).hold (0 );
+ let accum = accum .define (def );
+ assert_eq ! (accum .sample (), 0 );
+ sink .send (3 );
+ assert_eq ! (accum .sample (), 3 );
+ sink .send (7 );
+ assert_eq ! (accum .sample (), 10 );
+ sink .send (- 21 );
+ assert_eq ! (accum .sample (), - 11 );
+ }
+
+ #[test ]
+ fn snapshot_order_standard () {
+ let sink = Sink ::new ();
+ let signal = sink .stream ().hold (0 );
+ let mut events = signal
+ .snapshot (& sink .stream (), | a , b | (a , b ))
+ .events ();
+ sink .send (1 );
+ assert_eq ! (events .next (), Some ((0 , 1 )));
+ }
+
+ #[test ]
+ fn snapshot_lift_order_standard () {
+ let sink = Sink ::new ();
+ let signal = sink .stream ().hold (0 );
+ let mut events = lift1 (| x | x , & signal )
+ .snapshot (& sink .stream (), | a , b | (a , b ))
+ .events ();
+ sink .send (1 );
+ assert_eq ! (events .next (), Some ((0 , 1 )));
+ }
+
+ #[test ]
+ fn snapshot_order_alternative () {
+ let sink = Sink ::new ();
+
+
+ let first = sink .stream ().map (| x | x );
+ let signal = sink .stream ().hold (0 );
+ let mut events = signal .snapshot (& first , | a , b | (a , b )).events ();
+ sink .send (1 );
+ assert_eq ! (events .next (), Some ((0 , 1 )));
+ }
+
+ #[test ]
+ fn cyclic_signal_intermediate () {
+ let sink = Sink ::new ();
+ let stream = sink .stream ();
+ let mut snap = None ;
+ let sum = Signal ::cyclic (| a | {
+ let my_snap = a .snapshot (& stream , | a , e | e + a );
+ snap = Some (my_snap .clone ());
+ my_snap .hold (0 )
+ });
+ let snap = snap .unwrap ();
+ let mut events = snap .events ();
+
+ sink .send (3 );
+ assert_eq ! (sum .sample (), 3 );
+ assert_eq ! (events .next (), Some (3 ));
+ }
+}
+
+
+
+
+
+
+
+
+
Keyboard shortcuts
+
+ ?
+ Show this help dialog
+ S
+ Focus the search field
+ ⇤
+ Move up in search results
+ ⇥
+ Move down in search results
+ ⏎
+ Go to active search result
+
+
+
+
Search tricks
+
+ Prefix searches with a type followed by a colon (e.g.
+ fn:
) to restrict the search to a given type.
+
+
+ Accepted types are: fn
, mod
,
+ struct
, enum
,
+ trait
, typedef
(or
+ tdef
).
+
+
+ Search functions by type signature (e.g.
+ vec -> usize
)
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/carboxyl/source.rs.html b/src/carboxyl/source.rs.html
new file mode 100644
index 0000000..5aab27b
--- /dev/null
+++ b/src/carboxyl/source.rs.html
@@ -0,0 +1,359 @@
+
+
+
+
+
+
+
+
+
+ source.rs.html -- source
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+
+
+
+
+
+
+use std ::sync ::{ RwLock , Weak };
+
+
+#[derive (PartialEq , Eq , Clone , Copy , Debug )]
+pub enum CallbackError {
+ Disappeared ,
+ Poisoned ,
+}
+
+
+pub type CallbackResult < T = ()> = Result < T , CallbackError > ;
+
+
+type Callback < A > = Box < FnMut (A ) -> CallbackResult + Send + Sync + 'static > ;
+
+
+
+
+pub fn with_weak < T , U , F : FnOnce (& mut T ) -> U > (weak : & Weak < RwLock < T >> , f : F ) -> CallbackResult < U > {
+ weak .upgrade ()
+ .ok_or (CallbackError ::Disappeared )
+ .and_then (| mutex | mutex .write ()
+ .map (| mut t | f (& mut t ))
+ .map_err (| _| CallbackError ::Poisoned )
+ )
+}
+
+
+
+pub struct Source < A > {
+ callbacks : Vec < Callback < A >> ,
+}
+
+impl < A > Source < A > {
+
+ pub fn new () -> Source < A > {
+ Source { callbacks : vec ! [] }
+ }
+
+
+
+
+ pub fn register < F > (& mut self , callback : F )
+ where F : FnMut (A ) -> CallbackResult + Send + Sync + 'static
+ {
+ self .callbacks .push (Box ::new (callback ));
+ }
+}
+
+impl < A : Send + Sync + Clone + 'static > Source < A > {
+
+ pub fn send (& mut self , a : A ) {
+ use std ::mem ;
+ let mut new_callbacks = vec ! ();
+ mem ::swap (& mut new_callbacks , & mut self .callbacks );
+ self .callbacks = new_callbacks
+ .into_iter ()
+ .filter_map (| mut callback | {
+ let result = callback (a .clone ());
+ match result {
+ Ok (_) => Some (callback ),
+ Err (_) => None ,
+ }
+ })
+ .collect ();
+ }
+}
+
+
+#[cfg (test )]
+mod test {
+ use std ::sync ::{ Arc , RwLock };
+ use std ::thread ;
+ use super ::* ;
+
+ #[test ]
+ fn with_weak_no_error () {
+ let a = Arc ::new (RwLock ::new (3 ));
+ let weak = a .downgrade ();
+ assert_eq ! (with_weak (& weak , | a | { * a = 4 ; }), Ok (()));
+ assert_eq ! (* a .read ().unwrap (), 4 );
+ }
+
+ #[test ]
+ fn with_weak_disappeared () {
+ let weak = Arc ::new (RwLock ::new (3 )).downgrade ();
+ assert_eq ! (with_weak (& weak , | _| ()), Err (CallbackError ::Disappeared ));
+ }
+
+ #[test ]
+ fn with_weak_poisoned () {
+ let a = Arc ::new (RwLock ::new (3 ));
+ let a2 = a .clone ();
+ let weak = a .downgrade ();
+ let _ = thread ::spawn (move || {
+ let _g = a2 .write ().unwrap ();
+ panic ! ();
+ }).join ();
+ assert_eq ! (with_weak (& weak , | _| ()), Err (CallbackError ::Poisoned ));
+ }
+
+ #[test ]
+ fn source_register_and_send () {
+ let mut src = Source ::new ();
+ let a = Arc ::new (RwLock ::new (3 ));
+ {
+ let a = a .clone ();
+ src .register (move | x | {
+ * a .write ().unwrap () = x ;
+ Ok (())
+ });
+ }
+ assert_eq ! (src .callbacks .len (), 1 );
+ src .send (4 );
+ assert_eq ! (* a .read ().unwrap (), 4 );
+ }
+
+ #[test ]
+ fn source_unregister () {
+ let mut src = Source ::new ();
+ src .register (| _| Err (CallbackError ::Disappeared ));
+ assert_eq ! (src .callbacks .len (), 1 );
+ src .send (());
+ assert_eq ! (src .callbacks .len (), 0 );
+ }
+}
+
+
+
+
+
+
+
+
+
Keyboard shortcuts
+
+ ?
+ Show this help dialog
+ S
+ Focus the search field
+ ⇤
+ Move up in search results
+ ⇥
+ Move down in search results
+ ⏎
+ Go to active search result
+
+
+
+
Search tricks
+
+ Prefix searches with a type followed by a colon (e.g.
+ fn:
) to restrict the search to a given type.
+
+
+ Accepted types are: fn
, mod
,
+ struct
, enum
,
+ trait
, typedef
(or
+ tdef
).
+
+
+ Search functions by type signature (e.g.
+ vec -> usize
)
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/carboxyl/stream.rs.html b/src/carboxyl/stream.rs.html
new file mode 100644
index 0000000..8290275
--- /dev/null
+++ b/src/carboxyl/stream.rs.html
@@ -0,0 +1,1645 @@
+
+
+
+
+
+
+
+
+
+ stream.rs.html -- source
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+
+
+
+use std ::sync ::{ Arc , RwLock , Mutex , Weak };
+use std ::sync ::mpsc ::{ Receiver , channel };
+use std ::thread ;
+use source ::{ Source , CallbackError , CallbackResult , with_weak };
+use signal ::{ self , Signal , SignalMut , sample_raw };
+use transaction ::{ commit , later };
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+pub struct Sink < A > {
+ source : Arc < RwLock < Source < A >> > ,
+}
+
+impl < A > Clone for Sink < A > {
+ fn clone (& self ) -> Sink < A > {
+ Sink { source : self .source .clone () }
+ }
+}
+
+impl < A : Send + Sync > Sink < A > {
+
+ pub fn new () -> Sink < A > {
+ Sink { source : Arc ::new (RwLock ::new (Source ::new ())) }
+ }
+
+
+ pub fn stream (& self ) -> Stream < A > {
+ Stream { source : self .source .clone (), keep_alive : Box ::new (()), }
+ }
+}
+
+impl < A : Send + Sync + Clone + 'static > Sink < A > {
+
+
+
+
+ pub fn send_async (& self , a : A ) {
+ let clone = self .clone ();
+ thread ::spawn (move || clone .send (a ));
+ }
+
+
+
+
+ pub fn feed < I : IntoIterator < Item = A >> (& self , iterator : I ) {
+ for event in iterator {
+ self .send (event );
+ }
+ }
+
+
+
+
+
+
+ pub fn feed_async < I : IntoIterator < Item = A > + Send + 'static > (& self , iterator : I ) {
+ let clone = self .clone ();
+ thread ::spawn (move || clone .feed (iterator ));
+ }
+
+
+
+
+
+ pub fn send (& self , a : A ) {
+ commit (|| self .source .write ().unwrap ().send (a ))
+ }
+}
+
+
+
+pub trait BoxClone : Sync + Send {
+
+ fn box_clone (& self ) -> Box < BoxClone > ;
+}
+
+impl < T : Sync + Send + Clone + 'static > BoxClone for T {
+ fn box_clone (& self ) -> Box < BoxClone > {
+ Box ::new (self .clone ())
+ }
+}
+
+
+
+
+
+
+pub fn source < A > (stream : & Stream < A > ) -> & Arc < RwLock < Source < A >> > {
+ & stream .source
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+pub struct Stream < A > {
+ source : Arc < RwLock < Source < A >> > ,
+ #[allow (dead_code )]
+ keep_alive : Box < BoxClone > ,
+}
+
+impl < A > Clone for Stream < A > {
+ fn clone (& self ) -> Stream < A > {
+ Stream {
+ source : self .source .clone (),
+ keep_alive : self .keep_alive .box_clone (),
+ }
+ }
+}
+
+impl < A : Clone + Send + Sync + 'static > Stream < A > {
+
+
+
+ pub fn never () -> Stream < A > {
+ Stream {
+ source : Arc ::new (RwLock ::new (Source ::new ())),
+ keep_alive : Box ::new (())
+ }
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pub fn map < B , F > (& self , f : F ) -> Stream < B >
+ where B : Send + Sync + Clone + 'static ,
+ F : Fn (A ) -> B + Send + Sync + 'static ,
+ {
+ commit (|| {
+ let src = Arc ::new (RwLock ::new (Source ::new ()));
+ let weak = src .downgrade ();
+ self .source .write ().unwrap ()
+ .register (move | a | with_weak (& weak , | src | src .send (f (a ))));
+ Stream {
+ source : src ,
+ keep_alive : Box ::new (self .clone ()),
+ }
+ })
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pub fn filter < F > (& self , f : F ) -> Stream < A >
+ where F : Fn (& A ) -> bool + Send + Sync + 'static ,
+ {
+ self .filter_map (move | a | if f (& a ) { Some (a ) } else { None })
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pub fn filter_map < B , F > (& self , f : F ) -> Stream < B >
+ where B : Send + Sync + Clone + 'static ,
+ F : Fn (A ) -> Option < B > + Send + Sync + 'static ,
+ {
+ self .map (f ).filter_some ()
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pub fn merge (& self , other : & Stream < A > ) -> Stream < A > {
+ commit (|| {
+ let src = Arc ::new (RwLock ::new (Source ::new ()));
+ for parent in [self , other ].iter () {
+ let weak = src .downgrade ();
+ parent .source .write ().unwrap ()
+ .register (move | a | with_weak (& weak , | src | src .send (a )));
+ }
+ Stream {
+ source : src ,
+ keep_alive : Box ::new ((self .clone (), other .clone ())),
+ }
+ })
+ }
+
+
+
+
+
+
+ pub fn coalesce < F > (& self , f : F ) -> Stream < A >
+ where F : Fn (A , A ) -> A + Send + Sync + 'static ,
+ {
+ commit (|| {
+ let src = Arc ::new (RwLock ::new (Source ::new ()));
+ let weak = src .downgrade ();
+ self .source .write ().unwrap ().register ({
+ let mutex = Arc ::new (Mutex ::new (None ));
+ move | a | {
+ let mut inner = mutex .lock ().unwrap ();
+ * inner = Some (match inner .take () {
+ Some (b ) => f (a , b ),
+ None => a ,
+ });
+
+ later ({
+ let mutex = mutex .clone ();
+ let weak = weak .clone ();
+ move || {
+ let mut inner = mutex .lock ().unwrap ();
+
+ inner .take ().map (| value |
+ with_weak (& weak , | src | src .send (value ))
+ );
+ }
+ });
+ Ok (())
+ }
+ });
+ Stream { source : src , keep_alive : Box ::new (self .clone ()) }
+ })
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pub fn hold (& self , initial : A ) -> Signal < A > {
+ signal ::hold (initial , self )
+ }
+
+
+ pub fn events (& self ) -> Events < A > { Events ::new (self ) }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pub fn scan < B , F > (& self , initial : B , f : F ) -> Signal < B >
+ where B : Send + Sync + Clone + 'static ,
+ F : Fn (B , A ) -> B + Send + Sync + 'static ,
+ {
+ Signal ::cyclic (| scan | scan .snapshot (self , f ).hold (initial ))
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pub fn scan_mut < B , F > (& self , initial : B , f : F ) -> SignalMut < B >
+ where B : Send + Sync + 'static ,
+ F : Fn (& mut B , A ) + Send + Sync + 'static ,
+ {
+ signal ::scan_mut (self , initial , f )
+ }
+}
+
+impl < A : Clone + Send + Sync + 'static > Stream < Option < A >> {
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pub fn filter_some (& self ) -> Stream < A > {
+ commit (|| {
+ let src = Arc ::new (RwLock ::new (Source ::new ()));
+ let weak = src .downgrade ();
+ self .source .write ().unwrap ()
+ .register (move | a | a .map_or (
+ Ok (()),
+ | a | with_weak (& weak , | src | src .send (a ))
+ ));
+ Stream {
+ source : src ,
+ keep_alive : Box ::new (self .clone ())
+ }
+ })
+ }
+}
+
+impl < A : Send + Sync + Clone + 'static > Stream < Stream < A >> {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ pub fn switch (& self ) -> Stream < A > {
+ fn rewire_callbacks < A > (new_stream : Stream < A > , source : Weak < RwLock < Source < A >> > ,
+ terminate : & mut Arc < ()> )
+ -> CallbackResult
+ where A : Send + Sync + Clone + 'static ,
+ {
+ * terminate = Arc ::new (());
+ let weak = terminate .downgrade ();
+ new_stream .source .write ().unwrap ().register (move | a |
+ weak .upgrade ()
+ .ok_or (CallbackError ::Disappeared )
+ .and_then (| _| with_weak (& source , | src | src .send (a )))
+ );
+ Ok (())
+ }
+ commit (|| {
+ let src = Arc ::new (RwLock ::new (Source ::new ()));
+ let weak = src .downgrade ();
+ self .source .write ().unwrap ().register ({
+ let mut terminate = Arc ::new (());
+ move | stream | rewire_callbacks (stream , weak .clone (), & mut terminate )
+ });
+ Stream {
+ source : src ,
+ keep_alive : Box ::new (self .clone ()),
+ }
+ })
+ }
+}
+
+
+
+pub fn snapshot < A , B , C , F > (signal : & Signal < A > , stream : & Stream < B > , f : F ) -> Stream < C >
+ where A : Clone + Send + Sync + 'static ,
+ B : Clone + Send + Sync + 'static ,
+ C : Clone + Send + Sync + 'static ,
+ F : Fn (A , B ) -> C + Send + Sync + 'static ,
+{
+ commit (|| {
+ let src = Arc ::new (RwLock ::new (Source ::new ()));
+ let weak = src .downgrade ();
+ stream .source .write ().unwrap ().register ({
+ let signal = signal .clone ();
+ move | b | with_weak (& weak , | src | src .send (f (sample_raw (& signal ), b )))
+ });
+ Stream {
+ source : src ,
+ keep_alive : Box ::new ((stream .clone (), signal .clone ())),
+ }
+ })
+}
+
+
+
+pub struct Events < A > {
+ receiver : Receiver < A > ,
+ #[allow (dead_code )]
+ keep_alive : Box < BoxClone > ,
+}
+
+impl < A : Send + Sync + 'static > Events < A > {
+
+ fn new (stream : & Stream < A > ) -> Events < A > {
+ commit (|| {
+ let (tx , rx ) = channel ();
+ let tx = Mutex ::new (tx );
+ stream .source .write ().unwrap ().register (
+ move | a | tx .lock ().unwrap ().send (a ).map_err (| _| CallbackError ::Disappeared )
+ );
+ Events {
+ receiver : rx ,
+ keep_alive : Box ::new (stream .clone ()),
+ }
+ })
+ }
+}
+
+impl < A : Send + Sync + 'static > Iterator for Events < A > {
+ type Item = A ;
+ fn next (& mut self ) -> Option < A > { self .receiver .recv ().ok () }
+}
+
+
+#[cfg (test )]
+mod test {
+ use std ::thread ;
+ use quickcheck ::quickcheck ;
+
+ use testing ::{ id , stream_eq };
+ use super ::* ;
+
+ #[test ]
+ fn sink () {
+ let sink = Sink ::new ();
+ let mut events = sink .stream ().events ();
+ sink .send (1 );
+ sink .send (2 );
+ assert_eq ! (events .next (), Some (1 ));
+ assert_eq ! (events .next (), Some (2 ));
+ }
+
+ #[test ]
+ fn map () {
+ let sink = Sink ::new ();
+ let triple = sink .stream ().map (| x | 3 * x );
+ let mut events = triple .events ();
+ sink .send (1 );
+ assert_eq ! (events .next (), Some (3 ));
+ }
+
+ #[test ]
+ fn filter_some () {
+ let sink = Sink ::new ();
+ let small = sink .stream ().filter_some ();
+ let mut events = small .events ();
+ sink .send (None );
+ sink .send (Some (9 ));
+ assert_eq ! (events .next (), Some (9 ));
+ }
+
+ #[test ]
+ fn chain_1 () {
+ let sink : Sink < i32 > = Sink ::new ();
+ let chain = sink .stream ()
+ .map (| x | x / 2 )
+ .filter (| & x | x < 3 );
+ let mut events = chain .events ();
+ sink .send (7 );
+ sink .send (4 );
+ assert_eq ! (events .next (), Some (2 ));
+ }
+
+ #[test ]
+ fn merge () {
+ let sink1 = Sink ::new ();
+ let sink2 = Sink ::new ();
+ let mut events = sink1 .stream ().merge (& sink2 .stream ()).events ();
+ sink1 .send (12 );
+ sink2 .send (9 );
+ assert_eq ! (events .next (), Some (12 ));
+ assert_eq ! (events .next (), Some (9 ));
+ }
+
+ #[test ]
+ fn chain_2 () {
+ let sink1 : Sink < i32 > = Sink ::new ();
+ let sink2 : Sink < i32 > = Sink ::new ();
+ let mut events = sink1 .stream ().map (| x | x + 4 )
+ .merge (
+ & sink2 .stream ()
+ .filter_map (| x | if x < 4 { Some (x ) } else { None })
+ .map (| x | x * 5 ))
+ .events ();
+ sink1 .send (12 );
+ sink2 .send (3 );
+ assert_eq ! (events .next (), Some (16 ));
+ assert_eq ! (events .next (), Some (15 ));
+ }
+
+ #[test ]
+ fn move_closure () {
+ let sink = Sink ::< i32 > ::new ();
+ let x = 3 ;
+ sink .stream ().map (move | y | y + x );
+ }
+
+ #[test ]
+ fn scan_race_condition () {
+ let sink = Sink ::new ();
+
+ sink .feed_async (0 ..100000 );
+
+
+ for _ in 0 ..10 {
+ let _sum = sink .stream ().scan (0 , | a , b | a + b );
+ }
+ }
+
+ #[test ]
+ fn sink_send_async () {
+ let sink = Sink ::new ();
+ let mut events = sink .stream ().events ();
+ sink .send_async (1 );
+ assert_eq ! (events .next (), Some (1 ));
+ }
+
+ #[test ]
+ fn sink_feed () {
+ let sink = Sink ::new ();
+ let events = sink .stream ().events ();
+ sink .feed (0 ..10 );
+ for (n , m ) in events .take (10 ).enumerate () {
+ assert_eq ! (n as i32 , m );
+ }
+ }
+
+ #[test ]
+ fn sink_feed_async () {
+ let sink = Sink ::new ();
+ let events = sink .stream ().events ();
+ sink .feed_async (0 ..10 );
+ for (n , m ) in events .take (10 ).enumerate () {
+ assert_eq ! (n as i32 , m );
+ }
+ }
+
+ #[test ]
+ fn coalesce () {
+ let sink = Sink ::new ();
+ let stream = sink .stream ()
+ .merge (& sink .stream ())
+ .coalesce (| a , b | a + b );
+ let mut events = stream .events ();
+
+ sink .send (1 );
+ assert_eq ! (events .next (), Some (2 ));
+ }
+
+ #[test ]
+ fn monoid_left_identity () {
+ fn check (input : Vec < i32 > ) -> Result < bool , String > {
+ let sink = Sink ::new ();
+ let a = sink .stream ();
+ let eq = stream_eq (& Stream ::never ().merge (& a ), & a );
+ sink .feed (input .into_iter ());
+ eq .sample ()
+ }
+ quickcheck (check as fn (Vec < i32 > ) -> Result < bool , String > );
+ }
+
+ #[test ]
+ fn monoid_right_identity () {
+ fn check (input : Vec < i32 > ) -> Result < bool , String > {
+ let sink = Sink ::new ();
+ let a = sink .stream ();
+ let eq = stream_eq (& a .merge (& Stream ::never ()), & a );
+ sink .feed (input .into_iter ());
+ eq .sample ()
+ }
+ quickcheck (check as fn (Vec < i32 > ) -> Result < bool , String > );
+ }
+
+ #[test ]
+ fn monoid_associative () {
+ fn check (input_a : Vec < i32 > , input_b : Vec < i32 > , input_c : Vec < i32 > ) -> Result < bool , String > {
+ let sink_a = Sink ::new ();
+ let sink_b = Sink ::new ();
+ let sink_c = Sink ::new ();
+ let a = sink_a .stream ();
+ let b = sink_b .stream ();
+ let c = sink_c .stream ();
+ let eq = stream_eq (& a .merge (& b .merge (& c )), & a .merge (& b ).merge (& c ));
+ {
+ let _g1 = thread ::scoped (|| sink_a .feed (input_a .into_iter ()));
+ let _g2 = thread ::scoped (|| sink_b .feed (input_b .into_iter ()));
+ let _g3 = thread ::scoped (|| sink_c .feed (input_c .into_iter ()));
+ }
+ eq .sample ()
+ }
+ quickcheck (check as fn (Vec < i32 > , Vec < i32 > , Vec < i32 > ) -> Result < bool , String > );
+ }
+
+ #[test ]
+ fn functor_identity () {
+ fn check (input : Vec < i32 > ) -> Result < bool , String > {
+ let sink = Sink ::new ();
+ let a = sink .stream ();
+ let eq = stream_eq (& a .map (id ), & a );
+ sink .feed (input .into_iter ());
+ eq .sample ()
+ }
+ quickcheck (check as fn (Vec < i32 > ) -> Result < bool , String > );
+ }
+
+ #[test ]
+ fn functor_composition () {
+ fn check (input : Vec < i32 > ) -> Result < bool , String > {
+ fn f (n : i32 ) -> i64 { (n + 3 ) as i64 }
+ fn g (n : i64 ) -> f64 { n as f64 / 2.5 }
+
+ let sink = Sink ::new ();
+ let a = sink .stream ();
+ let eq = stream_eq (& a .map (f ).map (g ), & a .map (| n | g (f (n ))));
+ sink .feed (input .into_iter ());
+ eq .sample ()
+ }
+ quickcheck (check as fn (Vec < i32 > ) -> Result < bool , String > );
+ }
+}
+
+
+
+
+
+
+
+
+
Keyboard shortcuts
+
+ ?
+ Show this help dialog
+ S
+ Focus the search field
+ ⇤
+ Move up in search results
+ ⇥
+ Move down in search results
+ ⏎
+ Go to active search result
+
+
+
+
Search tricks
+
+ Prefix searches with a type followed by a colon (e.g.
+ fn:
) to restrict the search to a given type.
+
+
+ Accepted types are: fn
, mod
,
+ struct
, enum
,
+ trait
, typedef
(or
+ tdef
).
+
+
+ Search functions by type signature (e.g.
+ vec -> usize
)
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/carboxyl/transaction.rs.html b/src/carboxyl/transaction.rs.html
new file mode 100644
index 0000000..e9cc7b6
--- /dev/null
+++ b/src/carboxyl/transaction.rs.html
@@ -0,0 +1,459 @@
+
+
+
+
+
+
+
+
+
+ transaction.rs.html -- source
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+
+
+
+
+
+
+use std ::sync ::Mutex ;
+use std ::cell ::RefCell ;
+use std ::boxed ::FnBox ;
+
+
+
+
+
+
+lazy_static ! {
+ static ref TRANSACTION_MUTEX : Mutex < ()> = Mutex ::new (());
+}
+
+
+thread_local ! (
+ static CURRENT_TRANSACTION : RefCell < Option < Transaction >> =
+ RefCell ::new (None )
+);
+
+
+
+type Callback = Box < FnBox () + 'static > ;
+
+
+
+pub struct Transaction {
+ intermediate : Vec < Callback > ,
+ finalizers : Vec < Callback > ,
+}
+
+impl Transaction {
+
+ fn new () -> Transaction {
+ Transaction {
+ intermediate : vec ! [],
+ finalizers : vec ! [],
+ }
+ }
+
+
+
+ pub fn later < F : FnOnce () + 'static > (& mut self , callback : F ) {
+ self .intermediate .push (Box ::new (callback ));
+ }
+
+
+
+
+ pub fn end < F : FnOnce () + 'static > (& mut self , callback : F ) {
+ self .finalizers .push (Box ::new (callback ));
+ }
+
+
+ fn advance (& mut self ) -> Vec < Callback > {
+ use std ::mem ;
+ let mut intermediate = vec ! [];
+ mem ::swap (& mut intermediate , & mut self .intermediate );
+ intermediate
+ }
+
+
+ fn finalize (self ) {
+ for finalizer in self .finalizers {
+ finalizer .call_box (());
+ }
+ }
+}
+
+
+
+
+
+
+
+pub fn commit < A , F : FnOnce () -> A > (body : F ) -> A {
+ use std ::mem ;
+
+ let mut prev = CURRENT_TRANSACTION .with (| current | {
+ let mut prev = Some (Transaction ::new ());
+ mem ::swap (& mut prev , & mut current .borrow_mut ());
+ prev
+ });
+
+ let _lock = match prev {
+ None => Some (TRANSACTION_MUTEX .lock ().ok ()
+ .expect ("global transaction mutex poisoned" )
+ ),
+ Some (_) => None ,
+ };
+
+ let result = body ();
+
+ loop {
+ let callbacks = with_current (Transaction ::advance );
+ if callbacks .is_empty () { break }
+ for callback in callbacks {
+ callback .call_box (());
+ }
+ }
+
+ CURRENT_TRANSACTION .with (| current |
+ mem ::swap (& mut prev , & mut current .borrow_mut ())
+ );
+ prev .unwrap ().finalize ();
+
+ result
+}
+
+
+
+pub fn with_current < A , F : FnOnce (& mut Transaction ) -> A > (action : F ) -> A {
+ CURRENT_TRANSACTION .with (| current |
+ match & mut * current .borrow_mut () {
+ & mut Some (ref mut trans ) => action (trans ),
+ _ => panic ! ("there is no active transaction to register a callback" ),
+ }
+ )
+}
+
+pub fn later < F : FnOnce () + 'static > (action : F ) {
+ with_current (| c | c .later (action ))
+}
+
+pub fn end < F : FnOnce () + 'static > (action : F ) {
+ with_current (| c | c .end (action ))
+}
+
+
+#[cfg (test )]
+mod test {
+ use super ::* ;
+
+ #[test ]
+ fn commit_single () {
+ let mut v = 3 ;
+ commit (|| v += 5 );
+ assert_eq ! (v , 8 );
+ }
+
+ #[test ]
+ fn commit_nested () {
+ let mut v = 3 ;
+ commit (|| {
+ commit (|| v *= 2 );
+ v += 4 ;
+ });
+ assert_eq ! (v , 10 );
+ }
+
+ #[test ]
+ fn commits_parallel () {
+ use std ::sync ::{Arc , Mutex };
+ use std ::thread ;
+
+
+ let v = Arc ::new (Mutex ::new (3 ));
+
+ let guards : Vec < _> = (0 ..3 )
+ .map (| _| {
+ let v = v .clone ();
+ thread ::spawn (move || commit (move || {
+
+
+ * v .lock ().unwrap () *= 2 ;
+
+ thread ::sleep_ms (1 );
+ * v .lock ().unwrap () -= 1 ;
+ }))
+ })
+ .collect ();
+
+ for guard in guards { guard .join ().ok ().expect ("thread failed" ); }
+
+ assert_eq ! (& * v .lock ().unwrap (), & 17 );
+ }
+}
+
+
+
+
+
+
+
+
+
Keyboard shortcuts
+
+ ?
+ Show this help dialog
+ S
+ Focus the search field
+ ⇤
+ Move up in search results
+ ⇥
+ Move down in search results
+ ⏎
+ Go to active search result
+
+
+
+
Search tricks
+
+ Prefix searches with a type followed by a colon (e.g.
+ fn:
) to restrict the search to a given type.
+
+
+ Accepted types are: fn
, mod
,
+ struct
, enum
,
+ trait
, typedef
(or
+ tdef
).
+
+
+ Search functions by type signature (e.g.
+ vec -> usize
)
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
--
cgit v1.2.3