taskorch 0.1.0

Concurrent Pool for task processing
Documentation
# Task Orch


## System Composition

The entire concurrency library can generally be divided into four main components:

- **Task** — The minimal unit of execution, built from a fn or closure along with runtime metadata.
- **Queue** — The queue holds tasks that are waiting to be processed. It acts as a buffer where tasks are stored until they can be executed.
- **Threads** — Threads are responsible for executing the tasks retrieved from the queue.
- **Resource Pool** — Responsible for the lifecycle management of both the Queue and the Threads, establishing a mapping between names and instances.


## Task

### Task Modes

Tasks can be executed in **two distinct modes**:
- **Independent**: Runs freely without constraint.
- **Conditional**: Executes only when all conditions are satisfied.

### Task Flow

1. **Activation**:  
   A task is scheduled once all its required conditions are fulfilled.
2. **Execution**:  
   The task runs and computes its return value.
3. **Data Passing**:  
   If a `target anchor` is configured, the return value will be passed on to another task.

**Key Notes**:  
- **Conditions** correspond to the function’s parameters (0-indexed).

### Task ID Assignment

- **Explicit ID**: You can provide your own ID using a generator or by calling `taskid_next()`.
- **Auto-generated**: If you omit specifying an ID, the system will automatically assign one.

### Building a Task (3-Step Process)

1. **Prepare**:  Define a function or closure.
2. **Create**:  Create the task chained by `.task()`.
3. **Notify (Optional)**:  Chain tasks by calling `to()` to set a `target anchor`.  
   *This step can be skipped if the task does not produce any output.*

### Task Creation Code


#### Note

NO `parameter`, NO `taskid` needed.  
NO `return`, NO `target anchor` required.  

**Case 1**:  [ **No** parameter, **No** return ]  
```rust
# use taskorch::TaskBuildNew as _;
let task = 
    (||{})          // <1> Define the body
        .task();    // <2> Create a task from the given closure.
                    // <3> `to()` skipped, as there is no return value
```

**Case 2**:  [ **No** parameter, **With** return ]  
```rust
# use taskorch::{TaskBuildNew as _, TaskBuildOp as _};
let task = 
    (||{3})         // <1> Define the body
        .task()     // <2> Create a task from the given closure.
        .to(2,0);   // <3> Set target;
                    //     the return value will be forwarded to task #2, condition #0.

let task = 
    (||{3})         // <1> ..
        .task();    // <2> ..
                    // <3> `to()` skipped, the return value dropped
```

**Case 3**:  [ **With** parameter, **No** return ]  
```rust
# use taskorch::TaskBuildNew as _;

let task = 
    (|_:i8|{})      // <1> Define the body, taskid is auto-generated.
        .task();    // <2> Create a task from the given closure.
                    // <3> `to()` skipped, as there is no return value
let task = 
    (|_:i8|{}, 1)   // <1> Define the body, with an explicit taskid.
        .task();    // <2> ..
                    // <3> ..
```

**Case 4**:  [ **With** parameter, **With** return ]  
```rust
# use taskorch::{TaskBuildNew as _, TaskBuildOp as _};

let task = 
    (|_:i8|{3})     // <1> Define the body, taskid is auto-generated.
        .task();    // <2> Create a task from the given closure.
                    // <3> `to()` skipped, the return value dropped
let task = 
    (|_:i8|{3}, 1)  // <1> Define the body, with an explicit taskid.
        .task();    // <2> ..
                    // <3> ..

let task = 
    (|_:i8|{3})     // <1> Define the body, taskid is auto-generated.
        .task()     // <2> Create a task from the given closure.
        .to(2,0);   // <3> Set target;
                    //     the return value will be forwarded to task #2 and cond #0

let task = 
    (|_:i8|{3}, 1) // <1> Define the body, with an explicit taskid.
        .task()    // <2> ..
        .to(2,0);  // <3> ..
```
**Exit task creation**  
The only difference here is the use of `.exit_task()` instead of `.task()`.

## Note

As this is the initial development release (v0.1.0), the API is **highly unstable** and **will change** in subsequent versions.

## Example

```rust
use taskorch::{Pool, Queue, TaskBuildNew, TaskBuildOp};

fn main() {
    println!("----- test task orch -----");

    // Step#1. create a Pool
    let mut pool = Pool::new();

    // Step#2. create a queue
    let qid = pool.insert_queue(&Queue::new()).unwrap();
    let submitter = pool.task_submitter(qid).unwrap();

    // Step#3. create tasks

    // an indepent task
    submitter.submit((||println!("task free say hello")).task());

    // an exit task with ONE str cond
    let id_exit = submitter.submit(
        (
            |msg:&str|println!("exit task, recved ({msg:?}) and EXIT"),
            1
        ).exit_task()
    );
    assert_eq!(id_exit,1);

    // normal task pass message to exit task
    submitter.submit(
        (move||{
            let id_exit = &id_exit;
            println!("normal pass [\"msg:exit\"] to: task#{id_exit}");
            "msg:exit"
        }).task().to(id_exit, 0)
    );

    // Step#4. start a thread and run
    pool.spawn_thread_for(qid);

    // Step#5. wait until all finished
    pool.join();
}
```
For a more complex demo, see the `usage` example.