windowed_stats/experimental/event/
builder.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::marker::PhantomData;
6
7use crate::experimental::clock::Timed;
8use crate::experimental::event::Event;
9use crate::experimental::event::reactor::{Context, Reactor};
10use crate::experimental::series::interpolation::InterpolationKind;
11use crate::experimental::series::statistic::{FoldError, Metadata, SerialStatistic, Statistic};
12use crate::experimental::series::{MatrixSampler, SamplingProfile, TimeMatrix};
13use crate::experimental::serve::{InspectSender, InspectedTimeMatrix, TimeMatrixClient};
14
15/// A type that maps the presence of an optional builder field to another type.
16pub trait Optional {
17    type Field;
18}
19
20/// An optional builder field that has been set to a value of type `T`.
21#[derive(Clone, Copy, Debug, Default)]
22pub struct Set<T>(PhantomData<fn() -> T>);
23
24impl<T> Optional for Set<T> {
25    type Field = T;
26}
27
28/// An optional builder field that has **not** been set.
29#[derive(Clone, Copy, Debug, Default)]
30pub struct Unset;
31
32impl Optional for Unset {
33    type Field = ();
34}
35
36/// Builds a [`Reactor`] that samples a [data record][`DataEvent::record`] with a [`TimeMatrix`].
37///
38/// The [`TimeMatrix`] is send to [an Inspect server][`serve::serve_time_matrix_inspection] via a
39/// given client.
40///
41/// See the [`event::sample_data_record`] function.
42///
43/// [`DataEvent::record`]: crate::experimental::event::DataEvent::record
44/// [`event::sample_data_record`]: crate::experimental::event::sample_data_record
45/// [`Reactor`]: crate::experimental::event::Reactor
46/// [`serve::serve_time_matrix_inspection`]: crate::experimental::serve::serve_time_matrix_inspection
47/// [`TimeMatrix`]: crate::experimental::series::TimeMatrix
48#[derive(Clone, Copy, Debug)]
49pub struct SampleDataRecord<F, S = (), M = Unset>
50where
51    M: Optional,
52{
53    statistic: F,
54    metadata: M::Field,
55    phantom: PhantomData<fn() -> S>,
56}
57
58impl<F, S, M> SampleDataRecord<F, S, M>
59where
60    M: Optional,
61{
62    fn reactor<T>(
63        matrix: InspectedTimeMatrix<T>,
64    ) -> impl Reactor<T, S, Response = (), Error = FoldError>
65    where
66        T: Clone,
67    {
68        move |event: Timed<Event<T>>, _: Context<'_, S>| {
69            if let Some(sample) = event.to_timed_sample() { matrix.fold(sample) } else { Ok(()) }
70        }
71    }
72}
73
74impl<F, S> SampleDataRecord<F, S, Set<Metadata<F>>>
75where
76    F: Statistic,
77{
78    pub fn in_time_matrix<P>(
79        self,
80        client: &TimeMatrixClient,
81        name: impl AsRef<str>,
82        profile: SamplingProfile,
83        interpolation: P::Output<F::Sample>,
84    ) -> impl Reactor<F::Sample, S, Response = (), Error = FoldError>
85    where
86        TimeMatrix<F, P>: 'static + MatrixSampler<F::Sample> + Send,
87        Metadata<F>: 'static + Send + Sync,
88        F: SerialStatistic<P>,
89        F::Sample: Send,
90        P: InterpolationKind,
91    {
92        let SampleDataRecord { statistic, metadata, .. } = self;
93        let matrix = client.inspect_time_matrix_with_metadata(
94            name.as_ref(),
95            TimeMatrix::with_statistic(profile, interpolation, statistic),
96            metadata,
97        );
98        Self::reactor(matrix)
99    }
100}
101
102impl<F, S> SampleDataRecord<F, S, Unset>
103where
104    F: Statistic,
105{
106    /// Builds the [`Reactor`] with the given metadata for the [`TimeMatrix`].
107    ///
108    /// The type of `metadata` is determined by the [`DataSemantic`] of the [`Statistic`]. For
109    /// example, the [`Union`] statistic has [`BitSet`] semantics and so requires types convertible
110    /// into the [`BitSetIndex`] metadata type.
111    ///
112    /// [`BitSet`]: crate::experimental::series::BitSet
113    /// [`BitSetIndex`]: crate::experimental::series::metadata::BitSetIndex
114    /// [`DataSemantic`]: crate::experimental::series::DataSemantic
115    /// [`Reactor`]: crate::experimental::event::Reactor
116    /// [`Statistic`]: crate::experimental::series::statistic::Statistic
117    /// [`TimeMatrix`]: crate::experimental::series::TimeMatrix
118    /// [`Union`]: crate::experimental::series::statistic::Union
119    pub fn with_metadata(
120        self,
121        metadata: impl Into<Metadata<F>>,
122    ) -> SampleDataRecord<F, S, Set<Metadata<F>>> {
123        let SampleDataRecord { statistic, .. } = self;
124        SampleDataRecord { statistic, metadata: metadata.into(), phantom: PhantomData }
125    }
126
127    pub fn in_time_matrix<P>(
128        self,
129        client: &TimeMatrixClient,
130        name: impl AsRef<str>,
131        profile: SamplingProfile,
132        interpolation: P::Output<F::Sample>,
133    ) -> impl Reactor<F::Sample, S, Response = (), Error = FoldError>
134    where
135        TimeMatrix<F, P>: 'static + MatrixSampler<F::Sample> + Send,
136        Metadata<F>: 'static + Send + Sync,
137        F: SerialStatistic<P>,
138        F::Sample: Send,
139        P: InterpolationKind,
140    {
141        let SampleDataRecord { statistic, .. } = self;
142        let matrix = client.inspect_time_matrix(
143            name.as_ref(),
144            TimeMatrix::with_statistic(profile, interpolation, statistic),
145        );
146        Self::reactor(matrix)
147    }
148}
149
150/// Constructs a builder for a [`Reactor`] that samples a [data record][`DataEvent::record`] with a
151/// [`TimeMatrix`] using the given [`Statistic`].
152///
153/// [`DataEvent::record`]: crate::experimental::event::DataEvent::record
154/// [`Reactor`]: crate::experimental::event::Reactor
155/// [`Statistic`]: crate::experimental::series::statistic::Statistic
156/// [`TimeMatrix`]: crate::experimental::series::TimeMatrix
157pub fn sample_data_record<S, F>(statistic: F) -> SampleDataRecord<F, S, Unset>
158where
159    F: Statistic,
160{
161    SampleDataRecord { statistic, metadata: (), phantom: PhantomData }
162}