├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md ├── clippy.sh ├── paralleltest.sh ├── publish.sh ├── src ├── actor.rs ├── common.rs ├── cor.rs ├── fp.rs ├── handler.rs ├── lib.rs ├── maybe.rs ├── monadio.rs ├── publisher.rs └── sync.rs └── test.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | /target 13 | **/*.rs.bk 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | env: 3 | global: 4 | - PROJECT_NAME: fp_rust 5 | - RUST_BACKTRACE: full 6 | matrix: 7 | fast_finish: true 8 | include: 9 | # Nightly channel. 10 | # All *nix releases are done on the nightly channel to take advantage 11 | # of the regex library's multiple pattern SIMD search. 12 | - os: linux 13 | rust: nightly 14 | env: TARGET=i686-unknown-linux-musl 15 | - os: linux 16 | rust: nightly 17 | env: TARGET=x86_64-unknown-linux-musl 18 | - os: osx 19 | rust: nightly 20 | # XML_CATALOG_FILES is apparently necessary for asciidoc on macOS. 21 | env: TARGET=x86_64-apple-darwin XML_CATALOG_FILES=/usr/local/etc/xml/catalog 22 | - os: linux 23 | rust: nightly 24 | env: TARGET=arm-unknown-linux-gnueabihf GCC_VERSION=4.8 25 | addons: 26 | apt: 27 | packages: 28 | - gcc-4.8-arm-linux-gnueabihf 29 | - binutils-arm-linux-gnueabihf 30 | - libc6-armhf-cross 31 | - libc6-dev-armhf-cross 32 | # For generating man page. 33 | - libxslt1-dev 34 | - asciidoc 35 | - docbook-xsl 36 | - xsltproc 37 | - libxml2-utils 38 | # Beta channel. We enable these to make sure there are no regressions in 39 | # Rust beta releases. 40 | - os: linux 41 | rust: beta 42 | env: TARGET=x86_64-unknown-linux-musl 43 | - os: linux 44 | rust: beta 45 | env: TARGET=x86_64-unknown-linux-gnu 46 | # Minimum Rust supported channel. We enable these to make sure ripgrep 47 | # continues to work on the advertised minimum Rust version. 48 | - os: linux 49 | rust: 1.27.0 50 | env: TARGET=x86_64-unknown-linux-gnu 51 | - os: linux 52 | rust: 1.27.0 53 | env: TARGET=x86_64-unknown-linux-musl 54 | - os: linux 55 | rust: 1.27.0 56 | env: TARGET=arm-unknown-linux-gnueabihf GCC_VERSION=4.8 57 | addons: 58 | apt: 59 | packages: 60 | - gcc-4.8-arm-linux-gnueabihf 61 | - binutils-arm-linux-gnueabihf 62 | - libc6-armhf-cross 63 | - libc6-dev-armhf-cross 64 | # For generating man page. 65 | - libxslt1-dev 66 | - asciidoc 67 | - docbook-xsl 68 | - xsltproc 69 | - libxml2-utils 70 | notifications: 71 | email: 72 | on_success: never 73 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fp_rust" 3 | version = "0.3.5" 4 | license = "MIT" 5 | authors = ["JunYi JohnTeee Lee "] 6 | edition = "2018" 7 | include = ["src/**/*.rs", "Cargo.toml"] 8 | readme = "README.md" 9 | description = "Implement fp features for Rust" 10 | documentation = "https://docs.rs/fp_rust/" 11 | homepage = "https://github.com/TeaEntityLab/fpRust" 12 | repository = "https://github.com/TeaEntityLab/fpRust" 13 | keywords = ["functional","rx","monad","optional","pubsub"] 14 | 15 | [badges.maintenance] 16 | status = "actively-developed" 17 | 18 | [lib] 19 | name = "fp_rust" 20 | path = "src/lib.rs" 21 | 22 | [features] 23 | default = [ 24 | "pure", 25 | # "for_futures", 26 | ] 27 | for_futures = [ "futures", "futures-test" ] 28 | # for_futures = [ "futures", "tokio" ] 29 | pure = [ 30 | "fp", 31 | "maybe", 32 | "sync", 33 | "cor", 34 | "actor", 35 | "handler", 36 | "monadio", 37 | "publisher", 38 | ] 39 | fp = [ ] 40 | maybe = [ ] 41 | sync = [ ] 42 | cor = [ ] 43 | actor = [ "sync" ] 44 | handler = [ "sync" ] 45 | monadio = [ "sync", "handler" ] 46 | publisher = [ "sync", "handler" ] 47 | 48 | # For test 49 | test_runtime = [ "pure", "for_futures" ] 50 | 51 | [dependencies] 52 | # tokio = { version = "^1.9.0", features = ["full"], optional = true } 53 | futures = { version = "0.3", default-features = false, features = ["thread-pool"], optional = true } 54 | futures-test = { version = "0.3", optional = true } 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 TeaEntityLab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fpRust 2 | 3 | [![tag](https://img.shields.io/github/tag/TeaEntityLab/fpRust.svg)](https://github.com/TeaEntityLab/fpRust) 4 | [![Crates.io](https://img.shields.io/crates/d/fp_rust.svg)](https://crates.io/crates/fp_rust) 5 | [![Travis CI Build Status](https://api.travis-ci.org/TeaEntityLab/fpRust.svg?branch=master)](https://travis-ci.org/TeaEntityLab/fpRust) 6 | [![docs](https://img.shields.io/badge/docs-online-5023dd.svg)](https://docs.rs/fp_rust/) 7 | 8 | [![license](https://img.shields.io/github/license/TeaEntityLab/fpRust.svg?style=social&label=License)](https://github.com/TeaEntityLab/fpRust) 9 | [![stars](https://img.shields.io/github/stars/TeaEntityLab/fpRust.svg?style=social&label=Stars)](https://github.com/TeaEntityLab/fpRust) 10 | [![forks](https://img.shields.io/github/forks/TeaEntityLab/fpRust.svg?style=social&label=Fork)](https://github.com/TeaEntityLab/fpRust) 11 | 12 | Monad, Functional Programming features for Rust 13 | 14 | # Why 15 | 16 | I love functional programming, Rx-style coding. 17 | 18 | However it's hard to implement them in Rust, and there're few libraries to achieve parts of them. 19 | 20 | Thus I implemented fpRust. I hope you would like it :) 21 | 22 | # Features 23 | 24 | * MonadIO, Rx-like (*`fp_rust::monadio::MonadIO`*) 25 | * map/fmap/subscribe 26 | * async/sync 27 | * Support *`Future`* (*`to_future()`*) with *`feature: for_futures` 28 | 29 | * Publisher (*`fp_rust::publisher::Publisher`*) 30 | * Support *`Stream`* implementation(*`subscribe_as_stream()`*) with *`feature: for_futures` 31 | 32 | * Fp functions (*`fp_rust::fp`*) 33 | * compose!(), pipe!() 34 | * map!(), reduce!(), filter!(), foldl!(), foldr!() 35 | * contains!(), reverse!() 36 | 37 | * Async (*`fp_rust::sync`* & *`fp_rust::handler::HandlerThread`*) 38 | * simple BlockingQueue (inspired by *`Java BlockingQueue`*, implemented by built-in *`std::sync::mpsc::channel`*) 39 | * HandlerThread (inspired by *`Android Handler`*, implemented by built-in *`std::thread`*) 40 | * WillAsync (inspired by *`Java Future`*) 41 | * Support as a *`Future`* with *`feature: for_futures` 42 | * CountDownLatch (inspired by *`Java CountDownLatch`*, implemented by built-in *`std::sync::Mutex`*) 43 | * Support as a *`Future`* with *`feature: for_futures` 44 | 45 | * Cor (*`fp_rust::cor::Cor`*) 46 | * PythonicGenerator-like Coroutine 47 | * yield/yieldFrom 48 | * async/sync 49 | 50 | * Actor (*`fp_rust::actor::ActorAsync`*) 51 | * Pure simple *`Actor`* model(`receive`/`send`/`spawn`) 52 | * `Context` for keeping internal states 53 | * Able to communicate with Parent/Children Actors 54 | 55 | * DoNotation (*`fp_rust::cor::Cor`*) 56 | * Haskell DoNotation-like, *macro* 57 | 58 | ~~* Pattern matching~~ 59 | 60 | 61 | 62 | # Usage 63 | 64 | ## MonadIO (RxObserver-like) 65 | 66 | Example: 67 | ```rust 68 | 69 | extern crate fp_rust; 70 | 71 | use std::{ 72 | thread, 73 | time, 74 | sync::{ 75 | Arc, 76 | Mutex, 77 | Condvar, 78 | } 79 | }; 80 | 81 | use fp_rust::handler::{ 82 | Handler, 83 | HandlerThread, 84 | }; 85 | use fp_rust::common::SubscriptionFunc; 86 | use fp_rust::monadio::{ 87 | MonadIO, 88 | of, 89 | }; 90 | use fp_rust::sync::CountDownLatch; 91 | 92 | // fmap & map (sync) 93 | let mut _subscription = Arc::new(SubscriptionFunc::new(move |x: Arc| { 94 | println!("monadio_sync {:?}", x); // monadio_sync 36 95 | assert_eq!(36, *Arc::make_mut(&mut x.clone())); 96 | })); 97 | let subscription = _subscription.clone(); 98 | let monadio_sync = MonadIO::just(1) 99 | .fmap(|x| MonadIO::new(move || x * 4)) 100 | .map(|x| x * 3) 101 | .map(|x| x * 3); 102 | monadio_sync.subscribe(subscription); 103 | 104 | // fmap & map (async) 105 | let mut _handler_observe_on = HandlerThread::new_with_mutex(); 106 | let mut _handler_subscribe_on = HandlerThread::new_with_mutex(); 107 | let monadio_async = MonadIO::new_with_handlers( 108 | || { 109 | println!("In string"); 110 | String::from("ok") 111 | }, 112 | Some(_handler_observe_on.clone()), 113 | Some(_handler_subscribe_on.clone()), 114 | ); 115 | 116 | let latch = CountDownLatch::new(1); 117 | let latch2 = latch.clone(); 118 | 119 | thread::sleep(time::Duration::from_millis(1)); 120 | 121 | let subscription = Arc::new(SubscriptionFunc::new(move |x: Arc| { 122 | println!("monadio_async {:?}", x); // monadio_async ok 123 | 124 | latch2.countdown(); // Unlock here 125 | })); 126 | monadio_async.subscribe(subscription); 127 | monadio_async.subscribe(Arc::new(SubscriptionFunc::new(move |x: Arc| { 128 | println!("monadio_async sub2 {:?}", x); // monadio_async sub2 ok 129 | }))); 130 | { 131 | let mut handler_observe_on = _handler_observe_on.lock().unwrap(); 132 | let mut handler_subscribe_on = _handler_subscribe_on.lock().unwrap(); 133 | 134 | println!("hh2"); 135 | handler_observe_on.start(); 136 | handler_subscribe_on.start(); 137 | println!("hh2 running"); 138 | 139 | handler_observe_on.post(RawFunc::new(move || {})); 140 | handler_observe_on.post(RawFunc::new(move || {})); 141 | handler_observe_on.post(RawFunc::new(move || {})); 142 | handler_observe_on.post(RawFunc::new(move || {})); 143 | handler_observe_on.post(RawFunc::new(move || {})); 144 | } 145 | thread::sleep(time::Duration::from_millis(1)); 146 | 147 | // Waiting for being unlcoked 148 | latch.clone().wait(); 149 | ``` 150 | 151 | ## Publisher (PubSub-like) 152 | 153 | Example: 154 | ```rust 155 | 156 | extern crate fp_rust; 157 | 158 | use fp_rust::common::{SubscriptionFunc, RawFunc}; 159 | use fp_rust::handler::{Handler, HandlerThread}; 160 | use fp_rust::publisher::Publisher; 161 | use std::sync::Arc; 162 | 163 | use fp_rust::sync::CountDownLatch; 164 | 165 | let mut pub1 = Publisher::new(); 166 | pub1.subscribe_fn(|x: Arc| { 167 | println!("pub1 {:?}", x); 168 | assert_eq!(9, *Arc::make_mut(&mut x.clone())); 169 | }); 170 | pub1.publish(9); 171 | 172 | let mut _h = HandlerThread::new_with_mutex(); 173 | 174 | let mut pub2 = Publisher::new_with_handlers(Some(_h.clone())); 175 | 176 | let latch = CountDownLatch::new(1); 177 | let latch2 = latch.clone(); 178 | 179 | let s = Arc::new(SubscriptionFunc::new(move |x: Arc| { 180 | println!("pub2-s1 I got {:?}", x); 181 | 182 | latch2.countdown(); 183 | })); 184 | pub2.subscribe(s.clone()); 185 | pub2.map(move |x: Arc| { 186 | println!("pub2-s2 I got {:?}", x); 187 | }); 188 | 189 | { 190 | let h = &mut _h.lock().unwrap(); 191 | 192 | println!("hh2"); 193 | h.start(); 194 | println!("hh2 running"); 195 | 196 | h.post(RawFunc::new(move || {})); 197 | h.post(RawFunc::new(move || {})); 198 | h.post(RawFunc::new(move || {})); 199 | h.post(RawFunc::new(move || {})); 200 | h.post(RawFunc::new(move || {})); 201 | } 202 | 203 | pub2.publish(String::from("OKOK")); 204 | pub2.publish(String::from("OKOK2")); 205 | 206 | pub2.unsubscribe(s.clone()); 207 | 208 | pub2.publish(String::from("OKOK3")); 209 | 210 | latch.clone().wait(); 211 | ``` 212 | 213 | ## Cor (PythonicGenerator-like) 214 | 215 | Example: 216 | ```rust 217 | 218 | #[macro_use] 219 | extern crate fp_rust; 220 | 221 | use std::time; 222 | use std::thread; 223 | 224 | use fp_rust::cor::Cor; 225 | 226 | println!("test_cor_new"); 227 | 228 | let _cor1 = cor_newmutex!( 229 | |this| { 230 | println!("cor1 started"); 231 | 232 | let s = cor_yield!(this, Some(String::from("given_to_outside"))); 233 | println!("cor1 {:?}", s); 234 | }, 235 | String, 236 | i16 237 | ); 238 | let cor1 = _cor1.clone(); 239 | 240 | let _cor2 = cor_newmutex!( 241 | move |this| { 242 | println!("cor2 started"); 243 | 244 | println!("cor2 yield_from before"); 245 | 246 | let s = cor_yield_from!(this, cor1, Some(3)); 247 | println!("cor2 {:?}", s); 248 | }, 249 | i16, 250 | i16 251 | ); 252 | 253 | { 254 | let cor1 = _cor1.clone(); 255 | cor1.lock().unwrap().set_async(true); // NOTE Cor default async 256 | // NOTE cor1 should keep async to avoid deadlock waiting.(waiting for each other) 257 | } 258 | { 259 | let cor2 = _cor2.clone(); 260 | cor2.lock().unwrap().set_async(false); 261 | // NOTE cor2 is the entry point, so it could be sync without any deadlock. 262 | } 263 | cor_start!(_cor1); 264 | cor_start!(_cor2); 265 | 266 | thread::sleep(time::Duration::from_millis(1)); 267 | ``` 268 | 269 | ## Do Notation (Haskell DoNotation-like) 270 | 271 | Example: 272 | ```rust 273 | 274 | #[macro_use] 275 | extern crate fp_rust; 276 | 277 | use std::time; 278 | use std::thread; 279 | 280 | use fp_rust::cor::Cor; 281 | 282 | 283 | let v = Arc::new(Mutex::new(String::from(""))); 284 | 285 | let _v = v.clone(); 286 | do_m!(move |this| { 287 | println!("test_cor_do_m started"); 288 | 289 | let cor_inner1 = cor_newmutex_and_start!( 290 | |this| { 291 | let s = cor_yield!(this, Some(String::from("1"))); 292 | println!("cor_inner1 {:?}", s); 293 | }, 294 | String, 295 | i16 296 | ); 297 | let cor_inner2 = cor_newmutex_and_start!( 298 | |this| { 299 | let s = cor_yield!(this, Some(String::from("2"))); 300 | println!("cor_inner2 {:?}", s); 301 | }, 302 | String, 303 | i16 304 | ); 305 | let cor_inner3 = cor_newmutex_and_start!( 306 | |this| { 307 | let s = cor_yield!(this, Some(String::from("3"))); 308 | println!("cor_inner3 {:?}", s); 309 | }, 310 | String, 311 | i16 312 | ); 313 | 314 | { 315 | (*_v.lock().unwrap()) = [ 316 | cor_yield_from!(this, cor_inner1, Some(1)).unwrap(), 317 | cor_yield_from!(this, cor_inner2, Some(2)).unwrap(), 318 | cor_yield_from!(this, cor_inner3, Some(3)).unwrap(), 319 | ].join(""); 320 | } 321 | }); 322 | 323 | let _v = v.clone(); 324 | 325 | { 326 | assert_eq!("123", *_v.lock().unwrap()); 327 | } 328 | ``` 329 | 330 | ## Fp Functions (Compose, Pipe, Map, Reduce, Filter) 331 | 332 | Example: 333 | 334 | ```rust 335 | #[macro_use] 336 | extern crate fp_rust 337 | 338 | use fp_rust::fp::{ 339 | compose_two, 340 | map, reduce, filter, 341 | }; 342 | 343 | let add = |x| x + 2; 344 | let multiply = |x| x * 3; 345 | let divide = |x| x / 2; 346 | 347 | let result = (compose!(add, multiply, divide))(10); 348 | assert_eq!(17, result); 349 | println!("Composed FnOnce Result is {}", result); 350 | 351 | let result = (pipe!(add, multiply, divide))(10); 352 | assert_eq!(18, result); 353 | println!("Piped FnOnce Result is {}", result); 354 | 355 | let result = (compose!(reduce!(|a, b| a * b), filter!(|x| *x < 6), map!(|x| x * 2)))(vec![1, 2, 3, 4]); 356 | assert_eq!(Some(8), result); 357 | println!("test_map_reduce_filter Result is {:?}", result); 358 | ``` 359 | 360 | ## Actor 361 | 362 | ### Actor common(send/receive/spawn/states) 363 | 364 | Example: 365 | 366 | ```rust 367 | use std::time::Duration; 368 | 369 | use fp_rust::common::LinkedListAsync; 370 | 371 | #[derive(Clone, Debug)] 372 | enum Value { 373 | // Str(String), 374 | Int(i32), 375 | VecStr(Vec), 376 | Spawn, 377 | Shutdown, 378 | } 379 | 380 | let result_i32 = LinkedListAsync::::new(); 381 | let result_i32_thread = result_i32.clone(); 382 | let result_string = LinkedListAsync::>::new(); 383 | let result_string_thread = result_string.clone(); 384 | let mut root = ActorAsync::new( 385 | move |this: &mut ActorAsync<_, _>, msg: Value, context: &mut HashMap| { 386 | match msg { 387 | Value::Spawn => { 388 | println!("Actor Spawn"); 389 | let result_i32_thread = result_i32_thread.clone(); 390 | let spawned = this.spawn_with_handle(Box::new( 391 | move |this: &mut ActorAsync<_, _>, msg: Value, _| { 392 | match msg { 393 | Value::Int(v) => { 394 | println!("Actor Child Int"); 395 | result_i32_thread.push_back(v * 10); 396 | } 397 | Value::Shutdown => { 398 | println!("Actor Child Shutdown"); 399 | this.stop(); 400 | } 401 | _ => {} 402 | }; 403 | }, 404 | )); 405 | let list = context.get("children_ids").cloned(); 406 | let mut list = match list { 407 | Some(Value::VecStr(list)) => list, 408 | _ => Vec::new(), 409 | }; 410 | list.push(spawned.get_id()); 411 | context.insert("children_ids".into(), Value::VecStr(list)); 412 | } 413 | Value::Shutdown => { 414 | println!("Actor Shutdown"); 415 | if let Some(Value::VecStr(ids)) = context.get("children_ids") { 416 | result_string_thread.push_back(ids.clone()); 417 | } 418 | 419 | this.for_each_child(move |id, handle| { 420 | println!("Actor Shutdown id {:?}", id); 421 | handle.send(Value::Shutdown); 422 | }); 423 | this.stop(); 424 | } 425 | Value::Int(v) => { 426 | println!("Actor Int"); 427 | if let Some(Value::VecStr(ids)) = context.get("children_ids") { 428 | for id in ids { 429 | println!("Actor Int id {:?}", id); 430 | if let Some(mut handle) = this.get_handle_child(id) { 431 | handle.send(Value::Int(v)); 432 | } 433 | } 434 | } 435 | } 436 | _ => {} 437 | } 438 | }, 439 | ); 440 | 441 | let mut root_handle = root.get_handle(); 442 | root.start(); 443 | 444 | // One child 445 | root_handle.send(Value::Spawn); 446 | root_handle.send(Value::Int(10)); 447 | // Two children 448 | root_handle.send(Value::Spawn); 449 | root_handle.send(Value::Int(20)); 450 | // Three children 451 | root_handle.send(Value::Spawn); 452 | root_handle.send(Value::Int(30)); 453 | 454 | // Send Shutdown 455 | root_handle.send(Value::Shutdown); 456 | 457 | thread::sleep(Duration::from_millis(1)); 458 | // 3 children Actors 459 | assert_eq!(3, result_string.pop_front().unwrap().len()); 460 | 461 | let mut v = Vec::>::new(); 462 | for _ in 1..7 { 463 | let i = result_i32.pop_front(); 464 | println!("Actor {:?}", i); 465 | v.push(i); 466 | } 467 | v.sort(); 468 | assert_eq!( 469 | [ 470 | Some(100), 471 | Some(200), 472 | Some(200), 473 | Some(300), 474 | Some(300), 475 | Some(300) 476 | ], 477 | v.as_slice() 478 | ) 479 | ``` 480 | 481 | ### Actor Ask (inspired by Akka/Erlang) 482 | 483 | Example: 484 | 485 | ```rust 486 | use std::time::Duration; 487 | 488 | use fp_rust::common::LinkedListAsync; 489 | 490 | #[derive(Clone, Debug)] 491 | enum Value { 492 | AskIntByLinkedListAsync((i32, LinkedListAsync)), 493 | AskIntByBlockingQueue((i32, BlockingQueue)), 494 | } 495 | 496 | let mut root = ActorAsync::new( 497 | move |_: &mut ActorAsync<_, _>, msg: Value, _: &mut HashMap| match msg { 498 | Value::AskIntByLinkedListAsync(v) => { 499 | println!("Actor AskIntByLinkedListAsync"); 500 | v.1.push_back(v.0 * 10); 501 | } 502 | Value::AskIntByBlockingQueue(mut v) => { 503 | println!("Actor AskIntByBlockingQueue"); 504 | 505 | // NOTE If negative, hanging for testing timeout 506 | if v.0 < 0 { 507 | return; 508 | } 509 | 510 | // NOTE General Cases 511 | v.1.offer(v.0 * 10); 512 | } // _ => {} 513 | }, 514 | ); 515 | 516 | let mut root_handle = root.get_handle(); 517 | root.start(); 518 | 519 | // LinkedListAsync 520 | let result_i32 = LinkedListAsync::::new(); 521 | root_handle.send(Value::AskIntByLinkedListAsync((1, result_i32.clone()))); 522 | root_handle.send(Value::AskIntByLinkedListAsync((2, result_i32.clone()))); 523 | root_handle.send(Value::AskIntByLinkedListAsync((3, result_i32.clone()))); 524 | thread::sleep(Duration::from_millis(1)); 525 | let i = result_i32.pop_front(); 526 | assert_eq!(Some(10), i); 527 | let i = result_i32.pop_front(); 528 | assert_eq!(Some(20), i); 529 | let i = result_i32.pop_front(); 530 | assert_eq!(Some(30), i); 531 | 532 | // BlockingQueue 533 | let mut result_i32 = BlockingQueue::::new(); 534 | result_i32.timeout = Some(Duration::from_millis(1)); 535 | root_handle.send(Value::AskIntByBlockingQueue((4, result_i32.clone()))); 536 | root_handle.send(Value::AskIntByBlockingQueue((5, result_i32.clone()))); 537 | root_handle.send(Value::AskIntByBlockingQueue((6, result_i32.clone()))); 538 | thread::sleep(Duration::from_millis(1)); 539 | let i = result_i32.take(); 540 | assert_eq!(Some(40), i); 541 | let i = result_i32.take(); 542 | assert_eq!(Some(50), i); 543 | let i = result_i32.take(); 544 | assert_eq!(Some(60), i); 545 | 546 | // Timeout case: 547 | root_handle.send(Value::AskIntByBlockingQueue((-1, result_i32.clone()))); 548 | let i = result_i32.take(); 549 | assert_eq!(None, i); 550 | ``` 551 | -------------------------------------------------------------------------------- /clippy.sh: -------------------------------------------------------------------------------- 1 | cargo +nightly clippy 2 | -------------------------------------------------------------------------------- /paralleltest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Usages Ref: 3 | # ./paralleltest.sh 2>&1 | grep failed 4 | # ./paralleltest.sh 2>&1 | grep "assertion failed" 5 | # ./paralleltest.sh 2>&1 | grep "src/actor.rs" 6 | 7 | for i in $(seq 1 1000) 8 | do 9 | ( ./test.sh ) & 10 | if (( $i % 10 == 0 )); then wait; fi # Limit to 10 concurrent subshells. 11 | done 12 | wait 13 | -------------------------------------------------------------------------------- /publish.sh: -------------------------------------------------------------------------------- 1 | cargo publish && git push && git push --tag 2 | -------------------------------------------------------------------------------- /src/actor.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | In this module there're implementations & tests of `Actor`. 3 | */ 4 | 5 | use std::collections::HashMap; 6 | use std::sync::{ 7 | atomic::{AtomicBool, Ordering}, 8 | Arc, Mutex, 9 | }; 10 | use std::thread; 11 | 12 | use super::common::{generate_id, UniqueId}; 13 | use super::sync::{BlockingQueue, Queue}; 14 | 15 | /** 16 | `Actor` defines concepts of `Actor`: Send/Receive Messages, States, Methods. 17 | 18 | # Arguments 19 | 20 | * `Msg` - The generic type of Message data 21 | * `ContextValue` - The generic type of ContextValue 22 | 23 | # Remarks 24 | 25 | It defines simple and practical hehaviors of `Actor` model. 26 | 27 | `` 28 | */ 29 | pub trait Actor: UniqueId { 30 | fn receive( 31 | &mut self, 32 | this: &mut Self, 33 | message: Msg, 34 | context: &mut HashMap, 35 | ); 36 | fn spawn_with_handle(&self, func: Functor) -> HandleType; 37 | 38 | fn get_handle(&self) -> HandleType; 39 | fn get_handle_child(&self, name: impl Into) -> Option; 40 | fn get_handle_parent(&self) -> Option; 41 | 42 | fn for_each_child(&self, func: impl FnMut(&String, &mut HandleType)); 43 | } 44 | 45 | pub trait Handle: UniqueId { 46 | fn send(&mut self, message: Msg); 47 | } 48 | 49 | #[derive(Debug, Clone)] 50 | pub struct HandleAsync 51 | where 52 | Msg: Send + 'static, 53 | { 54 | id: String, 55 | queue: BlockingQueue, 56 | } 57 | 58 | impl Handle for HandleAsync 59 | where 60 | Msg: Send + 'static, 61 | { 62 | fn send(&mut self, message: Msg) { 63 | self.queue.offer(message); 64 | } 65 | } 66 | impl UniqueId for HandleAsync 67 | where 68 | Msg: Send + 'static, 69 | { 70 | fn get_id(&self) -> String { 71 | self.id.clone() 72 | } 73 | } 74 | 75 | // #[derive(Clone)] 76 | pub struct ActorAsync 77 | where 78 | Msg: Send + 'static, 79 | { 80 | started_alive: Arc>, 81 | 82 | id: String, 83 | parent_handle: Option>, 84 | children_handle_map: Arc>>>, 85 | 86 | context: Arc>>>, 87 | queue: BlockingQueue, 88 | effect: Arc< 89 | Mutex< 90 | dyn FnMut(&mut ActorAsync, Msg, &mut HashMap) 91 | + Send 92 | + Sync 93 | + 'static, 94 | >, 95 | >, 96 | 97 | join_handle: Arc>>>, 98 | } 99 | impl Clone for ActorAsync 100 | where 101 | Msg: Clone + Send + 'static, 102 | { 103 | fn clone(&self) -> Self { 104 | Self { 105 | started_alive: self.started_alive.clone(), 106 | 107 | id: self.id.clone(), 108 | parent_handle: self.parent_handle.clone(), 109 | children_handle_map: self.children_handle_map.clone(), 110 | 111 | context: self.context.clone(), 112 | queue: self.queue.clone(), 113 | effect: self.effect.clone(), 114 | join_handle: self.join_handle.clone(), 115 | } 116 | } 117 | } 118 | 119 | impl ActorAsync 120 | where 121 | Msg: Send + 'static, 122 | { 123 | pub fn new( 124 | effect: impl FnMut(&mut ActorAsync, Msg, &mut HashMap) 125 | + Send 126 | + Sync 127 | + 'static, 128 | ) -> Self { 129 | Self::new_with_options(effect, None, BlockingQueue::new()) 130 | } 131 | 132 | pub fn new_with_options( 133 | effect: impl FnMut(&mut ActorAsync, Msg, &mut HashMap) 134 | + Send 135 | + Sync 136 | + 'static, 137 | parent_handle: Option>, 138 | queue: BlockingQueue, 139 | ) -> Self { 140 | Self { 141 | queue, 142 | parent_handle, 143 | id: generate_id(), 144 | children_handle_map: Arc::new(Mutex::new(HashMap::new())), 145 | context: Arc::new(Mutex::new(Box::new(HashMap::new()))), 146 | started_alive: Arc::new(Mutex::new((AtomicBool::new(false), AtomicBool::new(false)))), 147 | join_handle: Arc::new(Mutex::new(None)), 148 | effect: Arc::new(Mutex::new(effect)), 149 | } 150 | } 151 | 152 | pub fn is_started(&mut self) -> bool { 153 | let started_alive = self.started_alive.lock().unwrap(); 154 | let &(ref started, _) = &*started_alive; 155 | started.load(Ordering::SeqCst) 156 | } 157 | 158 | pub fn is_alive(&mut self) -> bool { 159 | let started_alive = self.started_alive.lock().unwrap(); 160 | let &(_, ref alive) = &*started_alive; 161 | alive.load(Ordering::SeqCst) 162 | } 163 | 164 | pub fn stop(&mut self) { 165 | { 166 | let started_alive = self.started_alive.lock().unwrap(); 167 | let &(ref started, ref alive) = &*started_alive; 168 | 169 | if !started.load(Ordering::SeqCst) { 170 | return; 171 | } 172 | if !alive.load(Ordering::SeqCst) { 173 | return; 174 | } 175 | alive.store(false, Ordering::SeqCst); 176 | } 177 | 178 | // NOTE: Kill thread <- OS depending 179 | // let mut join_handle = self.join_handle.lock().unwrap(); 180 | // join_handle 181 | // .take() 182 | // .expect("Called stop on non-running thread") 183 | // .join() 184 | // .expect("Could not join spawned thread"); 185 | } 186 | } 187 | 188 | impl ActorAsync 189 | where 190 | Msg: Clone + Send + 'static, 191 | ContextValue: Send + 'static, 192 | { 193 | pub fn start(&mut self) { 194 | { 195 | let started_alive = self.started_alive.lock().unwrap(); 196 | let &(ref started, ref alive) = &*started_alive; 197 | 198 | if started.load(Ordering::SeqCst) { 199 | return; 200 | } 201 | started.store(true, Ordering::SeqCst); 202 | if alive.load(Ordering::SeqCst) { 203 | return; 204 | } 205 | alive.store(true, Ordering::SeqCst); 206 | } 207 | 208 | let mut this = self.clone(); 209 | let mut this_for_receive = self.clone(); 210 | let this_for_context = self.clone(); 211 | let started_alive_thread = self.started_alive.clone(); 212 | self.join_handle = Arc::new(Mutex::new(Some(thread::spawn(move || { 213 | while { 214 | let started_alive = started_alive_thread.lock().unwrap(); 215 | let &(_, ref alive) = &*started_alive; 216 | 217 | alive.load(Ordering::SeqCst) 218 | } { 219 | let v = this.queue.take(); 220 | 221 | match v { 222 | Some(m) => { 223 | let mut context = this_for_context.context.lock().unwrap(); 224 | this.receive(&mut this_for_receive, m, context.as_mut()); 225 | } 226 | None => { 227 | let started_alive = started_alive_thread.lock().unwrap(); 228 | let &(_, ref alive) = &*started_alive; 229 | 230 | alive.store(false, Ordering::SeqCst); 231 | } 232 | } 233 | } 234 | 235 | this.stop(); 236 | })))); 237 | } 238 | } 239 | 240 | impl UniqueId for ActorAsync 241 | where 242 | Msg: Send + 'static, 243 | { 244 | fn get_id(&self) -> String { 245 | self.id.clone() 246 | } 247 | } 248 | 249 | impl 250 | Actor< 251 | Msg, 252 | ContextValue, 253 | HandleAsync, 254 | Box< 255 | dyn FnMut(&mut ActorAsync, Msg, &mut HashMap) 256 | + Send 257 | + Sync 258 | + 'static, 259 | >, 260 | > for ActorAsync 261 | where 262 | Msg: Clone + Send + 'static, 263 | ContextValue: Send + 'static, 264 | { 265 | fn receive( 266 | &mut self, 267 | this: &mut Self, 268 | message: Msg, 269 | context: &mut HashMap, 270 | ) { 271 | { 272 | self.effect.lock().unwrap()(this, message, context); 273 | } 274 | } 275 | fn spawn_with_handle( 276 | &self, 277 | func: Box< 278 | dyn FnMut(&mut ActorAsync, Msg, &mut HashMap) 279 | + Send 280 | + Sync 281 | + 'static, 282 | >, 283 | ) -> HandleAsync { 284 | let mut new_one = Self::new(func); 285 | new_one.parent_handle = Some(self.get_handle()); 286 | { 287 | self.children_handle_map 288 | .lock() 289 | .unwrap() 290 | .insert(new_one.get_id(), new_one.get_handle()); 291 | } 292 | new_one.start(); 293 | return new_one.get_handle(); 294 | } 295 | fn get_handle(&self) -> HandleAsync { 296 | HandleAsync { 297 | id: self.id.clone(), 298 | queue: self.queue.clone(), 299 | } 300 | } 301 | fn get_handle_child(&self, name: impl Into) -> Option> { 302 | match self.children_handle_map.lock().unwrap().get(&name.into()) { 303 | Some(v) => Some(v.clone()), 304 | None => None, 305 | } 306 | } 307 | fn get_handle_parent(&self) -> Option> { 308 | return self.parent_handle.clone(); 309 | } 310 | 311 | fn for_each_child(&self, mut func: impl FnMut(&String, &mut HandleAsync)) { 312 | for (id, handle) in self.children_handle_map.lock().unwrap().iter_mut() { 313 | func(id, handle); 314 | } 315 | } 316 | } 317 | 318 | #[test] 319 | fn test_actor_common() { 320 | use std::time::Duration; 321 | 322 | use super::common::LinkedListAsync; 323 | 324 | #[derive(Clone, Debug)] 325 | enum Value { 326 | // Str(String), 327 | Int(i32), 328 | VecStr(Vec), 329 | Spawn, 330 | Shutdown, 331 | } 332 | 333 | let result_i32 = LinkedListAsync::::new(); 334 | let result_i32_thread = result_i32.clone(); 335 | let result_string = LinkedListAsync::>::new(); 336 | let result_string_thread = result_string.clone(); 337 | let mut root = ActorAsync::new( 338 | move |this: &mut ActorAsync<_, _>, msg: Value, context: &mut HashMap| { 339 | match msg { 340 | Value::Spawn => { 341 | println!("Actor Spawn"); 342 | let result_i32_thread = result_i32_thread.clone(); 343 | let spawned = this.spawn_with_handle(Box::new( 344 | move |this: &mut ActorAsync<_, _>, msg: Value, _| { 345 | match msg { 346 | Value::Int(v) => { 347 | println!("Actor Child Int"); 348 | result_i32_thread.push_back(v * 10); 349 | } 350 | Value::Shutdown => { 351 | println!("Actor Child Shutdown"); 352 | this.stop(); 353 | } 354 | _ => {} 355 | }; 356 | }, 357 | )); 358 | let list = context.get("children_ids").cloned(); 359 | let mut list = match list { 360 | Some(Value::VecStr(list)) => list, 361 | _ => Vec::new(), 362 | }; 363 | list.push(spawned.get_id()); 364 | context.insert("children_ids".into(), Value::VecStr(list)); 365 | } 366 | Value::Shutdown => { 367 | println!("Actor Shutdown"); 368 | if let Some(Value::VecStr(ids)) = context.get("children_ids") { 369 | result_string_thread.push_back(ids.clone()); 370 | } 371 | 372 | this.for_each_child(move |id, handle| { 373 | println!("Actor Shutdown id {:?}", id); 374 | handle.send(Value::Shutdown); 375 | }); 376 | this.stop(); 377 | } 378 | Value::Int(v) => { 379 | println!("Actor Int"); 380 | if let Some(Value::VecStr(ids)) = context.get("children_ids") { 381 | for id in ids { 382 | println!("Actor Int id {:?}", id); 383 | if let Some(mut handle) = this.get_handle_child(id) { 384 | handle.send(Value::Int(v)); 385 | } 386 | } 387 | } 388 | } 389 | _ => {} 390 | } 391 | }, 392 | ); 393 | 394 | let mut root_handle = root.get_handle(); 395 | root.start(); 396 | 397 | // One child 398 | root_handle.send(Value::Spawn); 399 | root_handle.send(Value::Int(10)); 400 | // Two children 401 | root_handle.send(Value::Spawn); 402 | root_handle.send(Value::Int(20)); 403 | // Three children 404 | root_handle.send(Value::Spawn); 405 | root_handle.send(Value::Int(30)); 406 | 407 | // Send Shutdown 408 | root_handle.send(Value::Shutdown); 409 | 410 | thread::sleep(Duration::from_millis(10)); 411 | // 3 children Actors 412 | assert_eq!(3, result_string.pop_front().unwrap().len()); 413 | 414 | let mut v = Vec::>::new(); 415 | for _ in 1..7 { 416 | let i = result_i32.pop_front(); 417 | println!("Actor {:?}", i); 418 | v.push(i); 419 | } 420 | v.sort(); 421 | assert_eq!( 422 | [ 423 | Some(100), 424 | Some(200), 425 | Some(200), 426 | Some(300), 427 | Some(300), 428 | Some(300) 429 | ], 430 | v.as_slice() 431 | ) 432 | } 433 | 434 | #[test] 435 | fn test_actor_ask() { 436 | use std::time::Duration; 437 | 438 | use super::common::LinkedListAsync; 439 | 440 | #[derive(Clone, Debug)] 441 | enum Value { 442 | AskIntByLinkedListAsync((i32, LinkedListAsync)), 443 | AskIntByBlockingQueue((i32, BlockingQueue)), 444 | } 445 | 446 | let mut root = ActorAsync::new( 447 | move |_: &mut ActorAsync<_, _>, msg: Value, _: &mut HashMap| match msg { 448 | Value::AskIntByLinkedListAsync(v) => { 449 | println!("Actor AskIntByLinkedListAsync"); 450 | v.1.push_back(v.0 * 10); 451 | } 452 | Value::AskIntByBlockingQueue(mut v) => { 453 | println!("Actor AskIntByBlockingQueue"); 454 | 455 | // NOTE If negative, hanging for testing timeout 456 | if v.0 < 0 { 457 | return; 458 | } 459 | 460 | // NOTE General Cases 461 | v.1.offer(v.0 * 10); 462 | } // _ => {} 463 | }, 464 | ); 465 | 466 | let mut root_handle = root.get_handle(); 467 | root.start(); 468 | 469 | // LinkedListAsync 470 | let result_i32 = LinkedListAsync::::new(); 471 | root_handle.send(Value::AskIntByLinkedListAsync((1, result_i32.clone()))); 472 | root_handle.send(Value::AskIntByLinkedListAsync((2, result_i32.clone()))); 473 | root_handle.send(Value::AskIntByLinkedListAsync((3, result_i32.clone()))); 474 | thread::sleep(Duration::from_millis(5)); 475 | let i = result_i32.pop_front(); 476 | assert_eq!(Some(10), i); 477 | let i = result_i32.pop_front(); 478 | assert_eq!(Some(20), i); 479 | let i = result_i32.pop_front(); 480 | assert_eq!(Some(30), i); 481 | 482 | // BlockingQueue 483 | let mut result_i32 = BlockingQueue::::new(); 484 | result_i32.timeout = Some(Duration::from_millis(1)); 485 | root_handle.send(Value::AskIntByBlockingQueue((4, result_i32.clone()))); 486 | root_handle.send(Value::AskIntByBlockingQueue((5, result_i32.clone()))); 487 | root_handle.send(Value::AskIntByBlockingQueue((6, result_i32.clone()))); 488 | thread::sleep(Duration::from_millis(5)); 489 | let i = result_i32.take(); 490 | assert_eq!(Some(40), i); 491 | let i = result_i32.take(); 492 | assert_eq!(Some(50), i); 493 | let i = result_i32.take(); 494 | assert_eq!(Some(60), i); 495 | 496 | // Timeout case: 497 | root_handle.send(Value::AskIntByBlockingQueue((-1, result_i32.clone()))); 498 | let i = result_i32.take(); 499 | assert_eq!(None, i); 500 | } 501 | -------------------------------------------------------------------------------- /src/common.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | In this module, there're many `trait`s/`struct`s and `fn`s defined, 3 | for general purposes crossing over many modules of `fpRust`. 4 | */ 5 | 6 | use std::cmp::PartialEq; 7 | use std::collections::LinkedList; 8 | use std::marker::PhantomData; 9 | use std::sync::{Arc, Mutex}; 10 | use std::thread; 11 | use std::time::{SystemTime, UNIX_EPOCH}; 12 | 13 | #[cfg(feature = "for_futures")] 14 | use futures::executor::ThreadPool; 15 | #[cfg(feature = "for_futures")] 16 | use futures::stream::Stream; 17 | #[cfg(feature = "for_futures")] 18 | use std::mem; 19 | #[cfg(feature = "for_futures")] 20 | use std::pin::Pin; 21 | #[cfg(feature = "for_futures")] 22 | use std::sync::{ 23 | atomic::{AtomicBool, Ordering}, 24 | Once, 25 | }; 26 | #[cfg(feature = "for_futures")] 27 | use std::task::{Context, Poll, Waker}; 28 | 29 | // pub trait FnMutReceiveThreadSafe: FnMut(Arc) + Send + Sync + 'static {} 30 | // pub trait FnMutReturnThreadSafe: FnMut() -> X + Send + Sync + 'static {} 31 | 32 | #[cfg(feature = "for_futures")] 33 | #[derive(Clone)] 34 | pub struct SharedThreadPoolReader { 35 | // Since we will be used in many threads, we need to protect 36 | // concurrent access 37 | pub inner: Arc>, 38 | } 39 | #[cfg(feature = "for_futures")] 40 | pub fn shared_thread_pool() -> SharedThreadPoolReader { 41 | // Initialize it to a null value 42 | static mut SINGLETON: *const SharedThreadPoolReader = 0 as *const SharedThreadPoolReader; 43 | static ONCE: Once = Once::new(); 44 | 45 | unsafe { 46 | ONCE.call_once(|| { 47 | // Make it 48 | let singleton = SharedThreadPoolReader { 49 | inner: Arc::new(Mutex::new( 50 | ThreadPool::new().expect("Unable to create threadpool"), 51 | )), 52 | }; 53 | 54 | // Put it in the heap so it can outlive this call 55 | SINGLETON = mem::transmute(Box::new(singleton)); 56 | }); 57 | 58 | // Now we give out a copy of the data that is safe to use concurrently. 59 | (*SINGLETON).clone() 60 | } 61 | } 62 | 63 | /** 64 | 65 | Insert `key-value` pairs into the given `map` 66 | 67 | # Arguments 68 | 69 | * `target` - The target `HashMap` to insert. 70 | * `key, value` - `key-value` pairs. 71 | 72 | */ 73 | #[macro_export] 74 | macro_rules! map_insert { 75 | ($target:ident, { 76 | $($key:ident : $value:expr,)* 77 | }) => { 78 | $( 79 | $target.insert(stringify!($key), $value); 80 | )* 81 | }; 82 | ($target:ident, [ 83 | $($key:ident : $value:expr,)* 84 | ]) => { 85 | $( 86 | $target.insert(stringify!($key), $value); 87 | )* 88 | }; 89 | ($target:ident, { 90 | $($key:expr => $value:expr,)* 91 | }) => { 92 | $( 93 | $target.insert($key, $value); 94 | )* 95 | }; 96 | ($target:ident, [ 97 | $($key:expr => $value:expr,)* 98 | ]) => { 99 | $( 100 | $target.insert($key, $value); 101 | )* 102 | }; 103 | ($target:ident, [ 104 | $($key:expr, $value:expr,)* 105 | ]) => { 106 | $( 107 | $target.insert($key, $value); 108 | )* 109 | }; 110 | } 111 | 112 | /** 113 | Get a mut ref of a specific element of a Vec. 114 | 115 | # Arguments 116 | 117 | * `v` - The mut ref of the `Vec` 118 | * `index` - The index of the element 119 | 120 | # Remarks 121 | 122 | This is a convenience function that gets the `mut ref` of an element of the `Vec`. 123 | 124 | */ 125 | pub fn get_mut<'a, T>(v: &'a mut Vec, index: usize) -> Option<&'a mut T> { 126 | for (i, elem) in v.into_iter().enumerate() { 127 | if index == i { 128 | return Some(elem); 129 | } 130 | } 131 | 132 | None 133 | } 134 | 135 | #[derive(Debug, Clone)] 136 | pub struct LinkedListAsync { 137 | inner: Arc>>, 138 | 139 | #[cfg(feature = "for_futures")] 140 | alive: Arc>, 141 | #[cfg(feature = "for_futures")] 142 | waker: Arc>>, 143 | 144 | _t: PhantomData, 145 | } 146 | 147 | impl LinkedListAsync { 148 | pub fn new() -> Self { 149 | Self { 150 | inner: Arc::new(Mutex::new(LinkedList::new())), 151 | 152 | #[cfg(feature = "for_futures")] 153 | alive: Arc::new(Mutex::new(AtomicBool::new(true))), 154 | #[cfg(feature = "for_futures")] 155 | waker: Arc::new(Mutex::new(None)), 156 | 157 | _t: PhantomData, 158 | } 159 | } 160 | 161 | pub fn push_back(&self, input: T) { 162 | #[cfg(feature = "for_futures")] 163 | { 164 | { 165 | let alive = self.alive.lock().unwrap(); 166 | if alive.load(Ordering::SeqCst) { 167 | self.inner.lock().unwrap().push_back(input); 168 | } 169 | 170 | self.wake(); 171 | } 172 | 173 | return; 174 | } 175 | 176 | #[cfg(not(feature = "for_futures"))] 177 | { 178 | self.inner.lock().unwrap().push_back(input); 179 | } 180 | } 181 | 182 | pub fn pop_front(&self) -> Option { 183 | self.inner.lock().unwrap().pop_front() 184 | } 185 | 186 | #[cfg(feature = "for_futures")] 187 | #[inline] 188 | fn wake(&self) { 189 | let mut waker = self.waker.lock().unwrap(); 190 | if let Some(waker) = waker.take() { 191 | waker.wake(); 192 | } 193 | } 194 | 195 | #[cfg(feature = "for_futures")] 196 | fn open_stream(&mut self) { 197 | self.alive.lock().unwrap().store(true, Ordering::SeqCst); 198 | } 199 | 200 | #[cfg(feature = "for_futures")] 201 | pub fn close_stream(&mut self) { 202 | { 203 | let alive = self.alive.lock().unwrap(); 204 | alive.store(false, Ordering::SeqCst); 205 | 206 | self.wake() 207 | } 208 | } 209 | } 210 | 211 | #[cfg(feature = "for_futures")] 212 | impl Stream for LinkedListAsync 213 | where 214 | T: 'static + Send + Unpin, 215 | { 216 | type Item = T; 217 | 218 | fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 219 | // let mut inner = self.inner.lock().unwrap(); 220 | let alive = self.alive.lock().unwrap(); 221 | let mut waker = self.waker.lock().unwrap(); 222 | 223 | let picked: Option; 224 | // { 225 | // picked = self.pop_front(); 226 | // } 227 | picked = self.pop_front(); 228 | if picked.is_some() { 229 | return Poll::Ready(picked); 230 | } 231 | 232 | // Check alive 233 | if alive.load(Ordering::SeqCst) { 234 | // Check cached 235 | // let picked: Option; 236 | // picked = inner.pop_front(); 237 | 238 | // Check Pending(None) or Ready(Some(item)) 239 | // if picked.is_none() { 240 | // Keep Pending 241 | { 242 | waker.replace(cx.waker().clone()); 243 | }; 244 | return Poll::Pending; 245 | // } 246 | // return Poll::Ready(picked); 247 | } 248 | return Poll::Ready(None); 249 | } 250 | 251 | fn size_hint(&self) -> (usize, Option) { 252 | // Check alive 253 | let alive = self.alive.lock().unwrap(); 254 | if alive.load(Ordering::SeqCst) { 255 | return (0, Some(0)); 256 | } 257 | return (0, None); 258 | } 259 | } 260 | 261 | impl Default for LinkedListAsync> { 262 | fn default() -> Self { 263 | Self::new() 264 | } 265 | } 266 | 267 | /** 268 | `Observable` memorizes all `Subscription` and send notifications. 269 | 270 | # Arguments 271 | 272 | * `X` - The generic type of broadcasted data 273 | * `T` - The generic type implementing `trait` `Subscription` 274 | 275 | # Remarks 276 | 277 | This is an implementation of Observer Pattern of GoF. 278 | 279 | *NOTE*: Inspired by and modified from https://github.com/eliovir/rust-examples/blob/master/design_pattern-observer.rs 280 | */ 281 | pub trait Observable> { 282 | /** 283 | Add a `Subscription`. 284 | 285 | # Arguments 286 | 287 | * `observer` - The given `Subscription`. 288 | 289 | */ 290 | fn add_observer(&mut self, observer: Arc); 291 | 292 | /** 293 | Remove the observer. 294 | 295 | # Arguments 296 | 297 | * `observer` - The given `Subscription`. 298 | 299 | */ 300 | fn delete_observer(&mut self, observer: Arc); 301 | 302 | /** 303 | Notify all `Subscription` subscribers with a given value `Arc`. 304 | 305 | # Arguments 306 | 307 | * `x` - The given `Arc` value for broadcasting. 308 | 309 | */ 310 | fn notify_observers(&mut self, x: Arc); 311 | } 312 | 313 | /** 314 | `Subscription` trait defines the interface of a broadcasting subscriber, 315 | for general purposes crossing over many modules of fpRust. 316 | 317 | # Arguments 318 | 319 | * `X` - The generic type of broadcasted data 320 | 321 | # Remarks 322 | 323 | This is an implementation of Observer Pattern of GoF, and inspired by Rx Subscription. 324 | 325 | */ 326 | pub trait Subscription: Send + Sync + 'static + UniqueId { 327 | /** 328 | The callback when `Subscription` received the broadcasted value. 329 | 330 | # Arguments 331 | 332 | * `func` - The given `FnMut`. 333 | 334 | */ 335 | fn on_next(&self, x: Arc); 336 | } 337 | 338 | /** 339 | `UniqueId` trait defines the interface of an object with an unique id, 340 | for general purposes crossing over many modules of fpRust. 341 | 342 | # Remarks 343 | 344 | This is inspired by Java/Swift Hashable. 345 | 346 | */ 347 | pub trait UniqueId { 348 | /** 349 | The callback when `Subscription` received the broadcasted value. 350 | 351 | # Arguments 352 | 353 | * `func` - The given `FnMut`. 354 | 355 | */ 356 | fn get_id(&self) -> T; 357 | } 358 | 359 | pub fn generate_id() -> String { 360 | let since_the_epoch = SystemTime::now() 361 | .duration_since(UNIX_EPOCH) 362 | .expect("Time went backwards"); 363 | 364 | format!("{:?}{:?}", thread::current().id(), since_the_epoch) 365 | } 366 | 367 | /** 368 | `SubscriptionFunc` struct implements the interface of `Subscription`, 369 | for general purposes crossing over many modules of fpRust. 370 | 371 | # Arguments 372 | 373 | * `T` - The generic type of broadcasted data 374 | 375 | # Remarks 376 | 377 | It's enough to use for general cases of `Subscription`. 378 | 379 | */ 380 | // #[derive(Clone)] 381 | pub struct SubscriptionFunc { 382 | id: String, 383 | pub receiver: RawReceiver, 384 | 385 | #[cfg(feature = "for_futures")] 386 | cached: LinkedListAsync>, 387 | } 388 | 389 | impl SubscriptionFunc { 390 | fn generate_id() -> String { 391 | generate_id() 392 | } 393 | 394 | pub fn new(func: impl FnMut(Arc) + Send + Sync + 'static) -> SubscriptionFunc { 395 | SubscriptionFunc { 396 | id: Self::generate_id(), 397 | receiver: RawReceiver::new(func), 398 | 399 | #[cfg(feature = "for_futures")] 400 | cached: LinkedListAsync::new(), 401 | } 402 | } 403 | } 404 | 405 | impl Clone for SubscriptionFunc { 406 | fn clone(&self) -> Self { 407 | SubscriptionFunc { 408 | // id: Self::generate_id(), 409 | id: self.id.clone(), 410 | receiver: RawReceiver { 411 | func: self.receiver.func.clone(), 412 | _t: PhantomData, 413 | }, 414 | #[cfg(feature = "for_futures")] 415 | cached: self.cached.clone(), 416 | } 417 | } 418 | } 419 | 420 | #[cfg(feature = "for_futures")] 421 | impl SubscriptionFunc { 422 | pub fn close_stream(&mut self) { 423 | self.cached.close_stream(); 424 | } 425 | } 426 | 427 | #[cfg(feature = "for_futures")] 428 | impl SubscriptionFunc 429 | where 430 | T: Unpin, 431 | { 432 | fn open_stream(&mut self) { 433 | self.cached.open_stream(); 434 | } 435 | 436 | pub fn as_stream(&mut self) -> LinkedListAsync> { 437 | self.open_stream(); 438 | 439 | self.cached.clone() 440 | } 441 | } 442 | 443 | impl UniqueId for SubscriptionFunc { 444 | fn get_id(&self) -> String { 445 | self.id.clone() 446 | } 447 | } 448 | 449 | impl PartialEq for SubscriptionFunc { 450 | fn eq(&self, other: &SubscriptionFunc) -> bool { 451 | self.id == other.id 452 | } 453 | } 454 | 455 | impl Subscription for SubscriptionFunc { 456 | fn on_next(&self, x: Arc) { 457 | self.receiver.invoke(x.clone()); 458 | 459 | #[cfg(feature = "for_futures")] 460 | { 461 | self.cached.push_back(x); 462 | } 463 | } 464 | } 465 | 466 | /** 467 | `RawReceiver` struct implements an useful container of `FnMut`(`Arc`) 468 | , receiving an `Arc` as its parameter. 469 | 470 | # Arguments 471 | 472 | * `T` - The generic type of received data. 473 | 474 | # Remarks 475 | 476 | It's the base of implementations of `SubscriptionFunc`. 477 | 478 | */ 479 | #[derive(Clone)] 480 | pub struct RawReceiver { 481 | func: Arc) + Send + Sync + 'static>>, 482 | _t: PhantomData, 483 | } 484 | 485 | impl RawReceiver { 486 | /** 487 | Generate a new `RawReceiver` with the given `FnMut`. 488 | 489 | # Arguments 490 | 491 | * `func` - The given `FnMut`. 492 | 493 | */ 494 | pub fn new(func: impl FnMut(Arc) + Send + Sync + 'static) -> RawReceiver { 495 | RawReceiver { 496 | func: Arc::new(Mutex::new(func)), 497 | _t: PhantomData, 498 | } 499 | } 500 | 501 | /** 502 | Invoke the `FnMut` with the given sent value. 503 | 504 | # Arguments 505 | 506 | * `x` - The sent value. 507 | 508 | */ 509 | pub fn invoke(&self, x: Arc) { 510 | (self.func.lock().unwrap())(x); 511 | } 512 | } 513 | 514 | /** 515 | `RawFunc` struct implements an useful container of `FnMut`, 516 | which could be sent crossing `channel`s. 517 | 518 | # Remarks 519 | 520 | It's the base of sending `FnMut` objects crossing `channel`s. 521 | 522 | */ 523 | #[derive(Clone)] 524 | pub struct RawFunc { 525 | func: Arc>, 526 | } 527 | 528 | impl RawFunc { 529 | /** 530 | Generate a new `RawFunc` with the given `FnMut`. 531 | 532 | # Arguments 533 | 534 | * `func` - The given `FnMut`. 535 | 536 | */ 537 | pub fn new(func: T) -> RawFunc 538 | where 539 | T: FnMut() + Send + Sync + 'static, 540 | { 541 | RawFunc { 542 | func: Arc::new(Mutex::new(func)), 543 | } 544 | } 545 | 546 | /** 547 | Invoke the `FnMut`. 548 | */ 549 | pub fn invoke(&self) { 550 | // let func = &mut *self.func.lock().unwrap(); 551 | (self.func.lock().unwrap())(); 552 | } 553 | } 554 | 555 | #[test] 556 | fn test_map_insert() { 557 | use std::collections::HashMap; 558 | 559 | let expected_by_ident = &mut HashMap::new(); 560 | expected_by_ident.insert("a", "2"); 561 | expected_by_ident.insert("b", "4"); 562 | expected_by_ident.insert("c", "6"); 563 | let actual = &mut HashMap::new(); 564 | map_insert!(actual, [ 565 | a : "2", 566 | b : "4", 567 | c : "6", 568 | ]); 569 | assert_eq!(expected_by_ident, actual); 570 | let actual = &mut HashMap::new(); 571 | map_insert!(actual, { 572 | a : "2", 573 | b : "4", 574 | c : "6", 575 | }); 576 | assert_eq!(expected_by_ident, actual); 577 | 578 | let expected = &mut HashMap::new(); 579 | expected.insert("1", "2"); 580 | expected.insert("3", "4"); 581 | expected.insert("5", "6"); 582 | 583 | let actual = &mut HashMap::new(); 584 | map_insert!(actual, [ 585 | "1" => "2", 586 | "3" => "4", 587 | "5" => "6", 588 | ]); 589 | assert_eq!(expected, actual); 590 | let actual = &mut HashMap::new(); 591 | map_insert!(actual, { 592 | "1" => "2", 593 | "3" => "4", 594 | "5" => "6", 595 | }); 596 | assert_eq!(expected, actual); 597 | 598 | let actual = &mut HashMap::new(); 599 | map_insert!(actual, ["1", "2", "3", "4", "5", "6",]); 600 | assert_eq!(expected, actual); 601 | } 602 | -------------------------------------------------------------------------------- /src/cor.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | In this module there're implementations & tests of `Cor`. 3 | */ 4 | use std::sync::{ 5 | atomic::{AtomicBool, Ordering}, 6 | mpsc::{channel, Receiver, Sender}, 7 | Arc, Mutex, 8 | }; 9 | use std::thread; 10 | 11 | /** 12 | Run codes inside a `doM` block(`Haskell` `do notation`) 13 | (this is a `sync` macro) 14 | 15 | # Arguments 16 | 17 | * `func` - The given `FnMut`, the execution code of `Cor`. 18 | 19 | */ 20 | #[macro_export] 21 | macro_rules! do_m { 22 | ($this:expr) => {{ 23 | let mut _do_m = cor_newmutex!($this, (), ()); 24 | 25 | { 26 | let mut do_m = _do_m.lock().unwrap(); 27 | do_m.set_async(false); 28 | } 29 | 30 | cor_start!(_do_m); 31 | }}; 32 | } 33 | 34 | /** 35 | Run codes inside a `doM` block(`Haskell` `do notation`) 36 | (this is a `sync` macro) 37 | */ 38 | #[macro_export] 39 | macro_rules! do_m_pattern { 40 | ( 41 | let $p:pat = $e:expr ; $( $t:tt )* 42 | ) => ( 43 | { let $p = $e ; do_m_pattern! { $( $t )* } } 44 | ); 45 | ( 46 | let $p:ident : $ty:ty = $e:expr ; $( $t:tt )* 47 | ) => ( 48 | { let $p:$ty = $e ; do_m_pattern! { $( $t )* } } 49 | ); 50 | ( 51 | let mut $p:ident : $ty:ty = $e:expr ; $( $t:tt )* 52 | ) => ( 53 | { let mut $p:$ty = $e ; do_m_pattern! { $( $t )* } } 54 | ); 55 | ( 56 | $p:ident = $e:expr ; $( $t:tt )* 57 | ) => ( 58 | { $p = $e ; do_m_pattern! { $( $t )* } } 59 | ); 60 | ( 61 | exec $b:expr ; $( $t:tt )* 62 | ) => ( 63 | { $b ; do_m_pattern! { $( $t )* } } 64 | ); 65 | ( 66 | ret $e:expr 67 | ) => ( 68 | // vec!() 69 | $e 70 | ); 71 | 72 | ($p:ident $ty:ty, $val:expr, yield_from $cor:expr; $($t:tt)*) => ({ 73 | let $p: Arc>> = Arc::new(Mutex::new(None::<$ty>)); 74 | let _p = $p.clone(); 75 | 76 | let mut _do_m = cor_newmutex!( 77 | move |this| { 78 | let mut p = _p.lock().unwrap(); 79 | *p = cor_yield_from!(this, $cor, $val); 80 | }, 81 | (), 82 | () 83 | ); 84 | 85 | { 86 | let mut do_m = _do_m.lock().unwrap(); 87 | do_m.set_async(false); 88 | } 89 | 90 | cor_start!(_do_m); 91 | 92 | do_m_pattern! { $( $t )* } 93 | 94 | // let mut v = vec!(p); 95 | // let next = &mut do_m_pattern! { $( $t )* }; 96 | // v.append(next); 97 | // v 98 | }); 99 | } 100 | 101 | /** 102 | Define a new `Cor` with type. 103 | It will return a `Arc>`. 104 | 105 | # Arguments 106 | 107 | * `func` - The given `FnMut`, the execution code of `Cor`. 108 | * `RETURN` - The type of returned data 109 | * `RECEIVE` - The type of received data 110 | 111 | */ 112 | #[macro_export] 113 | macro_rules! cor_newmutex { 114 | ($func:expr, $RETURN:ty, $RECEIVE:ty) => { 115 | >::new_with_mutex($func) 116 | }; 117 | } 118 | 119 | /** 120 | Define a new `Cor` with type and start it immediately. 121 | It will return a `Arc>`. 122 | 123 | # Arguments 124 | 125 | * `func` - The given `FnMut`, the execution code of `Cor`. 126 | * `RETURN` - The type of returned data 127 | * `RECEIVE` - The type of received data 128 | 129 | */ 130 | #[macro_export] 131 | macro_rules! cor_newmutex_and_start { 132 | ($func:expr, $RETURN:ty, $RECEIVE:ty) => {{ 133 | let new_one = >::new_with_mutex($func); 134 | cor_start!(new_one); 135 | new_one 136 | }}; 137 | } 138 | 139 | /** 140 | Make `this` returns a given `Option` `given_to_outside` to its callee `Cor`, 141 | and this method returns the `Option` value given from outside. 142 | 143 | # Arguments 144 | 145 | * `this` - The sender when sending `given_to_outside` to callee `Cor`. 146 | * `given_to_outside` - The value sent by `this` and received by `target`. 147 | 148 | # Remarks 149 | 150 | This method is implemented according to some coroutine/generator implementations, 151 | such as `Python`, `Lua`, `ECMASript`...etc. 152 | 153 | */ 154 | #[macro_export] 155 | macro_rules! cor_yield { 156 | ($this:expr, $given_to_outside:expr) => { 157 | Cor::yield_ref($this, $given_to_outside) 158 | }; 159 | } 160 | 161 | /** 162 | Make `this` sends a given `Option` to `target`, 163 | and this method returns the `Option` response from `target`. 164 | 165 | # Arguments 166 | 167 | * `this` - The sender when sending `sent_to_inside` to `target`. 168 | * `target` - The receiver of value `sent_to_inside` sent by `this`. 169 | * `sent_to_inside` - The value sent by `this` and received by `target`. 170 | 171 | # Remarks 172 | 173 | This method is implemented according to some coroutine/generator implementations, 174 | such as `Python`, `Lua`, `ECMASript`...etc. 175 | 176 | */ 177 | #[macro_export] 178 | macro_rules! cor_yield_from { 179 | ($this:expr, $target:expr, $sent_to_inside:expr) => { 180 | Cor::yield_from($this.clone(), $target.clone(), $sent_to_inside) 181 | }; 182 | } 183 | 184 | /** 185 | 186 | Start `this` `Cor`. 187 | 188 | # Arguments 189 | 190 | * `this` - The target `Cor` to start. 191 | 192 | *NOTE*: Beware the deadlock if it's sync(waiting for each other), except the entry point. 193 | 194 | */ 195 | #[macro_export] 196 | macro_rules! cor_start { 197 | ($this:expr) => { 198 | Cor::start($this.clone()) 199 | }; 200 | } 201 | 202 | /** 203 | `CorOp` defines a yield action between `Cor` objects. 204 | 205 | # Arguments 206 | 207 | * `RETURN` - The generic type of returned data 208 | * `RECEIVE` - The generic type of received data 209 | 210 | # Remarks 211 | 212 | It's the base of implementations of `Cor`. 213 | It contains the `Cor` calling `yield_from`() and the val sent together, 214 | and it's necessary to the target `Cor` making the response by `yield_ref`()/`yield_none`(). 215 | 216 | */ 217 | pub struct CorOp { 218 | pub result_ch_sender: Arc>>>, 219 | pub val: Option, 220 | } 221 | impl CorOp {} 222 | 223 | type CorEffect = 224 | dyn FnMut(Arc>>) + Send + Sync + 'static; 225 | 226 | /** 227 | The `Cor` implements a *PythonicGenerator-like Coroutine*. 228 | 229 | # Arguments 230 | 231 | * `RETURN` - The generic type of returned data 232 | * `RECEIVE` - The generic type of received data 233 | 234 | # Remarks 235 | 236 | It could be sync or async up to your usages, 237 | and it could use `yield_from` to send a value to another `Cor` object and get the response, 238 | and use `yield_ref`()/`yield_none`() to return my response to the callee of mine. 239 | 240 | *NOTE*: Beware the deadlock if it's sync(waiting for each other), except the entry point. 241 | 242 | */ 243 | #[derive(Clone)] 244 | pub struct Cor { 245 | is_async: bool, 246 | 247 | started_alive: Arc>, 248 | 249 | op_ch_sender: Arc>>>, 250 | op_ch_receiver: Arc>>>, 251 | effect: Arc>>, 252 | } 253 | impl Cor { 254 | /** 255 | Generate a new `Cor` with the given `FnMut` function for the execution of this `Cor`. 256 | 257 | # Arguments 258 | 259 | * `effect` - The given `FnMut`, the execution code of `Cor`. 260 | 261 | */ 262 | pub fn new( 263 | effect: impl FnMut(Arc>>) + Send + Sync + 'static, 264 | ) -> Cor { 265 | let (op_ch_sender, op_ch_receiver) = channel(); 266 | Cor { 267 | is_async: true, 268 | started_alive: Arc::new(Mutex::new((AtomicBool::new(false), AtomicBool::new(false)))), 269 | 270 | op_ch_sender: Arc::new(Mutex::new(op_ch_sender)), 271 | op_ch_receiver: Arc::new(Mutex::new(op_ch_receiver)), 272 | effect: Arc::new(Mutex::new(effect)), 273 | } 274 | } 275 | 276 | /** 277 | Generate a new `Arc>>` with the given `FnMut` function for the execution of this `Cor`. 278 | 279 | # Arguments 280 | 281 | * `effect` - The given `FnMut`, the execution code of `Cor`. 282 | 283 | */ 284 | pub fn new_with_mutex( 285 | effect: impl FnMut(Arc>>) + Send + Sync + 'static, 286 | ) -> Arc>> { 287 | Arc::new(Mutex::new(>::new(effect))) 288 | } 289 | 290 | /** 291 | Make `this` sends a given `Option` to `target`, 292 | and this method returns the `Option` response from `target`. 293 | 294 | # Arguments 295 | 296 | * `this` - The sender when sending `sent_to_inside` to `target`. 297 | * `target` - The receiver of value `sent_to_inside` sent by `this`. 298 | * `sent_to_inside` - The value sent by `this` and received by `target`. 299 | 300 | # Remarks 301 | 302 | This method is implemented according to some coroutine/generator implementations, 303 | such as `Python`, `Lua`, `ECMASript`...etc. 304 | 305 | */ 306 | pub fn yield_from( 307 | this: Arc>>, 308 | target: Arc>>, 309 | sent_to_inside: Option, 310 | ) -> Option { 311 | // me MutexGuard lifetime block 312 | { 313 | let me = this.lock().unwrap(); 314 | if !me.is_alive() { 315 | return None; 316 | } 317 | } 318 | 319 | // target MutexGuard lifetime block 320 | { 321 | let (result_ch_sender, result_ch_receiver) = channel(); 322 | let _result_ch_sender = Arc::new(Mutex::new(result_ch_sender)); 323 | let _result_ch_receiver = Arc::new(Mutex::new(result_ch_receiver)); 324 | 325 | { 326 | target 327 | .lock() 328 | .unwrap() 329 | .receive(_result_ch_sender.clone(), sent_to_inside); 330 | } 331 | 332 | let result; 333 | { 334 | let result_ch_receiver = _result_ch_receiver.lock().unwrap(); 335 | result = result_ch_receiver.recv(); 336 | } 337 | { 338 | drop(_result_ch_sender.lock().unwrap()); 339 | } 340 | 341 | if let Ok(_x) = result { 342 | return _x; 343 | } 344 | } 345 | 346 | None 347 | } 348 | 349 | /** 350 | Make `this` returns a given `None::` to its callee `Cor`, 351 | and this method returns the `Option` value given from outside. 352 | 353 | # Arguments 354 | 355 | * `this` - The sender when sending `given_to_outside` to callee `Cor`. 356 | 357 | # Remarks 358 | 359 | This method is implemented according to some coroutine/generator implementations, 360 | such as `Python`, `Lua`, `ECMASript`...etc. 361 | 362 | */ 363 | pub fn yield_none(this: Arc>>) -> Option { 364 | Cor::yield_ref(this, None) 365 | } 366 | 367 | /** 368 | Make `this` returns a given `Option` `given_to_outside` to its callee `Cor`, 369 | and this method returns the `Option` value given from outside. 370 | 371 | # Arguments 372 | 373 | * `this` - The sender when sending `given_to_outside` to callee `Cor`. 374 | * `given_to_outside` - The value sent by `this` and received by `target`. 375 | 376 | # Remarks 377 | 378 | This method is implemented according to some coroutine/generator implementations, 379 | such as `Python`, `Lua`, `ECMASript`...etc. 380 | 381 | */ 382 | pub fn yield_ref( 383 | this: Arc>>, 384 | given_to_outside: Option, 385 | ) -> Option { 386 | let _op_ch_receiver; 387 | // me MutexGuard lifetime block 388 | { 389 | let me = this.lock().unwrap(); 390 | if !me.is_alive() { 391 | return None; 392 | } 393 | _op_ch_receiver = me.op_ch_receiver.clone(); 394 | } 395 | 396 | let op; 397 | { 398 | op = _op_ch_receiver.lock().unwrap().recv(); 399 | } 400 | 401 | if let Ok(_x) = op { 402 | { 403 | let _result = _x.result_ch_sender.lock().unwrap().send(given_to_outside); 404 | } 405 | 406 | return _x.val; 407 | } 408 | 409 | None 410 | } 411 | 412 | /** 413 | 414 | Start `this` `Cor`. 415 | 416 | # Arguments 417 | 418 | * `this` - The target `Cor` to start. 419 | 420 | *NOTE*: Beware the deadlock if it's sync(waiting for each other), except the entry point. 421 | 422 | */ 423 | pub fn start(this: Arc>>) { 424 | let is_async; 425 | 426 | { 427 | let me = this.lock().unwrap(); 428 | is_async = me.is_async; 429 | 430 | let started_alive = me.started_alive.lock().unwrap(); 431 | let &(ref started, ref alive) = &*started_alive; 432 | if started.load(Ordering::SeqCst) { 433 | return; 434 | } 435 | started.store(true, Ordering::SeqCst); 436 | alive.store(true, Ordering::SeqCst); 437 | } 438 | 439 | { 440 | let do_things = move || { 441 | { 442 | let mut _effect; 443 | { 444 | _effect = this.lock().unwrap().effect.clone(); 445 | } 446 | 447 | (_effect.lock().unwrap())(this.clone()); 448 | } 449 | 450 | { 451 | this.lock().unwrap().stop(); 452 | } 453 | }; 454 | if is_async { 455 | thread::spawn(do_things); 456 | } else { 457 | do_things(); 458 | } 459 | } 460 | } 461 | 462 | /** 463 | Setup async or not. 464 | Default `async`: `true` 465 | 466 | # Arguments 467 | 468 | * `async` - async when `true`, otherwise `sync`. 469 | 470 | *NOTE*: Beware the deadlock if it's sync(waiting for each other), except the entry point. 471 | 472 | */ 473 | pub fn set_async(&mut self, is_async: bool) { 474 | self.is_async = is_async; 475 | } 476 | 477 | /** 478 | Did this `Cor` start? 479 | Return `true` when it did started (no matter it has stopped or not) 480 | 481 | */ 482 | pub fn is_started(&self) -> bool { 483 | let started_alive = self.started_alive.lock().unwrap(); 484 | let &(ref started, _) = &*started_alive; 485 | started.load(Ordering::SeqCst) 486 | } 487 | 488 | /** 489 | Is this `Cor` alive? 490 | Return `true` when it has started and not stopped yet. 491 | 492 | */ 493 | pub fn is_alive(&self) -> bool { 494 | let started_alive = self.started_alive.lock().unwrap(); 495 | let &(_, ref alive) = &*started_alive; 496 | alive.load(Ordering::SeqCst) 497 | } 498 | 499 | /** 500 | 501 | Stop `Cor`. 502 | This will make self.`is_alive`() returns `false`, 503 | and all `yield_from`() from this `Cor` as `target` will return `None::`. 504 | (Because it has stopped :P, that's reasonable) 505 | 506 | */ 507 | pub fn stop(&mut self) { 508 | { 509 | let started_alive = self.started_alive.lock().unwrap(); 510 | let &(ref started, ref alive) = &*started_alive; 511 | 512 | if !started.load(Ordering::SeqCst) { 513 | return; 514 | } 515 | if !alive.load(Ordering::SeqCst) { 516 | return; 517 | } 518 | alive.store(false, Ordering::SeqCst); 519 | 520 | { 521 | drop(self.op_ch_sender.lock().unwrap()); 522 | } 523 | } 524 | } 525 | 526 | fn receive( 527 | &mut self, 528 | result_ch_sender: Arc>>>, 529 | given_as_request: Option, 530 | ) { 531 | // do_close_safe 532 | // if !self.is_alive() { 533 | let started_alive = self.started_alive.lock().unwrap(); 534 | let &(_, ref alive) = &*started_alive; 535 | if !alive.load(Ordering::SeqCst) { 536 | return; 537 | } 538 | 539 | { 540 | let op_ch_sender = self.op_ch_sender.lock().unwrap(); 541 | let _result = op_ch_sender.send(CorOp { 542 | // cor: cor, 543 | result_ch_sender, 544 | val: given_as_request, 545 | }); 546 | } 547 | } 548 | 549 | /* 550 | fn do_close_safe(&mut self, mut effect: impl FnMut()) { 551 | if !self.is_alive() { 552 | return; 553 | } 554 | 555 | { 556 | let _started_alive = self.started_alive.lock().unwrap(); 557 | 558 | (effect)(); 559 | } 560 | } 561 | */ 562 | } 563 | 564 | #[test] 565 | fn test_cor_do_m() { 566 | let v = Arc::new(Mutex::new(String::from(""))); 567 | 568 | let _v = v.clone(); 569 | do_m!(move |this| { 570 | println!("test_cor_do_m started"); 571 | 572 | let cor_inner1 = cor_newmutex_and_start!( 573 | |this| { 574 | let s = cor_yield!(this, Some(String::from("1"))); 575 | println!("cor_inner1 {:?}", s); 576 | }, 577 | String, 578 | i16 579 | ); 580 | let cor_inner2 = cor_newmutex_and_start!( 581 | |this| { 582 | let s = cor_yield!(this, Some(String::from("2"))); 583 | println!("cor_inner2 {:?}", s); 584 | }, 585 | String, 586 | i16 587 | ); 588 | let cor_inner3 = cor_newmutex_and_start!( 589 | |this| { 590 | let s = cor_yield!(this, Some(String::from("3"))); 591 | println!("cor_inner3 {:?}", s); 592 | }, 593 | String, 594 | i16 595 | ); 596 | 597 | { 598 | (*_v.lock().unwrap()) = [ 599 | cor_yield_from!(this, cor_inner1, Some(1)).unwrap(), 600 | cor_yield_from!(this, cor_inner2, Some(2)).unwrap(), 601 | cor_yield_from!(this, cor_inner3, Some(3)).unwrap(), 602 | ] 603 | .join(""); 604 | } 605 | }); 606 | 607 | let _v = v.clone(); 608 | 609 | { 610 | assert_eq!("123", *_v.lock().unwrap()); 611 | } 612 | } 613 | 614 | #[test] 615 | fn test_cor_do_m_pattern() { 616 | let _r = do_m_pattern! { 617 | let mut _v4 = String::from(""); 618 | _v4 = String::from("4"); 619 | 620 | exec { 621 | println!("do_m_pattern _v4:{:?}", _v4) 622 | }; 623 | 624 | _v1 String, Some(1), yield_from cor_newmutex_and_start!( 625 | |this| { 626 | let s = cor_yield!(this, Some(String::from("1"))); 627 | println!("cor_inner1 {:?}", s); 628 | }, 629 | String, 630 | i16 631 | ); 632 | _v2 String, Some(2), yield_from cor_newmutex_and_start!( 633 | |this| { 634 | let s = cor_yield!(this, Some(String::from("2"))); 635 | println!("cor_inner2 {:?}", s); 636 | }, 637 | String, 638 | i16 639 | ); 640 | _v3 String, Some(3), yield_from cor_newmutex_and_start!( 641 | |this| { 642 | let s = cor_yield!(this, Some(String::from("3"))); 643 | println!("cor_inner3 {:?}", s); 644 | }, 645 | String, 646 | i16 647 | ); 648 | let _v1 = _v1.lock().unwrap(); 649 | let _v2 = _v2.lock().unwrap(); 650 | let _v3 = _v3.lock().unwrap(); 651 | ret [ 652 | _v1.clone().unwrap(), 653 | _v2.clone().unwrap(), 654 | _v3.clone().unwrap(), 655 | _v4, 656 | ].join("") 657 | }; 658 | 659 | assert_eq!("1234", _r); 660 | } 661 | 662 | #[test] 663 | fn test_cor_new() { 664 | use std::time; 665 | 666 | println!("test_cor_new"); 667 | 668 | let _cor1 = cor_newmutex!( 669 | |this| { 670 | println!("cor1 started"); 671 | 672 | let s = cor_yield!(this, Some(String::from("given_to_outside"))); 673 | println!("cor1 {:?}", s); 674 | }, 675 | String, 676 | i16 677 | ); 678 | let cor1 = _cor1.clone(); 679 | 680 | let _cor2 = cor_newmutex!( 681 | move |this| { 682 | println!("cor2 started"); 683 | 684 | println!("cor2 yield_from before"); 685 | 686 | let s = cor_yield_from!(this, cor1, Some(3)); 687 | println!("cor2 {:?}", s); 688 | }, 689 | i16, 690 | i16 691 | ); 692 | 693 | { 694 | let cor1 = _cor1.clone(); 695 | cor1.lock().unwrap().set_async(true); // NOTE Cor default async 696 | // NOTE cor1 should keep async to avoid deadlock waiting.(waiting for each other) 697 | } 698 | { 699 | let cor2 = _cor2.clone(); 700 | cor2.lock().unwrap().set_async(false); 701 | // NOTE cor2 is the entry point, so it could be sync without any deadlock. 702 | } 703 | cor_start!(_cor1); 704 | cor_start!(_cor2); 705 | 706 | thread::sleep(time::Duration::from_millis(1)); 707 | } 708 | -------------------------------------------------------------------------------- /src/fp.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | In this module there're implementations & tests 3 | of general functional programming features. 4 | */ 5 | 6 | /** 7 | Pipe functions. 8 | 9 | *NOTE*: Credit https://stackoverflow.com/questions/45786955/how-to-compose-functions-in-rust 10 | */ 11 | #[macro_export] 12 | macro_rules! pipe { 13 | ( $last:expr ) => { $last }; 14 | ( $head:expr, $($tail:expr), +) => { 15 | compose_two($head, pipe!($($tail),+)) 16 | }; 17 | } 18 | 19 | /** 20 | Compose functions. 21 | 22 | *NOTE*: Credit https://stackoverflow.com/questions/45786955/how-to-compose-functions-in-rust 23 | */ 24 | #[macro_export] 25 | macro_rules! compose { 26 | ( $last:expr ) => { $last }; 27 | ( $head:expr, $($tail:expr), +) => { 28 | compose_two(compose!($($tail),+), $head) 29 | }; 30 | } 31 | 32 | /** 33 | `Spread` the variadic arguments and call the given funciton. 34 | */ 35 | #[macro_export] 36 | macro_rules! spread_and_call { 37 | ($func:expr, $($x:expr), *) => { 38 | $func($($x), *); 39 | }; 40 | } 41 | 42 | /** 43 | `Partial` application macro with variadic arguments for a pre-defined function, 44 | and currying the lastest one argument by returning closure. 45 | */ 46 | #[macro_export] 47 | macro_rules! partial_left_last_one { 48 | ($func:expr, $($x:expr), *) => { 49 | |v| spread_and_call!($func, $($x), *, v) 50 | }; 51 | } 52 | 53 | /** 54 | `Map` macro for `Vec`, in currying ways by `partial_left_last_one!`(). 55 | */ 56 | #[macro_export] 57 | macro_rules! map { 58 | ($func:expr) => { 59 | partial_left_last_one!(map, $func) 60 | }; 61 | } 62 | 63 | /** 64 | `Filter` macro for `Vec`, in currying ways by `partial_left_last_one!`(). 65 | */ 66 | #[macro_export] 67 | macro_rules! filter { 68 | ($func:expr) => { 69 | partial_left_last_one!(filter, $func) 70 | }; 71 | } 72 | 73 | /** 74 | `Reduce` macro for `Vec`, in currying ways by `partial_left_last_one!`(). 75 | */ 76 | #[macro_export] 77 | macro_rules! reduce { 78 | ($func:expr) => { 79 | partial_left_last_one!(reduce, $func) 80 | }; 81 | } 82 | 83 | /** 84 | `Foldl` macro for `Vec`, in currying ways by `partial_left_last_one!`(). 85 | */ 86 | #[macro_export] 87 | macro_rules! foldl { 88 | ($func:expr, $second:expr) => { 89 | partial_left_last_one!(foldl, $func, $second) 90 | }; 91 | } 92 | 93 | /** 94 | `Foldr` macro for `Vec`, in currying ways by `partial_left_last_one!`(). 95 | */ 96 | #[macro_export] 97 | macro_rules! foldr { 98 | ($func:expr, $second:expr) => { 99 | partial_left_last_one!(foldr, $func, $second) 100 | }; 101 | } 102 | 103 | /** 104 | `Reverse` macro for `Vec`, in currying ways. 105 | */ 106 | #[macro_export] 107 | macro_rules! reverse { 108 | () => { 109 | |v| reverse(v) 110 | }; 111 | } 112 | 113 | /** 114 | `Contains` macro for `Vec`, in currying ways by `partial_left_last_one!`(). 115 | */ 116 | #[macro_export] 117 | macro_rules! contains { 118 | ($x:expr) => { 119 | partial_left_last_one!(contains, $x) 120 | }; 121 | } 122 | 123 | /** 124 | Compose two functions into one. 125 | Return `f(g(x))` 126 | 127 | # Arguments 128 | 129 | * `f` - The given `FnOnce`. 130 | * `g` - The given `FnOnce`. 131 | 132 | *NOTE*: Credit https://stackoverflow.com/questions/45786955/how-to-compose-functions-in-rust 133 | */ 134 | #[inline] 135 | pub fn compose_two(f: F, g: G) -> impl FnOnce(A) -> C 136 | where 137 | F: FnOnce(A) -> B, 138 | G: FnOnce(B) -> C, 139 | { 140 | move |x| g(f(x)) 141 | } 142 | 143 | #[inline] 144 | pub fn map(f: impl FnMut(T) -> B, v: Vec) -> Vec { 145 | v.into_iter().map(f).collect::>() 146 | } 147 | 148 | #[inline] 149 | pub fn filter<'r, T: 'r>(f: impl FnMut(&T) -> bool, v: Vec) -> Vec { 150 | v.into_iter().filter(f).into_iter().collect::>() 151 | } 152 | 153 | #[inline] 154 | pub fn foldl(f: impl FnMut(B, T) -> B, initial: B, v: Vec) -> B { 155 | v.into_iter().fold(initial, f) 156 | } 157 | 158 | #[inline] 159 | pub fn foldr(f: impl FnMut(B, T) -> B, initial: B, v: Vec) -> B { 160 | v.into_iter().rev().fold(initial, f) 161 | } 162 | 163 | #[inline] 164 | pub fn reverse(v: Vec) -> Vec { 165 | v.into_iter().rev().collect::>() 166 | } 167 | 168 | #[inline] 169 | pub fn contains(x: &T, v: Vec) -> bool { 170 | v.contains(x) 171 | } 172 | 173 | /** 174 | Implementations of `ECMASript`-like `reduce`() 175 | 176 | # Arguments 177 | 178 | * `T` - The generic type of data. 179 | 180 | *NOTE*: Credit https://github.com/dtolnay/reduce 181 | */ 182 | pub trait Reduce { 183 | fn reduce(self, f: F) -> Option 184 | where 185 | Self: Sized, 186 | F: FnMut(T, T) -> T; 187 | } 188 | 189 | impl Reduce for I 190 | where 191 | I: Iterator, 192 | { 193 | #[inline] 194 | fn reduce(mut self, f: F) -> Option 195 | where 196 | Self: Sized, 197 | F: FnMut(T, T) -> T, 198 | { 199 | self.next().map(|first| self.fold(first, f)) 200 | } 201 | } 202 | 203 | #[inline] 204 | pub fn reduce<'r, T: 'r>(f: impl FnMut(T, T) -> T, v: Vec) -> Option { 205 | Reduce::reduce(v.into_iter(), f) 206 | } 207 | 208 | #[test] 209 | fn test_compose() { 210 | let add = |x| x + 2; 211 | let multiply = |x| x * 3; 212 | let divide = |x| x / 2; 213 | 214 | let result = (compose!(add, multiply, divide))(10); 215 | assert_eq!(17, result); 216 | println!("Composed FnOnce Result is {}", result); 217 | 218 | let result = (pipe!(add, multiply, divide))(10); 219 | assert_eq!(18, result); 220 | println!("Piped FnOnce Result is {}", result); 221 | } 222 | 223 | #[test] 224 | fn test_map_reduce_filter() { 225 | let result = 226 | (compose!(reduce!(|a, b| a * b), filter!(|x| *x < 6), map!(|x| x * 2)))(vec![1, 2, 3, 4]); 227 | assert_eq!(Some(8), result); 228 | println!("test_map_reduce_filter Result is {:?}", result); 229 | } 230 | 231 | #[test] 232 | fn test_foldl_foldr() { 233 | // foldl!(f, initial) 234 | let result = (compose!( 235 | foldl!( 236 | |a, b| { 237 | if a < 4 { 238 | return a + b; 239 | } 240 | return a; 241 | }, 242 | 0 243 | ), 244 | filter!(|x| *x < 6), 245 | map!(|x| x * 2) 246 | ))(vec![1, 2, 3, 4]); 247 | assert_eq!(6, result); 248 | println!("foldl Result is {:?}", result); 249 | 250 | // foldr!(f, initial) 251 | let result = (compose!( 252 | foldr!( 253 | |a, b| { 254 | if a < 4 { 255 | return a + b; 256 | } 257 | return a; 258 | }, 259 | 0 260 | ), 261 | filter!(|x| *x < 6), 262 | map!(|x| x * 2) 263 | ))(vec![1, 2, 3, 4]); 264 | assert_eq!(4, result); 265 | println!("foldr Result is {:?}", result); 266 | } 267 | 268 | #[test] 269 | fn test_contains() { 270 | assert_eq!(true, contains!(&4)(vec![1, 2, 3, 4])); 271 | } 272 | 273 | #[test] 274 | fn test_reverse() { 275 | assert_eq!(vec![4, 3, 2, 1], reverse!()(vec![1, 2, 3, 4])); 276 | } 277 | -------------------------------------------------------------------------------- /src/handler.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | In this module there're implementations & tests of `Handler`. 3 | (Inspired by `Android Handler`) 4 | */ 5 | use std::sync::{ 6 | atomic::{AtomicBool, Ordering}, 7 | Arc, Mutex, 8 | }; 9 | use std::thread; 10 | 11 | use super::common::RawFunc; 12 | use super::sync as fpSync; 13 | use super::sync::Queue; 14 | 15 | /** 16 | `Handler` `trait` defines the interface which could receive `FnMut` and run them on its own `thread`. 17 | 18 | # Remarks 19 | 20 | This is highly inspired by `Android Handler` concepts. 21 | 22 | */ 23 | pub trait Handler: Send + Sync + 'static { 24 | /** 25 | Did this `Handler` start? 26 | Return `true` when it did started (no matter it has stopped or not) 27 | 28 | */ 29 | fn is_started(&mut self) -> bool; 30 | 31 | /** 32 | Is this `Handler` alive? 33 | Return `true` when it has started and not stopped yet. 34 | */ 35 | fn is_alive(&mut self) -> bool; 36 | 37 | /** 38 | Start `Handler`. 39 | */ 40 | fn start(&mut self); 41 | 42 | /** 43 | 44 | Stop `Cor`. 45 | This will make self.`is_alive`() returns `false`, 46 | and all `FnMut` posted by self.`post`() will not be executed. 47 | (Because it has stopped :P, that's reasonable) 48 | 49 | */ 50 | fn stop(&mut self); 51 | 52 | /** 53 | Post a job which will run on this `Handler`. 54 | 55 | # Arguments 56 | 57 | * `func` - The posted job. 58 | `` 59 | */ 60 | fn post(&mut self, func: RawFunc); 61 | } 62 | 63 | /** 64 | `HandlerThread` could receive `FnMut` and run them on its own `thread`. 65 | It implements `Handler` `trait` simply and works well. 66 | 67 | This is kind of facade which just handles `thread`, 68 | and bypasses jobs to `HandlerThreadInner`(private implementations). 69 | 70 | # Remarks 71 | 72 | This is highly inspired by `Android Handler` concepts. 73 | 74 | */ 75 | #[derive(Clone)] 76 | pub struct HandlerThread { 77 | started_alive: Arc>, 78 | 79 | inner: Arc, 80 | 81 | handle: Arc>>>, 82 | } 83 | 84 | impl Default for HandlerThread { 85 | fn default() -> Self { 86 | HandlerThread { 87 | started_alive: Arc::new(Mutex::new((AtomicBool::new(false), AtomicBool::new(false)))), 88 | inner: Arc::new(HandlerThreadInner::new()), 89 | 90 | handle: Arc::new(Mutex::new(None)), 91 | } 92 | } 93 | } 94 | 95 | impl HandlerThread { 96 | pub fn new() -> HandlerThread { 97 | Default::default() 98 | } 99 | pub fn new_with_mutex() -> Arc> { 100 | Arc::new(Mutex::new(HandlerThread::new())) 101 | } 102 | } 103 | 104 | impl Handler for HandlerThread { 105 | fn is_started(&mut self) -> bool { 106 | let started_alive = self.started_alive.lock().unwrap(); 107 | let &(ref started, _) = &*started_alive; 108 | started.load(Ordering::SeqCst) 109 | } 110 | 111 | fn is_alive(&mut self) -> bool { 112 | let started_alive = self.started_alive.lock().unwrap(); 113 | let &(_, ref alive) = &*started_alive; 114 | alive.load(Ordering::SeqCst) 115 | } 116 | 117 | fn start(&mut self) { 118 | { 119 | let started_alive = self.started_alive.lock().unwrap(); 120 | let &(ref started, ref alive) = &*started_alive; 121 | 122 | if started.load(Ordering::SeqCst) { 123 | return; 124 | } 125 | started.store(true, Ordering::SeqCst); 126 | if alive.load(Ordering::SeqCst) { 127 | return; 128 | } 129 | alive.store(true, Ordering::SeqCst); 130 | } 131 | 132 | let mut _inner = self.inner.clone(); 133 | let mut this = self.clone(); 134 | self.handle = Arc::new(Mutex::new(Some(thread::spawn(move || { 135 | Arc::make_mut(&mut _inner).start(); 136 | 137 | this.stop(); 138 | })))); 139 | } 140 | 141 | fn stop(&mut self) { 142 | { 143 | let started_alive = self.started_alive.lock().unwrap(); 144 | let &(ref started, ref alive) = &*started_alive; 145 | 146 | if !started.load(Ordering::SeqCst) { 147 | return; 148 | } 149 | if !alive.load(Ordering::SeqCst) { 150 | return; 151 | } 152 | alive.store(false, Ordering::SeqCst); 153 | } 154 | 155 | Arc::make_mut(&mut self.inner).stop(); 156 | 157 | // NOTE: Kill thread <- OS depending 158 | // let mut handle = self.handle.lock().unwrap(); 159 | // handle 160 | // .take() 161 | // .expect("Called stop on non-running thread") 162 | // .join() 163 | // .expect("Could not join spawned thread"); 164 | } 165 | 166 | fn post(&mut self, func: RawFunc) { 167 | Arc::make_mut(&mut self.inner).post(func); 168 | } 169 | } 170 | 171 | #[derive(Clone)] 172 | struct HandlerThreadInner { 173 | // this: Option>, 174 | started: Arc, 175 | alive: Arc, 176 | q: Arc>, 177 | } 178 | 179 | impl HandlerThreadInner { 180 | pub fn new() -> HandlerThreadInner { 181 | HandlerThreadInner { 182 | started: Arc::new(AtomicBool::new(false)), 183 | alive: Arc::new(AtomicBool::new(false)), 184 | q: Arc::new(>::new()), 185 | } 186 | } 187 | } 188 | 189 | impl Handler for HandlerThreadInner { 190 | fn is_started(&mut self) -> bool { 191 | self.started.load(Ordering::SeqCst) 192 | } 193 | 194 | fn is_alive(&mut self) -> bool { 195 | self.alive.load(Ordering::SeqCst) 196 | } 197 | 198 | fn start(&mut self) { 199 | self.alive.store(true, Ordering::SeqCst); 200 | 201 | if self.is_started() { 202 | return; 203 | } 204 | self.started.store(true, Ordering::SeqCst); 205 | 206 | let q = Arc::make_mut(&mut self.q); 207 | 208 | while self.alive.load(Ordering::SeqCst) { 209 | let v = q.take(); 210 | 211 | match v { 212 | Some(f) => { 213 | f.invoke(); 214 | } 215 | None => { 216 | self.alive.store(false, Ordering::SeqCst); 217 | } 218 | } 219 | } 220 | } 221 | 222 | fn stop(&mut self) { 223 | self.alive.store(false, Ordering::SeqCst); 224 | } 225 | 226 | fn post(&mut self, func: RawFunc) { 227 | let q = Arc::make_mut(&mut self.q); 228 | 229 | q.put(func); 230 | } 231 | } 232 | 233 | #[test] 234 | fn test_handler_new() { 235 | use super::sync::CountDownLatch; 236 | use std::time; 237 | 238 | let mut _h = HandlerThread::new_with_mutex(); 239 | let mut h = _h.lock().unwrap(); 240 | 241 | assert_eq!(false, h.is_alive()); 242 | assert_eq!(false, h.is_started()); 243 | 244 | h.stop(); 245 | h.stop(); 246 | assert_eq!(false, h.is_alive()); 247 | assert_eq!(false, h.is_started()); 248 | // let mut h1 = _h.clone(); 249 | h.start(); 250 | assert_eq!(true, h.is_alive()); 251 | assert_eq!(true, h.is_started()); 252 | 253 | let latch = CountDownLatch::new(1); 254 | let latch2 = latch.clone(); 255 | 256 | // /* 257 | h.post(RawFunc::new(move || { 258 | println!("Executed !"); 259 | 260 | let latch3 = latch2.clone(); 261 | 262 | let mut _h2 = HandlerThread::new_with_mutex(); 263 | let mut _h2_inside = _h2.clone(); 264 | 265 | let mut h2 = _h2.lock().unwrap(); 266 | h2.start(); 267 | 268 | h2.post(RawFunc::new(move || { 269 | latch3.countdown(); 270 | 271 | { 272 | _h2_inside.lock().unwrap().stop(); 273 | } 274 | })); 275 | })); 276 | println!("Test"); 277 | 278 | thread::sleep(time::Duration::from_millis(1)); 279 | 280 | assert_eq!(true, h.is_alive()); 281 | assert_eq!(true, h.is_started()); 282 | 283 | h.stop(); 284 | thread::sleep(time::Duration::from_millis(1)); 285 | 286 | assert_eq!(false, h.is_alive()); 287 | assert_eq!(true, h.is_started()); 288 | 289 | latch.clone().wait(); 290 | } 291 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "for_futures")] 2 | extern crate futures; 3 | // #[cfg(feature = "for_futures")] 4 | // extern crate tokio; 5 | 6 | pub mod common; 7 | 8 | #[cfg(feature = "handler")] 9 | pub mod handler; 10 | #[cfg(feature = "publisher")] 11 | pub mod publisher; 12 | #[cfg(feature = "sync")] 13 | pub mod sync; 14 | 15 | #[cfg(feature = "actor")] 16 | pub mod actor; 17 | #[cfg(feature = "cor")] 18 | pub mod cor; 19 | #[cfg(feature = "fp")] 20 | pub mod fp; 21 | #[cfg(feature = "maybe")] 22 | pub mod maybe; 23 | #[cfg(feature = "monadio")] 24 | pub mod monadio; 25 | -------------------------------------------------------------------------------- /src/maybe.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | In this module there're implementations & tests of `Maybe`. 3 | */ 4 | 5 | use std::sync::Arc; 6 | 7 | /** 8 | `Maybe` wraps built-in `Option`, 9 | and implements `Applicative` and `Chain` of `fantasy-land`. 10 | 11 | # Arguments 12 | 13 | * `T` - The generic type of data 14 | 15 | # Remarks 16 | 17 | It implements `Applicative` and `Chain` of `fantasy-land`, 18 | and use the same interface as `fpEs` & `fpGo`(sister libraries :P) 19 | 20 | `` 21 | */ 22 | #[derive(Clone)] 23 | pub struct Maybe { 24 | r: Arc>, 25 | } 26 | 27 | impl Maybe { 28 | pub fn option(&self) -> Option { 29 | self.r.as_ref().clone() 30 | } 31 | pub fn unwrap(&self) -> T { 32 | self.r.as_ref().clone().unwrap() 33 | } 34 | pub fn or(&self, val: T) -> T { 35 | self.r.as_ref().clone().unwrap_or(val) 36 | } 37 | } 38 | 39 | impl From for Maybe { 40 | fn from(r: T) -> Self { 41 | Maybe::just(Some(r)) 42 | } 43 | } 44 | 45 | impl Maybe { 46 | pub fn just(r: Option) -> Maybe { 47 | Maybe { r: Arc::new(r) } 48 | } 49 | pub fn of(r: Option) -> Maybe { 50 | Maybe::just(r) 51 | } 52 | pub fn val(r: T) -> Maybe { 53 | Maybe::just(Some(r)) 54 | } 55 | 56 | pub fn present(&self) -> bool { 57 | match self.r.as_ref() { 58 | Some(_x) => true, 59 | None => false, 60 | } 61 | } 62 | pub fn null(&self) -> bool { 63 | match self.r.as_ref() { 64 | Some(_x) => false, 65 | None => true, 66 | } 67 | } 68 | pub fn let_do(&self, func: F) 69 | where 70 | F: FnOnce(&T), 71 | { 72 | match self.r.as_ref() { 73 | Some(_x) => func(&_x), 74 | None => (), 75 | } 76 | } 77 | 78 | pub fn fmap(&self, func: F) -> Maybe 79 | where 80 | F: FnOnce(&Option) -> Maybe, 81 | { 82 | func(self.r.as_ref()) 83 | } 84 | pub fn map(&self, func: F) -> Maybe 85 | where 86 | F: FnOnce(&Option) -> Option, 87 | G: 'static, 88 | { 89 | Maybe::just(func(self.r.as_ref())) 90 | } 91 | pub fn bind(&self, func: F) -> Maybe 92 | where 93 | F: FnOnce(&Option) -> Option, 94 | G: 'static, 95 | { 96 | self.map(func) 97 | } 98 | pub fn then(&self, func: F) -> Maybe 99 | where 100 | F: FnOnce(&Option) -> Option, 101 | G: 'static, 102 | { 103 | self.map(func) 104 | } 105 | pub fn chain(&self, func: F) -> Maybe 106 | where 107 | F: FnOnce(&Option) -> Maybe, 108 | { 109 | self.fmap(func) 110 | } 111 | pub fn ap(&self, maybe_func: &Maybe) -> Maybe 112 | where 113 | F: FnOnce(&Option) -> Option + Clone + 'static, 114 | G: 'static, 115 | { 116 | maybe_func.chain(|f| self.map(f.clone().unwrap())) 117 | } 118 | } 119 | 120 | #[test] 121 | fn test_maybe_present() { 122 | assert_eq!(false, Maybe::just(None::).present()); 123 | assert_eq!(true, Maybe::val(true).present()); 124 | 125 | assert_eq!(true, Maybe::just(None::).null()); 126 | assert_eq!(false, Maybe::val(true).null()); 127 | 128 | let mut val; 129 | 130 | val = false; 131 | Maybe::just(None::).let_do(|x| val = *x); 132 | assert_eq!(false, val); 133 | 134 | val = false; 135 | Maybe::val(true).let_do(|x| val = *x); 136 | assert_eq!(true, val); 137 | } 138 | #[test] 139 | fn test_maybe_flatmap() { 140 | assert_eq!( 141 | false, 142 | Maybe::val(true) 143 | .fmap(|x| return Maybe::val(!x.unwrap())) 144 | .unwrap() 145 | ); 146 | assert_eq!( 147 | true, 148 | Maybe::val(false) 149 | .fmap(|x| return Maybe::val(!x.unwrap())) 150 | .unwrap() 151 | ); 152 | 153 | assert_eq!( 154 | false, 155 | Maybe::val(true).map(|x| return Some(!x.unwrap())).unwrap() 156 | ); 157 | assert_eq!( 158 | true, 159 | Maybe::val(false).map(|x| return Some(!x.unwrap())).unwrap() 160 | ); 161 | 162 | assert_eq!( 163 | true, 164 | Maybe::val(1) 165 | .ap(&Maybe::val(|x: &Option| if x.unwrap() > 0 { 166 | return Some(true); 167 | } else { 168 | return Some(false); 169 | })) 170 | .unwrap() 171 | ); 172 | } 173 | #[test] 174 | fn test_maybe_unwrap() { 175 | assert_eq!(false, Maybe::just(None::).or(false)); 176 | assert_eq!(true, Maybe::val(true).or(false)); 177 | use std::panic; 178 | 179 | let none_unwrap = panic::catch_unwind(|| { 180 | Maybe::just(None::).unwrap(); 181 | }); 182 | assert_eq!(true, none_unwrap.is_err()); 183 | assert_eq!(true, Maybe::val(true).unwrap()); 184 | 185 | assert_eq!( 186 | true, 187 | match Maybe::val(true).option() { 188 | None => false, 189 | Some(_x) => true, 190 | } 191 | ); 192 | assert_eq!( 193 | false, 194 | match Maybe::just(None::).option() { 195 | None => false, 196 | Some(_x) => true, 197 | } 198 | ); 199 | } 200 | -------------------------------------------------------------------------------- /src/monadio.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | In this module there're implementations & tests of `MonadIO`. 3 | It's inspired by `Rx` & `MonadIO` in `Haskell` 4 | */ 5 | use std::sync::{Arc, Mutex}; 6 | 7 | #[cfg(feature = "for_futures")] 8 | use super::common::shared_thread_pool; 9 | #[cfg(feature = "for_futures")] 10 | use crate::futures::task::SpawnExt; 11 | #[cfg(feature = "for_futures")] 12 | use std::error::Error; 13 | 14 | use super::handler::Handler; 15 | 16 | use super::sync::CountDownLatch; 17 | 18 | use super::common::{RawFunc, Subscription, SubscriptionFunc}; 19 | 20 | /** 21 | `MonadIO` implements basic `Rx`/`MonadIO` APIs. 22 | The `observe` and `subscribe` actions could be sync/async, 23 | and `observe` & `subscribe` could be on other `thread`s 24 | (by setting up `observe_on` and `subscribe_on`). 25 | 26 | # Arguments 27 | 28 | * `Y` - The generic type of data 29 | 30 | # Remarks 31 | 32 | It's inspired by `Rx` & `MonadIO` in `Haskell` 33 | , and easily run it on sync/async scenaios. 34 | 35 | `` 36 | */ 37 | #[derive(Clone)] 38 | pub struct MonadIO { 39 | effect: Arc Y + Send + Sync + 'static>>, 40 | ob_handler: Option>>, 41 | sub_handler: Option>>, 42 | } 43 | 44 | pub fn of(r: Z) -> impl FnMut() -> Z + Send + Sync + 'static { 45 | let _r = Box::new(r); 46 | 47 | move || *_r.clone() 48 | } 49 | 50 | impl From for MonadIO { 51 | fn from(r: Y) -> Self { 52 | MonadIO::just(r) 53 | } 54 | } 55 | 56 | impl MonadIO { 57 | pub fn just(r: Y) -> MonadIO { 58 | MonadIO::new(of(r)) 59 | } 60 | 61 | #[cfg(feature = "for_futures")] 62 | pub async fn to_future(&self) -> Result, Box> { 63 | // let mio = self.map(|y| y); 64 | let mio = self.clone(); 65 | let future = { 66 | shared_thread_pool() 67 | .inner 68 | .lock() 69 | .unwrap() 70 | .spawn_with_handle(async move { mio.eval() })? 71 | }; 72 | let result = future.await; 73 | Ok(result) 74 | } 75 | } 76 | 77 | impl MonadIO { 78 | pub fn new(effect: impl FnMut() -> Y + Send + Sync + 'static) -> MonadIO { 79 | MonadIO::new_with_handlers(effect, None, None) 80 | } 81 | 82 | pub fn new_with_handlers( 83 | effect: impl FnMut() -> Y + Send + Sync + 'static, 84 | ob: Option>>, 85 | sub: Option>>, 86 | ) -> MonadIO { 87 | MonadIO { 88 | effect: Arc::new(Mutex::new(effect)), 89 | ob_handler: ob, 90 | sub_handler: sub, 91 | } 92 | } 93 | 94 | pub fn observe_on(&mut self, h: Option>>) { 95 | self.ob_handler = h; 96 | } 97 | 98 | pub fn subscribe_on(&mut self, h: Option>>) { 99 | self.sub_handler = h; 100 | } 101 | 102 | pub fn map( 103 | &self, 104 | func: impl FnMut(Y) -> Z + Send + Sync + 'static, 105 | ) -> MonadIO { 106 | let _func = Arc::new(Mutex::new(func)); 107 | let mut _effect = self.effect.clone(); 108 | 109 | MonadIO::new_with_handlers( 110 | move || (_func.lock().unwrap())((_effect.lock().unwrap())()), 111 | self.ob_handler.clone(), 112 | self.sub_handler.clone(), 113 | ) 114 | } 115 | pub fn fmap( 116 | &self, 117 | func: impl FnMut(Y) -> MonadIO + Send + Sync + 'static, 118 | ) -> MonadIO { 119 | let mut _func = Arc::new(Mutex::new(func)); 120 | 121 | self.map(move |y: Y| ((_func.lock().unwrap())(y).effect.lock().unwrap())()) 122 | } 123 | pub fn subscribe(&self, s: Arc>) { 124 | let mut _effect = self.effect.clone(); 125 | 126 | match &self.ob_handler { 127 | Some(ob_handler) => { 128 | let mut sub_handler_thread = Arc::new(self.sub_handler.clone()); 129 | ob_handler.lock().unwrap().post(RawFunc::new(move || { 130 | match Arc::make_mut(&mut sub_handler_thread) { 131 | Some(ref mut sub_handler) => { 132 | let effect = _effect.clone(); 133 | let s = s.clone(); 134 | sub_handler.lock().unwrap().post(RawFunc::new(move || { 135 | let result = { Arc::new(effect.lock().unwrap()()) }; 136 | s.on_next(result); 137 | })); 138 | } 139 | None => { 140 | s.on_next(Arc::new(_effect.lock().unwrap()())); 141 | } 142 | } 143 | })); 144 | } 145 | None => { 146 | s.on_next(Arc::new(_effect.lock().unwrap()())); 147 | } 148 | } 149 | } 150 | pub fn subscribe_fn(&self, func: impl FnMut(Arc) + Send + Sync + 'static) { 151 | self.subscribe(Arc::new(SubscriptionFunc::new(func))) 152 | } 153 | 154 | pub fn eval(&self) -> Arc { 155 | let latch = CountDownLatch::new(1); 156 | let latch_thread = latch.clone(); 157 | 158 | let result = Arc::new(Mutex::new(None::>)); 159 | let result_thread = result.clone(); 160 | self.subscribe_fn(move |y| { 161 | result_thread.lock().unwrap().replace(y); 162 | 163 | latch_thread.countdown(); 164 | }); 165 | 166 | latch.wait(); 167 | let result = result.lock().as_mut().unwrap().to_owned(); 168 | result.unwrap() 169 | } 170 | } 171 | 172 | #[cfg(feature = "for_futures")] 173 | #[futures_test::test] 174 | async fn test_monadio_async() { 175 | assert_eq!(Arc::new(3), MonadIO::just(3).eval()); 176 | assert_eq!( 177 | Arc::new(3), 178 | MonadIO::just(3).to_future().await.ok().unwrap() 179 | ); 180 | assert_eq!( 181 | Arc::new(6), 182 | MonadIO::just(3) 183 | .map(|i| i * 2) 184 | .to_future() 185 | .await 186 | .ok() 187 | .unwrap() 188 | ); 189 | } 190 | 191 | #[test] 192 | fn test_monadio_new() { 193 | use super::common::SubscriptionFunc; 194 | use super::handler::HandlerThread; 195 | use std::sync::Arc; 196 | use std::{thread, time}; 197 | 198 | use super::sync::CountDownLatch; 199 | 200 | let monadio_simple = MonadIO::just(3); 201 | // let mut monadio_simple = MonadIO::just(3); 202 | { 203 | assert_eq!(3, (monadio_simple.effect.lock().unwrap())()); 204 | } 205 | let monadio_simple_map = monadio_simple.map(|x| x * 3); 206 | 207 | monadio_simple_map.subscribe_fn(move |x| { 208 | println!("monadio_simple_map {:?}", x); 209 | assert_eq!(9, *Arc::make_mut(&mut x.clone())); 210 | }); 211 | 212 | // fmap & map (sync) 213 | let mut _subscription = Arc::new(SubscriptionFunc::new(move |x: Arc| { 214 | println!("monadio_sync {:?}", x); // monadio_sync 36 215 | assert_eq!(36, *Arc::make_mut(&mut x.clone())); 216 | })); 217 | let subscription = _subscription.clone(); 218 | let monadio_sync = MonadIO::just(1) 219 | .fmap(|x| MonadIO::new(move || x * 4)) 220 | .map(|x| x * 3) 221 | .map(|x| x * 3); 222 | monadio_sync.subscribe(subscription); 223 | 224 | // fmap & map (async) 225 | let mut _handler_observe_on = HandlerThread::new_with_mutex(); 226 | let mut _handler_subscribe_on = HandlerThread::new_with_mutex(); 227 | let monadio_async = MonadIO::new_with_handlers( 228 | || { 229 | println!("In string"); 230 | String::from("ok") 231 | }, 232 | Some(_handler_observe_on.clone()), 233 | Some(_handler_subscribe_on.clone()), 234 | ); 235 | 236 | let latch = CountDownLatch::new(1); 237 | let latch2 = latch.clone(); 238 | 239 | thread::sleep(time::Duration::from_millis(1)); 240 | 241 | let subscription = Arc::new(SubscriptionFunc::new(move |x: Arc| { 242 | println!("monadio_async {:?}", x); // monadio_async ok 243 | 244 | latch2.countdown(); // Unlock here 245 | })); 246 | monadio_async.subscribe(subscription); 247 | monadio_async.subscribe(Arc::new(SubscriptionFunc::new(move |x: Arc| { 248 | println!("monadio_async sub2 {:?}", x); // monadio_async sub2 ok 249 | }))); 250 | { 251 | let mut handler_observe_on = _handler_observe_on.lock().unwrap(); 252 | let mut handler_subscribe_on = _handler_subscribe_on.lock().unwrap(); 253 | 254 | println!("hh2"); 255 | handler_observe_on.start(); 256 | handler_subscribe_on.start(); 257 | println!("hh2 running"); 258 | 259 | handler_observe_on.post(RawFunc::new(move || {})); 260 | handler_observe_on.post(RawFunc::new(move || {})); 261 | handler_observe_on.post(RawFunc::new(move || {})); 262 | handler_observe_on.post(RawFunc::new(move || {})); 263 | handler_observe_on.post(RawFunc::new(move || {})); 264 | } 265 | thread::sleep(time::Duration::from_millis(1)); 266 | 267 | // Waiting for being unlcoked 268 | latch.clone().wait(); 269 | } 270 | -------------------------------------------------------------------------------- /src/publisher.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | In this module, there're implementations & tests of `Publisher` 3 | */ 4 | use std::marker::PhantomData; 5 | use std::sync::{Arc, Mutex}; 6 | 7 | #[cfg(feature = "for_futures")] 8 | use super::common::LinkedListAsync; 9 | 10 | use super::common::{Observable, RawFunc, Subscription, SubscriptionFunc, UniqueId}; 11 | use super::handler::Handler; 12 | use super::sync::{BlockingQueue, Queue}; 13 | 14 | /** 15 | The `Publisher` implements *PubSub-like* features. 16 | 17 | # Arguments 18 | 19 | * `X` - The generic type of yielded/yielding data 20 | * `T` - In order to pass compilations, `T` must be `SubscriptionFunc` (for instantiation) 21 | 22 | # Remarks 23 | 24 | It could be sync or async up to your usages, 25 | and it could be mapped just as Rx-like APIs. 26 | 27 | */ 28 | #[derive(Clone)] 29 | pub struct Publisher { 30 | // observers: Vec>>, 31 | observers: Vec>>, 32 | 33 | sub_handler: Option>>, 34 | 35 | _x: PhantomData, 36 | } 37 | 38 | impl Default for Publisher { 39 | fn default() -> Self { 40 | Publisher { 41 | observers: vec![], 42 | sub_handler: None, 43 | _x: PhantomData, 44 | } 45 | } 46 | } 47 | 48 | impl Publisher { 49 | pub fn new() -> Publisher { 50 | Default::default() 51 | } 52 | pub fn new_with_handlers(h: Option>>) -> Publisher { 53 | let mut new_one = Publisher::new(); 54 | new_one.subscribe_on(h); 55 | new_one 56 | } 57 | 58 | pub fn subscribe_on(&mut self, h: Option>>) { 59 | self.sub_handler = h; 60 | } 61 | } 62 | impl Publisher 63 | where 64 | X: Send + Sync + 'static, 65 | { 66 | pub fn publish(&mut self, val: X) { 67 | self.notify_observers(Arc::new(val)); 68 | } 69 | 70 | pub fn subscribe(&mut self, s: Arc>) -> Arc> { 71 | self.add_observer(s.clone()); 72 | s 73 | } 74 | pub fn subscribe_fn( 75 | &mut self, 76 | func: impl FnMut(Arc) + Send + Sync + 'static, 77 | ) -> Arc> { 78 | self.subscribe(Arc::new(SubscriptionFunc::new(func))) 79 | } 80 | pub fn map( 81 | &mut self, 82 | func: impl FnMut(Arc) -> Z + Send + Sync + 'static, 83 | ) -> Arc> { 84 | let _func = Arc::new(Mutex::new(func)); 85 | self.subscribe_fn(move |x: Arc| { 86 | (_func.lock().unwrap())(x); 87 | }) 88 | } 89 | pub fn unsubscribe(&mut self, s: Arc>) { 90 | self.delete_observer(s); 91 | } 92 | 93 | pub fn subscribe_blocking_queue( 94 | &mut self, 95 | queue: &BlockingQueue>, 96 | ) -> Arc> { 97 | let mut queue_new = queue.clone(); 98 | self.subscribe_fn(move |v| queue_new.put(v)) 99 | } 100 | pub fn as_blocking_queue(&mut self) -> (Arc>, BlockingQueue>) { 101 | let queue = BlockingQueue::new(); 102 | let subscription = self.subscribe_blocking_queue(&queue); 103 | 104 | (subscription, queue) 105 | } 106 | } 107 | 108 | #[cfg(feature = "for_futures")] 109 | impl Publisher { 110 | pub fn subscribe_as_stream(&mut self, s: Arc>) -> LinkedListAsync> { 111 | self.subscribe(s).as_ref().clone().as_stream() 112 | } 113 | pub fn subscribe_fn_as_stream( 114 | &mut self, 115 | func: impl FnMut(Arc) + Send + Sync + 'static, 116 | ) -> LinkedListAsync> { 117 | self.subscribe_fn(func).as_ref().clone().as_stream() 118 | } 119 | pub fn as_stream(&mut self) -> LinkedListAsync> { 120 | self.subscribe_fn_as_stream(|_| {}) 121 | } 122 | } 123 | impl Observable> for Publisher { 124 | fn add_observer(&mut self, observer: Arc>) { 125 | // println!("add_observer({});", observer); 126 | self.observers.push(observer); 127 | } 128 | fn delete_observer(&mut self, observer: Arc>) { 129 | let id; 130 | { 131 | id = observer.get_id(); 132 | 133 | #[cfg(feature = "for_futures")] 134 | observer.as_ref().clone().close_stream(); 135 | } 136 | 137 | for (index, obs) in self.observers.iter().enumerate() { 138 | if obs.get_id() == id { 139 | // println!("delete_observer({});", observer); 140 | self.observers.remove(index); 141 | return; 142 | } 143 | } 144 | } 145 | fn notify_observers(&mut self, val: Arc) { 146 | let observers = self.observers.clone(); 147 | let mut _do_sub = Arc::new(move || { 148 | for (_, observer) in observers.iter().enumerate() { 149 | { 150 | observer.on_next(val.clone()); 151 | } 152 | } 153 | }); 154 | 155 | match &mut self.sub_handler { 156 | Some(ref mut sub_handler) => { 157 | sub_handler.lock().unwrap().post(RawFunc::new(move || { 158 | let sub = Arc::make_mut(&mut _do_sub); 159 | 160 | (sub)(); 161 | })); 162 | } 163 | None => { 164 | let sub = Arc::make_mut(&mut _do_sub); 165 | (sub)(); 166 | } 167 | }; 168 | } 169 | } 170 | 171 | #[cfg(feature = "for_futures")] 172 | #[futures_test::test] 173 | async fn test_publisher_stream() { 174 | use std::sync::Arc; 175 | 176 | use futures::StreamExt; 177 | 178 | use super::common::SubscriptionFunc; 179 | use super::handler::HandlerThread; 180 | 181 | // use super::sync::CountDownLatch; 182 | 183 | let mut _h = HandlerThread::new_with_mutex(); 184 | let mut pub1 = Publisher::new_with_handlers(Some(_h.clone())); 185 | //* 186 | let s = pub1.subscribe_as_stream(Arc::new(SubscriptionFunc::new(move |x| { 187 | println!("test_publisher_stream {:?}: {:?}", "SS", x); 188 | }))); 189 | // */ 190 | { 191 | let h = &mut _h.lock().unwrap(); 192 | 193 | println!("test_publisher_stream hh2"); 194 | h.start(); 195 | println!("test_publisher_stream hh2 running"); 196 | } 197 | pub1.publish(1); 198 | pub1.publish(2); 199 | pub1.publish(3); 200 | pub1.publish(4); 201 | let mut got_list = Vec::>::new(); 202 | { 203 | let mut result = s.clone(); 204 | for n in 1..5 { 205 | println!("test_publisher_stream {:?}: {:?}", n, "Before"); 206 | let item = result.next().await; 207 | if let Some(result) = item.clone() { 208 | (&mut got_list).push(result.clone()); 209 | } 210 | println!("test_publisher_stream {:?}: {:?}", n, item); 211 | } 212 | // got_list = s.collect::>().await; 213 | } 214 | assert_eq!( 215 | vec![Arc::new(1), Arc::new(2), Arc::new(3), Arc::new(4),], 216 | got_list 217 | ); 218 | pub1.publish(5); 219 | pub1.publish(6); 220 | pub1.publish(7); 221 | pub1.publish(8); 222 | let s2 = pub1.as_stream(); 223 | { 224 | let h = &mut _h.lock().unwrap(); 225 | 226 | let mut s = s.clone(); 227 | h.post(RawFunc::new(move || { 228 | s.close_stream(); 229 | })); 230 | } 231 | pub1.publish(9); 232 | pub1.publish(10); 233 | pub1.publish(11); 234 | pub1.publish(12); 235 | { 236 | let h = &mut _h.lock().unwrap(); 237 | 238 | let mut s2 = s2.clone(); 239 | h.post(RawFunc::new(move || { 240 | s2.close_stream(); 241 | })); 242 | } 243 | 244 | std::thread::sleep(std::time::Duration::from_millis(1)); 245 | 246 | got_list = s.clone().collect::>().await; 247 | assert_eq!( 248 | vec![Arc::new(5), Arc::new(6), Arc::new(7), Arc::new(8),], 249 | got_list 250 | ); 251 | got_list = s2.clone().collect::>().await; 252 | assert_eq!( 253 | vec![Arc::new(9), Arc::new(10), Arc::new(11), Arc::new(12),], 254 | got_list 255 | ); 256 | } 257 | 258 | #[test] 259 | fn test_publisher_new() { 260 | use std::sync::Arc; 261 | 262 | use super::common::SubscriptionFunc; 263 | use super::handler::HandlerThread; 264 | 265 | use super::sync::CountDownLatch; 266 | 267 | let mut pub1 = Publisher::new(); 268 | pub1.subscribe_fn(|x: Arc| { 269 | println!("pub1 {:?}", x); 270 | assert_eq!(9, *Arc::make_mut(&mut x.clone())); 271 | }); 272 | pub1.publish(9); 273 | 274 | let mut _h = HandlerThread::new_with_mutex(); 275 | 276 | let mut pub2 = Publisher::new_with_handlers(Some(_h.clone())); 277 | 278 | let latch = CountDownLatch::new(1); 279 | let latch2 = latch.clone(); 280 | 281 | let s = Arc::new(SubscriptionFunc::new(move |x: Arc| { 282 | println!("pub2-s1 I got {:?}", x); 283 | 284 | assert_eq!(true, x != Arc::new(String::from("OKOK3"))); 285 | 286 | latch2.countdown(); 287 | })); 288 | pub2.subscribe(s.clone()); 289 | pub2.map(move |x: Arc| { 290 | println!("pub2-s2 I got {:?}", x); 291 | }); 292 | 293 | { 294 | let h = &mut _h.lock().unwrap(); 295 | 296 | println!("hh2"); 297 | h.start(); 298 | println!("hh2 running"); 299 | 300 | h.post(RawFunc::new(move || {})); 301 | h.post(RawFunc::new(move || {})); 302 | h.post(RawFunc::new(move || {})); 303 | h.post(RawFunc::new(move || {})); 304 | h.post(RawFunc::new(move || {})); 305 | } 306 | 307 | pub2.publish(String::from("OKOK")); 308 | pub2.publish(String::from("OKOK2")); 309 | 310 | pub2.unsubscribe(s.clone()); 311 | 312 | pub2.publish(String::from("OKOK3")); 313 | 314 | latch.clone().wait(); 315 | } 316 | -------------------------------------------------------------------------------- /src/sync.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | In this module there're implementations & tests 3 | of general async handling features. 4 | */ 5 | 6 | use std::error::Error; 7 | use std::sync::{ 8 | atomic::{AtomicBool, Ordering}, 9 | mpsc, 10 | mpsc::RecvTimeoutError, 11 | Arc, Condvar, Mutex, 12 | }; 13 | use std::time::Duration; 14 | 15 | #[cfg(feature = "for_futures")] 16 | use super::common::shared_thread_pool; 17 | #[cfg(feature = "for_futures")] 18 | use crate::futures::task::SpawnExt; 19 | #[cfg(feature = "for_futures")] 20 | use std::future::Future; 21 | #[cfg(feature = "for_futures")] 22 | use std::pin::Pin; 23 | #[cfg(feature = "for_futures")] 24 | use std::task::{Context, Poll, Waker}; 25 | 26 | use super::common::{Observable, RawFunc, SubscriptionFunc}; 27 | 28 | #[cfg(feature = "handler")] 29 | use super::handler::{Handler, HandlerThread}; 30 | #[cfg(feature = "publisher")] 31 | use super::publisher::Publisher; 32 | 33 | /** 34 | `Will` `trait` defines the interface which could do actions in its `Handler`. 35 | 36 | # Remarks 37 | 38 | This is highly inspired by `Java Future` concepts. 39 | 40 | */ 41 | pub trait Will: Send + Sync + 'static { 42 | /** 43 | Did this `Will` start? 44 | Return `true` when it did started (no matter it has stopped or not) 45 | 46 | */ 47 | fn is_started(&mut self) -> bool; 48 | 49 | /** 50 | Is this `Will` alive? 51 | Return `true` when it has started and not stopped yet. 52 | */ 53 | fn is_alive(&mut self) -> bool; 54 | 55 | /** 56 | Start `Will`. 57 | */ 58 | fn start(&mut self); 59 | 60 | /** 61 | Stop `Will`. 62 | */ 63 | fn stop(&mut self); 64 | 65 | /** 66 | Add a callback called when it has completed. 67 | 68 | # Arguments 69 | 70 | * `subscription` - The callback. 71 | `` 72 | */ 73 | fn add_callback(&mut self, subscription: Arc>); 74 | 75 | /** 76 | Remove a callback called when it has completed. 77 | 78 | # Arguments 79 | 80 | * `subscription` - The callback. 81 | `` 82 | */ 83 | fn remove_callback(&mut self, subscription: Arc>); 84 | 85 | /** 86 | Get the result. 87 | */ 88 | fn result(&mut self) -> Option; 89 | } 90 | 91 | #[cfg(all(feature = "publisher", feature = "handler"))] 92 | #[derive(Clone)] 93 | pub struct WillAsync { 94 | effect: Arc T + Send + Sync + 'static>>, 95 | handler: Arc>, 96 | publisher: Arc>>, 97 | started_alive: Arc>, 98 | result: Arc>>, 99 | 100 | #[cfg(feature = "for_futures")] 101 | waker: Arc>>, 102 | } 103 | 104 | #[cfg(all(feature = "publisher", feature = "handler"))] 105 | impl WillAsync { 106 | pub fn new(effect: impl FnMut() -> T + Send + Sync + 'static) -> WillAsync { 107 | Self::new_with_handler(effect, HandlerThread::new_with_mutex()) 108 | } 109 | pub fn new_with_handler( 110 | effect: impl FnMut() -> T + Send + Sync + 'static, 111 | handler: Arc>, 112 | ) -> WillAsync { 113 | WillAsync { 114 | handler, 115 | effect: Arc::new(Mutex::new(effect)), 116 | started_alive: Arc::new(Mutex::new((AtomicBool::new(false), AtomicBool::new(false)))), 117 | publisher: Arc::new(Mutex::new(Publisher::default())), 118 | result: Arc::new(Mutex::new(None)), 119 | 120 | #[cfg(feature = "for_futures")] 121 | waker: Arc::new(Mutex::new(None)), 122 | } 123 | } 124 | } 125 | 126 | #[cfg(all(feature = "publisher", feature = "handler"))] 127 | impl Will for WillAsync 128 | where 129 | T: Clone + Send + Sync + 'static, 130 | { 131 | fn is_started(&mut self) -> bool { 132 | let started_alive = self.started_alive.lock().unwrap(); 133 | let &(ref started, _) = &*started_alive; 134 | started.load(Ordering::SeqCst) 135 | } 136 | 137 | fn is_alive(&mut self) -> bool { 138 | let started_alive = self.started_alive.lock().unwrap(); 139 | let &(_, ref alive) = &*started_alive; 140 | alive.load(Ordering::SeqCst) 141 | } 142 | 143 | fn start(&mut self) { 144 | let started_alive = self.started_alive.lock().unwrap(); 145 | let &(ref started, ref alive) = &*started_alive; 146 | if started.load(Ordering::SeqCst) { 147 | return; 148 | } 149 | started.store(true, Ordering::SeqCst); 150 | if alive.load(Ordering::SeqCst) { 151 | return; 152 | } 153 | alive.store(true, Ordering::SeqCst); 154 | 155 | let mut this = self.clone(); 156 | let _effect = self.effect.clone(); 157 | let _publisher = self.publisher.clone(); 158 | 159 | let mut handler = self.handler.lock().unwrap(); 160 | handler.start(); 161 | handler.post(RawFunc::new(move || { 162 | let result = { (_effect.lock().unwrap())() }; 163 | { 164 | (*this.result.lock().unwrap()) = Some(result.clone()); 165 | } 166 | { 167 | _publisher.lock().unwrap().publish(result); 168 | } 169 | this.stop(); 170 | })); 171 | } 172 | 173 | fn stop(&mut self) { 174 | let started_alive = self.started_alive.lock().unwrap(); 175 | let &(ref started, ref alive) = &*started_alive; 176 | if !started.load(Ordering::SeqCst) { 177 | return; 178 | } 179 | if !alive.load(Ordering::SeqCst) { 180 | return; 181 | } 182 | alive.store(false, Ordering::SeqCst); 183 | 184 | #[cfg(feature = "for_futures")] 185 | { 186 | if let Some(waker) = self.waker.lock().unwrap().take() { 187 | waker.wake() 188 | } 189 | } 190 | } 191 | 192 | fn add_callback(&mut self, subscription: Arc>) { 193 | self.publisher.lock().unwrap().subscribe(subscription); 194 | } 195 | 196 | fn remove_callback(&mut self, subscription: Arc>) { 197 | self.publisher.lock().unwrap().delete_observer(subscription); 198 | } 199 | 200 | fn result(&mut self) -> Option { 201 | self.result.lock().unwrap().clone() 202 | } 203 | } 204 | 205 | #[cfg(all(feature = "for_futures", feature = "publisher", feature = "handler"))] 206 | impl Future for WillAsync 207 | where 208 | T: Clone + Send + Sync + 'static, 209 | { 210 | type Output = Option; 211 | 212 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 213 | let started_alive = self.started_alive.lock().unwrap(); 214 | let &(ref started, ref alive) = &*started_alive; 215 | 216 | if started.load(Ordering::SeqCst) && (!alive.load(Ordering::SeqCst)) { 217 | Poll::Ready(self.clone().result()) 218 | } else { 219 | { 220 | self.waker.lock().unwrap().replace(cx.waker().clone()); 221 | } 222 | Poll::Pending 223 | } 224 | } 225 | } 226 | 227 | /** 228 | `CountDownLatch` implements a latch with a value(> 0), 229 | waiting for the value counted down until <= 0 230 | (the countdown action would be in other threads). 231 | 232 | # Remarks 233 | 234 | It's inspired by `CountDownLatch` in `Java` 235 | , and easily use it on async scenaios. 236 | 237 | `` 238 | */ 239 | #[derive(Debug, Clone)] 240 | pub struct CountDownLatch { 241 | pair: Arc<(Arc>, Condvar)>, 242 | 243 | #[cfg(feature = "for_futures")] 244 | waker: Arc>>, 245 | } 246 | 247 | impl CountDownLatch { 248 | pub fn new(count: u64) -> CountDownLatch { 249 | CountDownLatch { 250 | pair: Arc::new((Arc::new(Mutex::new(count)), Condvar::new())), 251 | 252 | #[cfg(feature = "for_futures")] 253 | waker: Arc::new(Mutex::new(None)), 254 | } 255 | } 256 | 257 | pub fn countdown(&self) { 258 | { 259 | let &(ref lock, ref cvar) = &*self.pair.clone(); 260 | let mut started = lock.lock().unwrap(); 261 | if *started > 0 { 262 | *started -= 1; 263 | } 264 | cvar.notify_one(); 265 | 266 | #[cfg(feature = "for_futures")] 267 | { 268 | let mut waker = self.waker.lock().unwrap(); 269 | if let Some(waker) = waker.take() { 270 | waker.wake() 271 | } 272 | } 273 | } 274 | } 275 | 276 | pub fn wait(&self) { 277 | let &(ref lock, ref cvar) = &*self.pair; 278 | 279 | /* 280 | let mut result = lock.lock(); 281 | let mut started; 282 | if result.is_err() { 283 | started = result.err().unwrap().into_inner(); 284 | } else { 285 | started = result.unwrap(); 286 | } 287 | */ 288 | let mut started = lock.lock().unwrap(); 289 | 290 | while *started > 0 { 291 | let result = cvar.wait(started); 292 | 293 | if result.is_err() { 294 | started = result.err().unwrap().into_inner(); 295 | } else { 296 | started = result.unwrap(); 297 | } 298 | } 299 | } 300 | } 301 | 302 | #[cfg(feature = "for_futures")] 303 | impl Future for CountDownLatch { 304 | type Output = (); 305 | 306 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 307 | let &(ref remaining, _) = &*self.pair; 308 | let count = remaining.lock().unwrap(); 309 | if *count > 0 { 310 | { 311 | self.waker.lock().unwrap().replace(cx.waker().clone()); 312 | } 313 | Poll::Pending 314 | } else { 315 | Poll::Ready(()) 316 | } 317 | } 318 | } 319 | 320 | /** 321 | `Queue` `trait` defined the interface which perform basic `Queue` actions. 322 | 323 | # Arguments 324 | 325 | * `T` - The generic type of data 326 | 327 | # Remarks 328 | 329 | It's inspired by `Queue` in `Java`. 330 | 331 | `` 332 | */ 333 | pub trait Queue { 334 | fn offer(&mut self, v: T); 335 | fn poll(&mut self) -> Option; 336 | fn put(&mut self, v: T); 337 | fn take(&mut self) -> Option; 338 | } 339 | 340 | /** 341 | `BlockingQueue` implements `Queue` `trait` and provides `BlockingQueue` features. 342 | 343 | # Arguments 344 | 345 | * `T` - The generic type of data 346 | 347 | # Remarks 348 | 349 | It's inspired by `BlockingQueue` in `Java`, 350 | , and easily use it on async scenaios. 351 | 352 | `` 353 | */ 354 | #[derive(Debug, Clone)] 355 | pub struct BlockingQueue { 356 | pub timeout: Option, 357 | pub panic: bool, 358 | alive: Arc>, 359 | blocking_sender: Arc>>, 360 | blocking_recever: Arc>>, 361 | } 362 | 363 | // impl Copy for BlockingQueue { 364 | // fn clone(&self) -> BlockingQueue { 365 | // *self 366 | // } 367 | // } 368 | 369 | impl Default for BlockingQueue { 370 | fn default() -> Self { 371 | let (blocking_sender, blocking_recever) = mpsc::channel(); 372 | 373 | BlockingQueue { 374 | alive: Arc::new(Mutex::new(AtomicBool::new(true))), 375 | timeout: None, 376 | panic: false, 377 | blocking_sender: Arc::new(Mutex::new(blocking_sender)), 378 | blocking_recever: Arc::new(Mutex::new(blocking_recever)), 379 | } 380 | } 381 | } 382 | 383 | impl BlockingQueue { 384 | pub fn new() -> BlockingQueue { 385 | Default::default() 386 | } 387 | 388 | pub fn is_alive(&self) -> bool { 389 | let alive = &self.alive.lock().unwrap(); 390 | alive.load(Ordering::SeqCst) 391 | } 392 | 393 | pub fn stop(&mut self) { 394 | { 395 | let alive = &self.alive.lock().unwrap(); 396 | if !alive.load(Ordering::SeqCst) { 397 | return; 398 | } 399 | alive.store(false, Ordering::SeqCst); 400 | 401 | let sender = self.blocking_sender.lock().unwrap(); 402 | drop(sender); 403 | } 404 | } 405 | } 406 | 407 | impl Queue for BlockingQueue 408 | where 409 | T: 'static + Send, 410 | { 411 | fn offer(&mut self, v: T) { 412 | { 413 | let alive = &self.alive.lock().unwrap(); 414 | if !alive.load(Ordering::SeqCst) { 415 | return; 416 | } 417 | 418 | let result = self.blocking_sender.lock().unwrap().send(v); 419 | if self.panic && result.is_err() { 420 | std::panic::panic_any(result.err()); 421 | } 422 | } 423 | } 424 | 425 | fn poll(&mut self) -> Option { 426 | let result = self.poll_result(); 427 | 428 | if self.panic && result.is_err() { 429 | std::panic::panic_any(result.err()); 430 | // return None; 431 | } 432 | 433 | match result { 434 | Ok(v) => Some(v), 435 | Err(_) => None, 436 | } 437 | } 438 | 439 | fn put(&mut self, v: T) { 440 | // NOTE Currently there's no maximum size of BlockingQueue. 441 | 442 | self.offer(v); 443 | } 444 | 445 | fn take(&mut self) -> Option { 446 | let result = self.take_result(); 447 | 448 | if self.panic && result.is_err() { 449 | std::panic::panic_any(result.err()); 450 | // return None; 451 | } 452 | 453 | match result { 454 | Ok(v) => Some(v), 455 | Err(_) => None, 456 | } 457 | } 458 | } 459 | 460 | impl BlockingQueue 461 | where 462 | T: Send + 'static, 463 | { 464 | pub fn poll_result(&mut self) -> Result> { 465 | if !self.is_alive() { 466 | return Err(Box::new(RecvTimeoutError::Disconnected)); 467 | } 468 | 469 | { 470 | let result = { self.blocking_recever.lock().unwrap().try_recv() }; 471 | 472 | match result { 473 | Ok(v) => Ok(v), 474 | Err(e) => Err(Box::new(e)), 475 | } 476 | } 477 | } 478 | 479 | pub fn take_result(&mut self) -> Result> { 480 | if !self.is_alive() { 481 | return Err(Box::new(RecvTimeoutError::Disconnected)); 482 | } 483 | 484 | { 485 | match self.timeout { 486 | Some(duration) => { 487 | let result = { self.blocking_recever.lock().unwrap().recv_timeout(duration) }; 488 | 489 | match result { 490 | Ok(v) => Ok(v), 491 | Err(e) => Err(Box::new(e)), 492 | } 493 | } 494 | None => { 495 | let result = { self.blocking_recever.lock().unwrap().recv() }; 496 | 497 | match result { 498 | Ok(v) => Ok(v), 499 | Err(e) => Err(Box::new(e)), 500 | } 501 | } 502 | } 503 | } 504 | } 505 | } 506 | #[cfg(feature = "for_futures")] 507 | impl BlockingQueue 508 | where 509 | T: Send + 'static + Clone, 510 | { 511 | pub async fn poll_result_as_future(&mut self) -> Result> { 512 | let mut queue = self.clone(); 513 | 514 | let spawn_future_result = { 515 | shared_thread_pool() 516 | .inner 517 | .lock() 518 | .unwrap() 519 | .spawn_with_handle(async move { queue.poll_result() }) 520 | }; 521 | match spawn_future_result { 522 | Ok(future) => future.await, 523 | Err(e) => Err(Box::new(e)), 524 | } 525 | } 526 | pub async fn take_result_as_future(&mut self) -> Result> { 527 | let mut queue = self.clone(); 528 | 529 | let spawn_future_result = { 530 | shared_thread_pool() 531 | .inner 532 | .lock() 533 | .unwrap() 534 | .spawn_with_handle(async move { queue.take_result() }) 535 | }; 536 | match spawn_future_result { 537 | Ok(future) => future.await, 538 | Err(e) => Err(Box::new(e)), 539 | } 540 | } 541 | } 542 | 543 | #[cfg(feature = "for_futures")] 544 | #[futures_test::test] 545 | async fn test_sync_future() { 546 | let mut wa = WillAsync::new(move || 1); 547 | wa.start(); 548 | 549 | assert_eq!(Some(1), wa.await); 550 | 551 | let mut _h = HandlerThread::new_with_mutex(); 552 | let mut pub1 = Publisher::new_with_handlers(Some(_h.clone())); 553 | 554 | let latch = CountDownLatch::new(4); 555 | let latch2 = latch.clone(); 556 | 557 | let _ = pub1.subscribe(Arc::new(SubscriptionFunc::new(move |y| { 558 | println!("test_sync_future {:?}", y); 559 | latch2.countdown(); 560 | }))); 561 | 562 | println!("test_sync_future before Publisher.start()"); 563 | 564 | { 565 | let h = &mut _h.lock().unwrap(); 566 | 567 | println!("test_sync_future hh2"); 568 | h.start(); 569 | println!("test_sync_future hh2 running"); 570 | } 571 | std::thread::sleep(Duration::from_millis(1)); 572 | 573 | pub1.publish(1); 574 | println!("test_sync_future pub1.publish"); 575 | pub1.publish(2); 576 | println!("test_sync_future pub1.publish"); 577 | pub1.publish(3); 578 | println!("test_sync_future pub1.publish"); 579 | pub1.publish(4); 580 | println!("test_sync_future pub1.publish"); 581 | 582 | let _ = latch.await; 583 | println!("test_sync_future done"); 584 | } 585 | 586 | #[test] 587 | fn test_will_sync_new() { 588 | use std::thread; 589 | use std::time; 590 | 591 | let latch = CountDownLatch::new(1); 592 | let latch2 = latch.clone(); 593 | let mut h = WillAsync::new(move || 1); 594 | assert_eq!(false, h.is_alive()); 595 | assert_eq!(false, h.is_started()); 596 | h.stop(); 597 | h.stop(); 598 | assert_eq!(false, h.is_alive()); 599 | assert_eq!(false, h.is_started()); 600 | h.add_callback(Arc::new(SubscriptionFunc::new(move |_v: Arc| { 601 | assert_eq!(1, *Arc::make_mut(&mut _v.clone())); 602 | latch2.countdown(); 603 | }))); 604 | h.start(); 605 | latch.clone().wait(); 606 | thread::sleep(time::Duration::from_millis(1)); 607 | assert_eq!(false, h.is_alive()); 608 | assert_eq!(true, h.is_started()); 609 | assert_eq!(1, h.result().unwrap()); 610 | } 611 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | # RUST_BACKTRACE=full cargo test -- --color always --nocapture 2 | cargo test --features="test_runtime" -- --color always --nocapture 3 | --------------------------------------------------------------------------------