Skip to main content

live_data/
descriptor.rs

1//! Per-feed descriptor and capability advertisement.
2
3use serde::{Deserialize, Serialize};
4
5use crate::schema::WireSchema;
6use crate::transport::{FormatPreference, TransportTag};
7
8/// Single named live feed, as advertised by a publisher.
9///
10/// A descriptor is information-only: it describes what the feed is and how it
11/// can be consumed. The matching producer-side handle
12/// lives in `live-stream`.
13#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14pub struct FeedDescriptor {
15    /// Stable identifier for the feed, unique within a single publisher.
16    pub name: String,
17    /// Schema every emitted batch on the feed conforms to.
18    pub schema: WireSchema,
19    /// Transports the publisher is currently accepting subscriptions over.
20    pub transports: Vec<TransportTag>,
21    /// Formats the publisher can serialise batches into.
22    pub formats: Vec<FormatPreference>,
23    /// What the publisher is willing to do server-side at subscribe time.
24    pub capabilities: Capabilities,
25    /// Name of the column carrying the canonical event timestamp on
26    /// this feed. Optional in the manifest grammar so future
27    /// non-temporal feeds remain expressible, always populated for
28    /// streaming market data feeds.
29    #[serde(default)]
30    pub event_time_key: Option<String>,
31    /// Free-form classification tags, e.g. `["finance", "ticks"]`.
32    #[serde(default)]
33    pub tags: Vec<String>,
34    /// Optional human-readable description.
35    #[serde(default)]
36    pub description: Option<String>,
37}
38
39impl FeedDescriptor {
40    pub fn new(name: impl Into<String>, schema: WireSchema) -> Self {
41        Self {
42            name: name.into(),
43            schema,
44            transports: Vec::new(),
45            formats: Vec::new(),
46            capabilities: Capabilities::minimal(),
47            event_time_key: None,
48            tags: Vec::new(),
49            description: None,
50        }
51    }
52}
53
54/// What the publisher is willing to do server-side when accepting a subscription.
55///
56/// Only `can_project` defaults to true. The other two fields exist so
57/// the wire format is stable when filter and sampling support land, and so
58/// consumers can already gate features on what the server advertises.
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
60pub struct Capabilities {
61    /// Server honours [`SubscriptionDescriptor::columns`] for projection.
62    pub can_project: bool,
63    /// Server honours [`SubscriptionDescriptor::filter`] for row-level filtering.
64    pub can_filter: bool,
65    /// Server honours [`SubscriptionDescriptor::sampling`].
66    pub can_sample: bool,
67}
68
69impl Capabilities {
70    /// Minimum guaranteed capability set
71    pub const fn minimal() -> Self {
72        Self { can_project: true, can_filter: false, can_sample: false }
73    }
74
75    /// All capabilities enabled.
76    pub const fn all() -> Self {
77        Self { can_project: true, can_filter: true, can_sample: true }
78    }
79}
80
81impl Default for Capabilities {
82    fn default() -> Self {
83        Self::minimal()
84    }
85}