Skip to main content

fiftyone_pipeline_core/
flow_element.rs

1/* *********************************************************************
2 * This Original Work is copyright of 51 Degrees Mobile Experts Limited.
3 * Copyright 2026 51 Degrees Mobile Experts Limited, Davidson House,
4 * Forbury Square, Reading, Berkshire, United Kingdom RG1 3EU.
5 *
6 * This Original Work is licensed under the European Union Public Licence
7 * (EUPL) v.1.2 and is subject to its terms as set out below.
8 *
9 * If a copy of the EUPL was not distributed with this file, You can obtain
10 * one at https://opensource.org/licenses/EUPL-1.2.
11 *
12 * The 'Compatible Licences' set out in the Appendix to the EUPL (as may be
13 * amended by the European Commission) shall be deemed incompatible for
14 * the purposes of the Work and the provisions of the compatibility
15 * clause in Article 5 of the EUPL shall not apply.
16 *
17 * If using the Work as, or as part of, a network application, by
18 * including the attribution notice(s) required under Article 5 of the EUPL
19 * in the end user terms of the application under an appropriate heading,
20 * such notice(s) shall fulfill the requirements of that article.
21 * ********************************************************************* */
22
23//! The flow element trait: a black box that processes flow data.
24//!
25//! A flow element reads evidence and earlier element data from a
26//! [`crate::FlowData`] and may add its own element data. See the
27//! [conceptual overview](https://github.com/51Degrees/specifications/blob/main/pipeline-specification/conceptual-overview.md#flow-element).
28//!
29//! # Design choice: object-safe `dyn` trait, not an associated type
30//!
31//! A pipeline holds a heterogeneous, ordered list of elements that produce
32//! different element-data types. To store them in a single `Vec` and run them
33//! in order, [`FlowElement`] is kept **object-safe** so the pipeline can hold
34//! `Arc<dyn FlowElement>` trait objects.
35//!
36//! That rules out putting the element-data type as an associated type or a
37//! generic parameter on this trait (either would make `dyn FlowElement`
38//! impossible). Instead the type linkage lives in [`crate::TypedKey<T>`]: a
39//! concrete element exposes a `TypedKey<T>` for its own data through its own
40//! inherent API, and [`crate::FlowData::get`] uses it to downcast. This is the
41//! "no-reflection core" approach from the plan and realises mechanisms 1 and 2
42//! of the
43//! [access-to-results specification](https://github.com/51Degrees/specifications/blob/main/pipeline-specification/features/access-to-results.md)
44//! without a generic on the stored element.
45//!
46//! # Thread safety
47//!
48//! `process` takes `&self`, so one shared element instance serves many
49//! concurrent flow data, as required by the
50//! [thread-safety specification](https://github.com/51Degrees/specifications/blob/main/pipeline-specification/features/thread-safety.md#flow-elements).
51//! The trait is therefore `Send + Sync`. Any per-request scratch state must be
52//! created inside `process`; any hot mutable state (for example a reloadable
53//! data file) belongs behind a synchronisation primitive owned by the element.
54
55use crate::error::Result;
56use crate::evidence::EvidenceKeyFilter;
57use crate::flow_data::FlowData;
58use crate::property::PropertyMetaData;
59
60/// The basic building block of a pipeline.
61///
62/// Implementations are shared (`Arc`) and immutable once added to a pipeline,
63/// so the trait requires `Send + Sync`. See the module documentation for the
64/// rationale behind the object-safe design.
65pub trait FlowElement: Send + Sync {
66    /// Process the supplied flow data with this element.
67    ///
68    /// The element reads evidence and earlier element data from `data` and may
69    /// add its own element data via [`crate::FlowData::get_or_add`]. Returning
70    /// `Err` signals a processing failure; the pipeline decides whether to
71    /// propagate or record it according to its `suppress_process_exceptions`
72    /// setting, per the
73    /// [exception-handling specification](https://github.com/51Degrees/specifications/blob/main/pipeline-specification/features/exception-handling.md#process-function).
74    ///
75    /// `process` takes `&self` so a single element instance can serve many
76    /// concurrent requests.
77    fn process(&self, data: &mut FlowData) -> Result<()>;
78
79    /// The string data key used to store and retrieve this element's data in a
80    /// flow data. This is a specification MUST.
81    fn data_key(&self) -> &str;
82
83    /// A filter describing the evidence keys this element can make use of.
84    ///
85    /// Advertising accepted evidence is a specification MUST. See the
86    /// [advertise-accepted-evidence specification](https://github.com/51Degrees/specifications/blob/main/pipeline-specification/features/advertize-accepted-evidence.md).
87    /// The pipeline ORs every element's filter together to derive its own
88    /// pipeline-wide filter.
89    fn evidence_key_filter(&self) -> &dyn EvidenceKeyFilter;
90
91    /// Metadata for the properties this element can populate.
92    ///
93    /// Publishing produced properties is a specification MUST. See the
94    /// [properties specification](https://github.com/51Degrees/specifications/blob/main/pipeline-specification/features/properties.md#property-metadata).
95    fn properties(&self) -> &[PropertyMetaData];
96
97    /// True if this element starts multiple threads internally. Defaults to
98    /// `false`. A pipeline reports itself concurrent if any element does, which
99    /// influences whether thread-safe flow data is needed.
100    fn is_concurrent(&self) -> bool {
101        false
102    }
103}