Rust SDK: gaps on processing components dispatching and target states declaration
Author: georgeh0Created Jul 27, 2026Updated Jul 28, 2026
See examples first
Rust example
e.g. code from the text_embedding example:
- It walks the target directory, collects all files first and keep them in a
Vec. - After all files collected, it mounts a component for each file, and collect all result rows.
- At last, it calls
declare_row()for rows collected from all files at top level.
Corresponding Python example
Conversely, this is how the Python example works:
It calls
walk_dirto get a iterator, somount_each()consumes files in streaming manner. We don't need to wait until all files collected in memory before starting doing work.Each component to process each file doesn't return anything. So we don't need to load and collect target rows for unchanged files.
declare_row()is called within the component, i.e. these target rows are owned by components for each specific file. These data only need to be in memory and reconciled when the specific file changes.
The gaps
- Sources need to provide methods to return an iterator or stream.
mount_each!needs to be able to take iterator/stream as input and dispatch works in streaming manner. - In most cases we should call
declare_*within specific components, and let the components return nothing, so unchanged components can be skipped cheaply and instantly (without loading anything in memory). - Semantics of
mount_each!should be based onmount()rather thanuse_mount(), i.e. it's "dispatching the component in background" (no return value dependency) rather than "running and wait for the result". It returns a handle similar tomount(), and the handle can be used to waiting for readiness optionally, but by default after it's dispatched we don't block on it. See Processing component for more explanations of the difference.
Source: cocoindex-io/cocoindex