Skip to content

reference docs for the queue system #17

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions docs/BITWISE_OPERATIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Bitwise Operations in the Reactive System

## Overview
The reactive system uses bitwise operations to efficiently track and manage various states of effects and computations. This document explains how these operations work and their purpose in the system.

## Flag Definitions

The system uses several flags to represent different states:

```typescript
// Error state flag
const ERROR_BIT = 1 << 0; // Binary: 0001

// Loading state flag
const LOADING_BIT = 1 << 1; // Binary: 0010

// Uninitialized state flag
const UNINITIALIZED_BIT = 1 << 2; // Binary: 0100
```

## Common Operations

### 1. Setting Flags
To set multiple flags:

```typescript
// Set error and loading flags
let flags = ERROR_BIT | LOADING_BIT; // Binary: 0011
```

### 2. Checking Flags
To check if a flag is set:

```typescript
// Check if error flag is set
if (flags & ERROR_BIT) {
// Handle error state
}

// Check if either error or loading flag is set
if (flags & (ERROR_BIT | LOADING_BIT)) {
// Handle error or loading state
}
```

### 3. Removing Flags
To remove a flag:

```typescript
// Remove loading flag
flags &= ~LOADING_BIT;
```

## Usage in the System

### 1. Effect States
Effects use flags to track their current state:

```typescript
// Notify queue about loading and error states
this._queue.notify(this, LOADING_BIT | ERROR_BIT, flags);
```

### 2. Boundary Conditions
Boundaries use flags to control propagation:

```typescript
// Set propagation mask for boundary
this._propagationMask = disabled ? ERROR_BIT | LOADING_BIT : 0;
```

### 3. State Management
Computations use flags to manage their state:

```typescript
// Check loading state
if (this._stateFlags & LOADING_BIT) {
throw new NotReadyError();
}
```

## Benefits of Bitwise Operations

1. **Efficiency**
- Single number can represent multiple states
- Bitwise operations are very fast
- Uses minimal memory

2. **Flexibility**
- Easy to combine states
- Easy to check multiple states
- Easy to modify states

3. **Type Safety**
- TypeScript can type-check the flags
- Prevents invalid state combinations
- Makes state management more predictable

## Common Flag Combinations

| Combination | Description |
|------------|-------------|
| `ERROR_BIT` | Error state only |
| `LOADING_BIT` | Loading state only |
| `ERROR_BIT | LOADING_BIT` | Both error and loading states |
| `LOADING_BIT | UNINITIALIZED_BIT` | Loading and uninitialized states |

## Best Practices

1. **Flag Definition**
- Use powers of 2 for flag values
- Document flag purposes
- Keep flag names descriptive

2. **Flag Operations**
- Use bitwise OR (`|`) to combine flags
- Use bitwise AND (`&`) to check flags
- Use bitwise NOT (`~`) to remove flags

3. **State Management**
- Clear flags when no longer needed
- Check flags before operations
- Handle all possible flag combinations

## Example Usage

```typescript
// Create an effect with initial flags
const effect = new Effect(initialValue, compute, effectFn);

// Set multiple flags
effect.write(newValue, ERROR_BIT | LOADING_BIT);

// Check flags
if (effect._stateFlags & LOADING_BIT) {
// Handle loading state
}

// Remove flag
effect._stateFlags &= ~ERROR_BIT;
```

## Related Documentation
- See [QUEUE_NOTIFICATION_SYSTEM.md](./QUEUE_NOTIFICATION_SYSTEM.md) for details on how flags are used in the queue system
- See [EFFECTS.md](./EFFECTS.md) for details on effect implementation
- See [BOUNDARIES.md](./BOUNDARIES.md) for details on boundary implementation
167 changes: 167 additions & 0 deletions docs/QUEUE_EXECUTION_CONTROL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# Queue System: Execution Control

## Overview
The queue system is primarily responsible for managing the execution of effects in the reactive system. While it also handles state notifications (see [QUEUE_NOTIFICATION_SYSTEM.md](./QUEUE_NOTIFICATION_SYSTEM.md)), its core purpose is to ensure effects run in the correct order, handle batching of updates, and coordinate execution across different parts of the application.

## Core Concepts

### 1. Effect Types
The system distinguishes between different types of effects:

- **Pure Effects**: Computations that derive values
- **Render Effects**: Effects that update the UI
- **User Effects**: Custom effects created by the user

### 2. Execution Queues
Each queue maintains three separate queues for different effect types:

```typescript
_queues: [Computation[], Effect[], Effect[]] = [[], [], []];
```

This separation ensures:
- Pure computations run before effects
- Render effects run before user effects
- Effects of the same type run in the order they were created

## Execution Flow

### 1. Enqueuing Effects
When an effect needs to run:

```typescript
enqueue<T extends Computation | Effect>(type: number, node: T): void {
this._queues[0].push(node as any);
if (type) this._queues[type].push(node as any);
schedule();
}
```

This:
- Adds the effect to the general queue
- Adds it to its specific type queue
- Schedules execution

### 2. Execution Scheduling
Effects are executed in batches:

```typescript
flush() {
if (this._running) return;
this._running = true;
try {
while (this.run(EFFECT_PURE)) {}
incrementClock();
scheduled = false;
this.run(EFFECT_RENDER);
this.run(EFFECT_USER);
} finally {
this._running = false;
}
}
```

The order is important:
1. Pure computations run first (may repeat if new computations are added)
2. Clock is incremented to mark the batch
3. Render effects run
4. User effects run

### 3. Effect Execution
Each effect type has its own execution strategy:

```typescript
run(type: number) {
if (this._queues[type].length) {
if (type === EFFECT_PURE) {
runPureQueue(this._queues[type]);
this._queues[type] = [];
} else {
const effects = this._queues[type] as Effect[];
this._queues[type] = [];
runEffectQueue(effects);
}
}
// ... handle child queues
}
```

## Specialized Execution Control

### 1. Conditional Execution
Some queues can conditionally execute effects:

```typescript
class ConditionalQueue extends Queue {
run(type: number) {
if (type && this._disabled.read()) return;
return super.run(type);
}
}
```

This allows:
- Pausing effect execution based on conditions
- Resuming execution when conditions change
- Managing execution in boundary contexts

### 2. Collection-based Execution
Queues can manage execution based on collections:

```typescript
class CollectionQueue extends Queue {
_disabled: Computation<boolean> = new Computation(false, null);

run(type: number) {
if (this._disabled.read()) return;
return super.run(type);
}
}
```

This enables:
- Group-based execution control
- Automatic enabling/disabling based on collection state
- Coordinated execution of related effects

## Best Practices

### 1. Effect Creation
- Use appropriate effect types
- Consider execution order requirements
- Handle cleanup properly

### 2. Queue Management
- Create appropriate queue hierarchies
- Use specialized queues when needed
- Ensure proper cleanup

### 3. Execution Control
- Batch related updates
- Handle edge cases (errors, loading states)
- Consider performance implications

## Example Usage

```typescript
// Create a queue with execution control
const queue = new Queue();

// Create different types of effects
const pureEffect = new Computation(initialValue, compute);
const renderEffect = new Effect(initialValue, compute, effectFn, { render: true });
const userEffect = new Effect(initialValue, compute, effectFn);

// Effects will be executed in the correct order
queue.enqueue(EFFECT_PURE, pureEffect);
queue.enqueue(EFFECT_RENDER, renderEffect);
queue.enqueue(EFFECT_USER, userEffect);

// Execute all effects
queue.flush();
```

## Related Documentation
- See [QUEUE_NOTIFICATION_SYSTEM.md](./QUEUE_NOTIFICATION_SYSTEM.md) for details on the secondary notification system
- See [BITWISE_OPERATIONS.md](./BITWISE_OPERATIONS.md) for details on state management
- See [EFFECTS.md](./EFFECTS.md) for details on effect implementation
Loading