coralline 0.1.0 copy "coralline: ^0.1.0" to clipboard
coralline: ^0.1.0 copied to clipboard

An elegant Dart library implementing Chain of Reactivity and Lazy-computation as a Pipeline.

Coralline #

pub package License: Apache-2.0 Dart SDK

"Don't write boilerplates. To handle complex reactive pipelines, all you have to do is call a line (Coralline)."
Stop tangling your logic wiresβ€”a composable pipeline for reactive structures. Simply call a line.

Coralline is an elegant, zero-overhead Dart reactive pipeline engine based on CORAL (Chain of Reactivity And Lazy-computation). Designed to solve the computational flooding and verbosity of modern Flutter state management libraries, Coralline powers state management with the exact same architecture as Flutter's RenderObject rendering engine: Push-Dirty, Pull-Data.



πŸ’‘ Why Coralline? #

Traditional push-based reactive frameworks (e.g., standard Streams) continuously flood heavy data payloads downstream to every pipeline stage whenever upstream data mutates.

flowchart LR
    A0["Data Change"] -->|"Compute & Push"| B0["Intermediate Stage 1"]
    B0 -->|"Compute & Push"| C0["Intermediate Stage 2"]
    C0 -->|"Compute & Push"| D0["UI Rebuild"]

(Intermediate computations & object allocations executed immediately on every mutation)


Coralline solves this problem with elegance:

Phase 1: Push-Dirty (COR: Chain of Reactivity)

flowchart LR
    A1["CoralController"] -->|"Push-Dirty O(1)"| B1["CoralBroadcaster"]
    B1 --> C1["Coral.diverge"]
    C1 --> D1["Trunk.converge"]
    D1 -->|"O(1) Invalidation"| E1["CoralTerminal.onDirty"]
    E1 --> F1["UI Render Queue"]

(No data computation or allocation; only broadcasts an O(1) dirty flag down the Chain of Reactivity)


Phase 2: Pull-Data (AL: And Lazy-computation)

flowchart RL
    F2["UI Render (Display)"] -->|"VSYNC Render Tick"| E2["CoralTerminal.snapshot"]
    E2 --> D2["Trunk.converge"]
    D2 -->|"Upstream Pull"| C2["Coral.diverge"]
    C2 --> B2["CoralBroadcaster"]
    B2 --> A2["CoralController"]

(Triggers backward Pull from Terminal up to Source ONLY during VSYNC render tick to compute exactly ONCE)

  1. Push-Dirty ($O(1)$ Invalidation): When a state source changes, Coralline broadcasts a lightweight, dirty flag down the DAG graph. No actual data is computed or pushed.
  2. Coalescing Buffer: Multiple synchronous state mutations within the same event loop are coalesced into a single invalidation frame, eliminating mid-frame layout thrashing.
  3. Pull-Data (Strictly Lazy Computation): Intermediate transformations (map, derive, aggregate) are executed only when the UI Terminal explicitly requests .snapshot or .data.
  4. Fasttrack Direct Pointer Bypass: Topology resolution is pre-cached ($O(1)$ direct jump), bypassing $O(d)$ parent-chain traversals during runtime state updates.



⚑ 15-Second Quick Start #

1. Counter Pipeline

import 'package:coralline/coralline.dart';

void main() {
  // 1. Create a reactive controller (Source)
  final controller = CoralController<int>(0);

  // 2. Build a lazy transformation pipeline ("Call a line")
  final doubleCoral = controller.coral.map((count) => count * 2);

  // 3. Connect and activate a terminal (Destination)
  late final CoralTerminal<int> terminal;
  terminal = doubleCoral.toTerminal(() {
    print('Doubled count is: ${terminal.data}');
  });
  terminal.activate();

  // 4. Update data imperatively
  controller.set(1); // Output: Doubled count is: 2
  controller.set(5); // Output: Doubled count is: 10
}

2. Async Data & Pattern Matching

final searchController = CoralController<String>('');

// Async pipeline with cascade and toCoral()
final searchResults = searchController.coral.cascade((query) {
  return fetchSearchResults(query).toCoral();
});

late final CoralTerminal<String> terminal;
terminal = searchResults.toTerminal(() {
  switch (terminal.snapshot) {
    case CoralSnapshotValid(:final data):
      print('Results: $data');
    case CoralSnapshotEmpty():
      print('Type a search query...');
    case CoralSnapshotDamaged(:final error):
      print('Error loading results: $error');
  }
});
terminal.activate();

πŸ’‘ Tip: Do I need to write a switch statement for every snapshot?
Not at all! For routine UI displays or fallback defaults, ergonomic accessors handle it in a single line:

  • Fallback Default Value: final count = terminal.snapshot.dataOrElse(() => 0);
  • Null Operator Convenience: final text = terminal.snapshot.dataOrNull?.toString() ?? 'Loading...';
  • Direct Access on Guaranteed Sources: final data = controller.coral.data;



πŸ”„ Coralline & Dart Stream (Complementary Architecture) #

"Can Coralline completely replace Dart Streams?"
Answer: Coralline does not view Streams as a target for total replacement. Instead, it advocates an elegant separation of concerns and complementary relationship: Stream for low-level asynchronous event collection, and Coralline for lazy UI state transformations and computation pipelines.

1. Architecture & Feature Comparison

Dimension Dart Stream Coralline
Reactive Paradigm Eager Push Model
(Heavy payloads emitted downstream immediately on mutation)
Push-Dirty, Pull-Data
($O(1)$ Dirty flag push, synchronous lazy pull on demand)
Execution Timing Eager Computation
Intermediate map/where & allocations run immediately
Lazy Computation
Computed exactly ONCE when UI renders, cached until dirty
Sync vs Async Async Event Loop
Bound to microtask queue; 1-frame latency potential
Synchronous Pure Computation
Pipeline executes synchronously for 0ms UI frame rendering
Frame Coalescing Manual Operators Required
Requires debounceTime for multi-mutations in 1 frame
Automatic Frame Coalescing
100 mutations in 1 frame computed exactly ONCE on render
State & Error Separated Event + onError
Ambiguous whether null means loading or data
CoralSnapshot Boxing
Valid, Empty, Damaged containers with fail-fast safety
Multi-Source Union Complex Stream Combination Native Trunk.of([...]).converge(...) Support
1:N Multicasting BroadcastStream
Manual listener tracking & cleanup required
CoralBroadcaster
Smart reference counting & Lazy Deactivation (zero hot-reload flicker)
Runtime Source Swapping Requires Teardown & Re-subscribe CoralCoupler
Runtime Coldswap / Hotswap sockets preserving downstream

πŸ’‘ Role Allocation Guide

  1. Areas Where Coralline Replaces Stream (Highly Recommended)
    • UI State Management & Reactive Pipelines: Replaces legacy Stream or StreamBuilder pipelines used for data transformation and UI feeding.
    • Multi-Source Combination & Form Validation: Business logic deriving final state from multiple fields or input streams.
  2. Areas Where Stream is Retained alongside Coralline (Complementary)
    • Low-Level Asynchronous Event Ingestion: Asynchronous event sources (WebSocket, hardware sensors, OS callbacks) are captured via Stream and bound into Coralline via .toCoral().
// Recommended Pattern: Capture events via Stream, bind to Coralline via .toCoral()
final Stream<Location> rawGpsStream = GpsSensor.stream();

// Automatically unsubscribes from Stream when active subscriber count drops to 0
final Coral<Location> locationCoral = rawGpsStream.toCoral();

// Build a lazy pipeline computed synchronously ONLY when UI requests a frame
final Coral<String> displayAddressCoral = locationCoral
    .cascade((location) => AddressFormatter.format(location));



🧩 Core Topologies #

Beyond simple 1:1 pipelines, Coralline provides first-class declarative support for complex reactive graph topologies:

1. N:1 Multi-Source Convergence (Trunk)

Bundles multiple independent upstream sources into a single computation. Regardless of how many times upstream sources mutate, lazy computation executes exactly once during UI rendering.

graph TD
    A["Coral A"] --> T["Trunk.of([A, B])"]
    B["Coral B"] --> T
    T --> Conv["converge((prices) => A + B)"]
    Conv --> Term["CoralTerminal (UI)"]

2. 1:N Multicast Sharing (CoralBroadcaster)

Eliminates redundant upstream computations when sharing a single source among multiple downstream consumers with automatic reference counting. Microtask-deferred lazyDeactivation prevents UI flicker during hot reloads.

graph TD
    Source["Upstream Source (Coral.resource)"] --> Broadcaster["CoralBroadcaster"]
    Broadcaster --> BranchA["Branch A"] --> TermA["UI Terminal A"]
    Broadcaster --> BranchB["Branch B"] --> TermB["UI Terminal B"]

3. Dynamic Runtime Source Swapping (CoralCoupler)

Swaps upstream sources dynamically at runtime using Coldswap or Hotswap without tearing down or re-instantiating downstream UI widgets and pipelines.

graph TD
    SourceA["Source A (Guest API)"] -. "couple()" .-> Coupler["CoralCoupler"]
    SourceB["Source B (Auth API)"] ==> Coupler
    Coupler ==> Pipe["Pipeline"] ==> Term["UI Terminal"]



πŸ“Š Feature Comparison Matrix #

Dimension BLoC (flutter_bloc) Riverpod Signals (dart_signals) Coralline
Core Paradigm Event Stream Transformer Provider Dependency Tree Fine-grained Reactive Signals Chain of Reactivity & Lazy Pipeline (CORAL)
Reactivity Mode Eager Stream Emission Eager Invalidation & Re-compute Eager Signal Effect Mutation Push-Dirty ($O(1)$) + Strictly Lazy Pull-Data
Flutter Engine Harmony Indirect (Stream-based) Custom Container Tree Atomic Variable Tracking 100% Identical to Flutter RenderObject Pipeline
Topology Resolution $O(d)$ Context Lookup Container Element Tree Dynamic Dependency Graph $O(1)$ Fasttrack Direct Pointer Bypass
Boilerplate Cost High (Events, States, Blocs) Medium-High (Providers, Ref) Low (Signal, Computed) Ultra Low ("Just call a line")
Release Overhead Stream allocation cost Element tracking overhead Graph tracking overhead Zero-Overhead Assertions (0% Release Cost)
Error Handling Exception in Stream AsyncValue Enum Imperative Try/Catch Struct-like CoralSnapshot<T> Boxing



🎯 Architecture for Flutter & Dart Engineers #

Coralline was built from the ground up to align perfectly with Flutter's internal architecture:

  • Pure Dart 3 Engine: Zero dependencies on flutter/widgets.dart in the core engine. Runs seamlessly on Dart VM, Server, CLI, Web (Wasm), and Flutter.
  • Zero-Overhead Assertions: Invariant safety checks, intent firewalls, and cycle detection are wrapped in assert(() { ... return true; }());. Release builds incur 0.00% runtime overhead.
  • Microtask Lazy Deactivation: Deactivation of shared broadcast pipelines is deferred to the end of the microtask queue, guaranteeing zero-flicker UI updates during hot-reloads and route switches.



πŸ“š Comprehensive Documentation #

Explore our detailed manuals tailored for different audiences:

  1. πŸš€ Quickstart & Core Concepts Guide - Build your first pipeline in 5 minutes.
  2. πŸ”€ Pipeline & Broadcasting Guide - Master 1:N sharing (CoralBroadcaster), dynamic topology (CoralCoupler), and snapshots.
  3. πŸ“– Public API Reference Manual - Comprehensive catalog of all public Classes, Mixins, and Extensions.
  4. πŸ”¬ Flutter & Dart Engineering Whitepaper - Deep technical analysis of Push-Dirty Pull-Data, Fasttrack $O(1)$, and Wasm performance.



πŸ“„ License #

Coralline is open-source software licensed under the Apache 2.0 License.
Copyright 2023-2026 Youngjune Jeon All rights reserved.

1
likes
160
points
96
downloads

Documentation

API reference

Publisher

verified publishercoralline.dev

Weekly Downloads

An elegant Dart library implementing Chain of Reactivity and Lazy-computation as a Pipeline.

Repository (GitHub)
View/report issues

Topics

#state-management #reactivity #pipeline #reactive

License

Apache-2.0 (license)

Dependencies

meta

More

Packages that depend on coralline