Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add extended documentation for all reactive operators #71

Merged
merged 9 commits into from
Dec 28, 2022
5 changes: 5 additions & 0 deletions apidoc/Bonsai_Reactive_CurrentThreadScheduler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
uid: Bonsai.Reactive.CurrentThreadScheduler
---

[!include[CurrentThreadScheduler](~/articles/reactive-currentthreadscheduler.md)]
5 changes: 5 additions & 0 deletions apidoc/Bonsai_Reactive_DefaultScheduler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
uid: Bonsai.Reactive.DefaultScheduler
---

[!include[DefaultScheduler](~/articles/reactive-defaultscheduler.md)]
5 changes: 5 additions & 0 deletions apidoc/Bonsai_Reactive_EventLoopScheduler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
uid: Bonsai.Reactive.EventLoopScheduler
---

[!include[EventLoopScheduler](~/articles/reactive-eventloopscheduler.md)]
5 changes: 5 additions & 0 deletions apidoc/Bonsai_Reactive_ImmediateScheduler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
uid: Bonsai.Reactive.ImmediateScheduler
---

[!include[ImmediateScheduler](~/articles/reactive-immediatescheduler.md)]
5 changes: 5 additions & 0 deletions apidoc/Bonsai_Reactive_NewThreadScheduler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
uid: Bonsai.Reactive.NewThreadScheduler
---

[!include[NewThreadScheduler](~/articles/reactive-newthreadscheduler.md)]
5 changes: 5 additions & 0 deletions apidoc/Bonsai_Reactive_TaskPoolScheduler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
uid: Bonsai.Reactive.TaskPoolScheduler
---

[!include[TaskPoolScheduler](~/articles/reactive-taskpoolscheduler.md)]
5 changes: 5 additions & 0 deletions apidoc/Bonsai_Reactive_ThreadPoolScheduler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
uid: Bonsai.Reactive.ThreadPoolScheduler
---

[!include[ThreadPoolScheduler](~/articles/reactive-threadpoolscheduler.md)]
2 changes: 1 addition & 1 deletion articles/reactive-accumulate.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ title: Accumulate

![Marble diagram](~/images/reactive-accumulate.svg)

The `Accumulate` operator returns the current value of the cumulative sum every time the source sequence emits a new value. The result sequence terminates successfully when the source sequence terminates successfully.
The `Accumulate` operator returns the current value of the cumulative sum each time the source sequence emits a notification. The result sequence terminates successfully when the source sequence terminates successfully.
2 changes: 2 additions & 0 deletions articles/reactive-amb.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ title: Amb
---

![Marble diagram](~/images/reactive-amb.svg)

The `Amb` operator sets up a winner-take-all race condition between all source sequences. The first sequence to emit a notification will gain full control of the output, and all the other sequences will have their subscriptions immediatelly cancelled. `Amb` is most commonly used to ensure only one of many outcomes being evaluated in parallel is propagated.
2 changes: 1 addition & 1 deletion articles/reactive-average.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ title: Average

![Marble diagram](~/images/reactive-average.svg)

The `Average` operator collects all the numbers from the source sequence and emits a single value representing the arithmetic mean. The single result value is emitted only when the source sequence terminates successfully.
The `Average` operator collects all the values from the source sequence and emits a single floating-point number representing their arithmetic mean. The single result value is emitted only when the source sequence terminates successfully.
4 changes: 4 additions & 0 deletions articles/reactive-buffercount.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ title: Buffer
---

![Marble diagram](~/images/reactive-buffercount.svg)

`BufferCount` groups the notifications of the source sequence into chunks containing the number of elements specified in the <xref href="Bonsai.Reactive.BufferCount.Count"/> property. The overlap between the elements in each chunk can be controlled using the <xref href="Bonsai.Reactive.BufferCount.Skip"/> property.

If no skip value is provided, the chunks will be strictly non-overlapping, with a new chunk beginning when the previous chunk ends. If the skip value is less than the specified number of elements, chunks will be overlapping, with a new buffer created every `Skip` notifications. Finally, if the skip value is greater than the specified number of elements, there will be a gap between each chunk where elements from the source sequence will be dropped.
4 changes: 4 additions & 0 deletions articles/reactive-buffertime.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ title: BufferTime
---

![Marble diagram](~/images/reactive-buffertime.svg)

The `BufferTime` operator groups the notifications of the source sequence into chunks, where each chunk contains the elements emitted during the specified <xref href="Bonsai.Reactive.BufferTime.TimeSpan"/>. The overlap between the elements in each chunk can be controlled using the <xref href="Bonsai.Reactive.BufferTime.TimeShift"/> property.

If no `TimeShift` is provided, the chunks will be strictly non-overlapping, with a new chunk beginning when the previous chunk ends. If `TimeShift` is smaller than `TimeSpan`, chunks will be overlapping, with a new buffer created every `TimeShift` interval. Finally, if `TimeShift` is larger than `TimeSpan`, there will be a time gap between each chunk where elements from the source sequence may be dropped.
6 changes: 6 additions & 0 deletions articles/reactive-buffertrigger.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,9 @@ title: BufferTrigger
---

![Marble diagram](~/images/reactive-buffertrigger.svg)

`BufferTrigger` groups the notifications of the source sequence into chunks, where the opening of each chunk is triggered by the notifications of the second sequence. The rules for closing each buffer can be specified using the <xref href="Bonsai.Reactive.BufferTrigger.Count"/> and <xref href="Bonsai.Reactive.BufferTrigger.TimeSpan"/> properties.

If neither buffer count nor buffer time span are specified, chunks will be strictly non-overlapping, with the previous chunk being closed when a new chunk is created. In this case, and only this case, the first chunk is also created immediately at the start of the sequence.

If the `Count` property or the `TimeSpan` property is specified, then a new chunk is created when the second sequence emits a notification, and it is automatically closed after either the specified number of elements is collected or the specified time span elapses. If a new chunk is created before the previous chunk is closed, then chunks will overlap, and any elements emitted during this period will be included in both buffers. If at any moment there is no open buffer, elements emitted from the source sequence will be dropped.
4 changes: 4 additions & 0 deletions articles/reactive-combinetimestamp.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ title: CombineTimestamp
---

![Marble diagram](~/images/reactive-combinetimestamp.svg)

`CombineTimestamp` is used primarily to create a sequence of <xref href="System.Reactive.Timestamped`1"/> values for downstream operators, when timestamps have been extracted from other sources.

Alternatively, it can be used to preserve the value of a timestamp during post-processing operations. In this case, even though the timestamped value may be transformed multiple times, we can keep the original acquisition timestamp in a branch and use the <xref href="Bonsai.Reactive.Zip"/> operator followed by `CombineTimestamp` to carry the timestamp value forward.
glopesdev marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 2 additions & 0 deletions articles/reactive-condition.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ title: Condition
---

![Marble diagram](~/images/reactive-condition.svg)

The nested workflow specifying the condition must return a sequence of type <xref href="System.Boolean"/>. This nested sequence may be synchronous or asynchronous with respect to notifications from the source sequence. After each element is emitted by the source sequence, the latest value from the nested sequence is checked. If the value is `true` then the element will be accepted and emitted by the result sequence. Otherwise, the element will be dropped.
glopesdev marked this conversation as resolved.
Show resolved Hide resolved
7 changes: 7 additions & 0 deletions articles/reactive-createobservable.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,10 @@ title: CreateObservable
---

![Marble diagram](~/images/reactive-createobservable.svg)

For each notification in the source sequence, `CreateObservable` constructs a new instance of the asynchronous operation specified in the nested workflow and emits the operation exposed as an observable sequence. However, `CreateObservable` does not itself subscribe to the sequence, which means the logic inside the nested workflow will not run unless the emitted observables are subscribed downstream.

> [!Note]
> You can manipulate and schedule each of the emitted observable sequences downstream using higher-order operators such as [**Merge**](xref:Bonsai.Reactive.Merge), [**Concat**](xref:Bonsai.Reactive.Concat) or [**Switch**](xref:Bonsai.Reactive.Switch).

The input to the nested workflow represents the element passed as an argument to the asynchronous operation. If the input is itself an observable sequence, the [WorkflowInput](xref:Bonsai.Expressions.WorkflowInputBuilder) node will subscribe to all the values in the sequence when the asynchronous operation is finally launched. Otherwise, the input will emit a single value containing the stored argument value.
8 changes: 8 additions & 0 deletions articles/reactive-currentthreadscheduler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
uid: reactive-currentthreadscheduler
title: CurrentThreadScheduler
---

The `CurrentThreadScheduler` operator returns a singleton object that can be used to schedule units of work in the current thread. The action is placed in a queue rather than executing immediately, and will only be called after the current action is complete.

[!include[Schedulers](~/articles/reactive-schedulers.md)]
6 changes: 6 additions & 0 deletions articles/reactive-defaultscheduler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
uid: reactive-defaultscheduler
title: DefaultScheduler
---

[!include[Schedulers](~/articles/reactive-schedulers.md)]
2 changes: 2 additions & 0 deletions articles/reactive-defer.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ title: Defer
---

![Marble diagram](~/images/reactive-defer.svg)

The `Defer` operator uses the nested workflow to specify the constructed sequence. All input sequences to the outer `Defer` node will be routed to the inner [WorkflowInput](xref:Bonsai.Expressions.WorkflowInputBuilder) nodes, and all notifications emitted by the inner [WorkflowOutput](xref:Bonsai.Expressions.WorkflowOutputBuilder) node will be emitted by the outer `Defer` node. Multiple subscriptions can be active simultaneously, in which case the nested workflow will run multiple times and is considered to be reentrant.
4 changes: 2 additions & 2 deletions articles/reactive-delay.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ title: Delay

![Marble diagram](~/images/reactive-delay.svg)

The `Delay` operator modifies the source sequence by pausing for the specified duration before emitting each of the values in the original sequence. This has the effect of delaying the timing of the entire sequence of values by that specified time interval.
The `Delay` operator modifies the source sequence by pausing for the specified duration before emitting each of the notifications in the original sequence. This has the effect of delaying the timing of the entire sequence of notifications by that specified time interval.

`Delay` is useful to model delayed responses to events in a control task, but also to access past data from a continuous stream in the future. In other words, if the stream timing is delayed, then any downstream observers grabbing data in the present moment will be receiving notifications from the past. For example, if you are recording data aligned on a temporal trigger detected in real-time, you can record data before the trigger simply by triggering the delayed sequence.
`Delay` is useful to model delayed responses to events in a control task, but also to access past data from a continuous stream in the future. In other words, if the stream timing is delayed, then any downstream observers grabbing data in the present moment will be receiving notifications from the past. For example, if you are recording data aligned on a temporal trigger detected in real-time, you can record data before the trigger simply by triggering the delayed sequence.
2 changes: 1 addition & 1 deletion articles/reactive-delaysubscription.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ title: DelaySubscription

The `DelaySubscription` operator modifies the source sequence by pausing for the specified duration before subscribing to the original sequence. This has the effect of delaying the start of the sequence by the specified time interval.

`DelaySubscription` can be used to control the timing of initialization. Note that if a source is [*hot*](xref:observables#temperature), delaying the start of the sequence will not preserve past data, since unlike [`Delay`](xref:Bonsai.Reactive.Delay) the `DelaySubscription` operator does not store or have access to any historical data.
`DelaySubscription` can be used to control the timing of initialization. Note that if a source is [*hot*](xref:observables#temperature), delaying the start of the sequence will not preserve past data, since unlike [`Delay`](xref:Bonsai.Reactive.Delay) the `DelaySubscription` operator does not store or have access to any historical data.
2 changes: 2 additions & 0 deletions articles/reactive-dematerialize.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ title: Dematerialize
---

![Marble diagram](~/images/reactive-dematerialize.svg)

`Dematerialize` is the complement of <xref href="Bonsai.Reactive.Materialize"/>. `Dematerialize` reconstructs the implicit notifications of an observable sequence from a sequence of explicit notifications. This can be useful if you have materialized a sequence for debugging or logging purposes but still need to retain the original sequence.
2 changes: 2 additions & 0 deletions articles/reactive-distinct.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ title: Distinct
---

![Marble diagram](~/images/reactive-distinct.svg)

The `Distinct` operator ensures that only unique elements are included in the result sequence. Uniqueness is specified by the default <xref href="System.Collections.Generic.EqualityComparer`1"/> for the type of the elements in the source sequence. If multiple non-unique elements are present in the source sequence, only the first element will be included in the result sequence.
2 changes: 2 additions & 0 deletions articles/reactive-distinctby.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ title: DistinctBy
---

![Marble diagram](~/images/reactive-distinctby.svg)

glopesdev marked this conversation as resolved.
Show resolved Hide resolved
The `DistinctBy` operator ensures that only unique elements are included in the result sequence. The <xref href="Bonsai.Reactive.DistinctBy.KeySelector"/> property specifies the member, or set of members, to use to test the uniqueness of each element in the source sequence. The default <xref href="System.Collections.Generic.EqualityComparer`1"/> for the type of the selected key is used to check whether each key is unique. If multiple non-unique keys are present in the source sequence, only the first element emitted with a given key will be included in the result sequence.
4 changes: 4 additions & 0 deletions articles/reactive-distinctuntilchanged.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ title: DistinctUntilChanged
---

![Marble diagram](~/images/reactive-distinctuntilchanged.svg)

The `DistinctUntilChanged` operator removes all contiguous elements in the sequence that are equal. Equality is determined by the default <xref href="System.Collections.Generic.EqualityComparer`1"/> for the type of the elements in the source sequence.

In other words, after each element is emitted by the result sequence, subsequent elements will be dropped until the value changes.
4 changes: 4 additions & 0 deletions articles/reactive-distinctuntilchangedby.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ title: DistinctUntilChangedBy
---

![Marble diagram](~/images/reactive-distinctuntilchangedby.svg)

glopesdev marked this conversation as resolved.
Show resolved Hide resolved
The `DistinctUntilChangedBy` operator removes all contiguous elements in the sequence with equal keys. The <xref href="Bonsai.Reactive.DistinctUntilChangedBy.KeySelector"/> property specifies the member, or set of members, used to test whether elements in the source sequence are equal. Equality is determined by the default <xref href="System.Collections.Generic.EqualityComparer`1"/> for the type of the selected key.

In other words, after each element is emitted by the result sequence, subsequent elements will be dropped until the value of the key changes.
2 changes: 2 additions & 0 deletions articles/reactive-elementindex.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ title: ElementIndex
---

![Marble diagram](~/images/reactive-elementindex.svg)

`ElementIndex` can be used to incrementally keep a tally of the number of elements in a sequence. It is also often used as the first step in custom index-dependent computations.
13 changes: 13 additions & 0 deletions articles/reactive-eventloopscheduler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
uid: reactive-eventloopscheduler
title: EventLoopScheduler
---

[!include[Schedulers](~/articles/reactive-schedulers.md)]

> [!Important]
> The scheduler object returned by `EventLoopScheduler` needs to be explicitly disposed. Assign the result of this operator to a <xref href="Bonsai.Reactive.ResourceSubject"/> to ensure the dedicated scheduler thread is terminated at the end of the workflow.

:::workflow
![Creating an EventLoopScheduler](~/workflows/reactive-eventloopscheduler-example.bonsai)
:::
10 changes: 10 additions & 0 deletions articles/reactive-first.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,13 @@ title: First
---

![Marble diagram](~/images/reactive-first.svg)

If the sequence has no elements, `First` will terminate with an error.

> [!Tip]
> If you are interested in finding the first element that meets some criteria, consider using the [**Condition**](xref:Bonsai.Reactive.Condition) operator before `First`.

> [!Warning]
> There are subtle but important differences between using the `First` operator and [**`Take(1)`**](xref:Bonsai.Reactive.Take):
> - When the source sequence has no elements, `Take(1)` will complete successfully, while `First` will throw an error.
> - When the source sequence emits the first element, `Take(1)` will immediately cancel the subscription to the source sequence before emitting the notification. `First`, on the other hand, will emit the notification and only afterwards cancel the subscription to the source sequence.
10 changes: 10 additions & 0 deletions articles/reactive-firstordefault.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,13 @@ title: FirstOrDefault
---

![Marble diagram](~/images/reactive-firstordefault.svg)

If the sequence has no elements, `FirstOrDefault` will emit a default value before terminating successfully.

> [!Tip]
> If you are interested in finding the first element that meets some criteria, consider using the [**Condition**](xref:Bonsai.Reactive.Condition) operator before `FirstOrDefault`.

> [!Warning]
> There are subtle but important differences between using the `FirstOrDefault` operator and [**`Take(1)`**](xref:Bonsai.Reactive.Take):
> - When the source sequence has no elements, `Take(1)` will complete successfully with no emitted values, while `FirstOrDefault` will emit a default value before terminating successfully.
> - When the source sequence emits the first element, `Take(1)` will immediately cancel the subscription to the source sequence before emitting the notification. `FirstOrDefault`, on the other hand, will emit the notification and only afterwards cancel the subscription to the source sequence.
9 changes: 9 additions & 0 deletions articles/reactive-gate.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,12 @@ title: Gate
---

![Marble diagram](~/images/reactive-gate.svg)

When the gate is in the open state, a single element is allowed to pass through from the source sequence. After this first element is emitted, the gate closes and all subsequent elements are dropped from the result sequence. The gate reopens when the second sequence emits a notification.

It is possible to specify how long the gate stays open by using the <xref href="Bonsai.Reactive.Gate.DueTime"/> property. If no value is specified, the gate stays open indefinitely until an element arrives. In this case, the gate starts immediately in the open state.

If a maximum due time is specified, no elements from the source sequence arriving after the due time elapses will be allowed through and the gate may close again without emitting any new elements. In this case, the gate starts in the closed state, and only opens when the second sequence emits a notification.

> [!Warning]
> If the second sequence emits notifications before the gate is closed, the gate will remain open. If there is a maximum specified due time, the timer will be reset upon arrival of the new notification. Even if there are multiple opening notifications, only a single element can make it through the gate.
4 changes: 4 additions & 0 deletions articles/reactive-gateinterval.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ title: GateInterval
---

![Marble diagram](~/images/reactive-gateinterval.svg)

The gate starts in the open state, and a single element is allowed to pass through from the source sequence. After this first element is emitted, the gate closes and all subsequent elements are dropped from the result sequence. The gate reopens when the specified <xref href="Bonsai.Reactive.GateInterval.Interval"/> elapses.

It is possible to specify how long the gate stays open by using the <xref href="Bonsai.Reactive.GateInterval.DueTime"/> property. If no value is specified, the gate stays open indefinitely until an element arrives. If a maximum due time is specified, then no elements from the source sequence arriving after the due time elapses will be allowed through until the gate reopens.
Loading