Thanks to visit codestin.com
Credit goes to lib.rs

1 unstable release

Uses new Rust 2024

0.1.0 Dec 28, 2025

#788 in Procedural macros

Apache-2.0 OR MIT

81KB
1.5K SLoC

picante

Crates.io docs.rs License codecov Experimental

picante is an async incremental query runtime for Rust, inspired by Salsa but built for Tokio-first pipelines (like Dodeca).

What it has today

  • Inputs (InputIngredient<K, V>), interning (InternedIngredient<K>), and derived async queries (DerivedIngredient<DB, K, V>)
  • Dependency tracking via Tokio task-locals
  • Per-task cycle detection (fast path)
  • Async single-flight memoization per (kind, key)
  • Cache persistence to disk (snapshot file) using facet + facet-postcard (no serde)
  • Runtime notifications for live reload (Runtime::subscribe_revisions, Runtime::subscribe_events)

Quickstart (minimal)

use picante::{DerivedIngredient, DynIngredient, HasRuntime, IngredientLookup, IngredientRegistry, InputIngredient, QueryKindId, Runtime};
use std::sync::Arc;

#[derive(Default)]
struct Db {
    runtime: Runtime,
    ingredients: IngredientRegistry<Db>,
}

impl HasRuntime for Db {
    fn runtime(&self) -> &Runtime {
        &self.runtime
    }
}

impl IngredientLookup for Db {
    fn ingredient(&self, kind: QueryKindId) -> Option<&dyn DynIngredient<Self>> {
        self.ingredients.ingredient(kind)
    }
}

#[tokio::main(flavor = "current_thread")]
async fn main() -> picante::PicanteResult<()> {
    let db = Db::default();

    let text: Arc<InputIngredient<String, String>> =
        Arc::new(InputIngredient::new(QueryKindId(1), "Text"));

    let len: Arc<DerivedIngredient<Db, String, u64>> = {
        let text = text.clone();
        Arc::new(DerivedIngredient::new(QueryKindId(2), "Len", move |db, key| {
            let text = text.clone();
            Box::pin(async move {
                let s = text.get(db, &key)?.unwrap_or_default();
                Ok(s.len() as u64)
            })
        }))
    };

    text.set(&db, "a".into(), "hello".into());
    assert_eq!(len.get(&db, "a".into()).await?, 5);

    Ok(())
}

Persistence (snapshot cache)

picante can save/load inputs and memoized derived values (including dependency lists):

use picante::persist::{load_cache, save_cache};

// save_cache(path, db.runtime(), &[&*text, &*len]).await?;
// load_cache(path, db.runtime(), &[&*text, &*len]).await?;

If you need cache size limits or custom corruption handling, use:

  • save_cache_with_options
  • load_cache_with_options

Notes

  • Tokio-only: query execution uses Tokio task-local context.
  • Global invalidation v1: changing any input bumps a single global Revision.
  • Compile-time optimized: derived query state machine uses trait objects to avoid monomorphization bloat (96% IR reduction, 36% faster builds). Small runtime cost (vtable dispatch + boxed futures) for large compile-time win. See architecture docs for details.

License

Licensed under either of Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) or MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT) at your option.

Dependencies

~420KB