Skip to main content

ehds_logging/
sink.rs

1// SPDX-FileCopyrightText: Cadasto B.V.
2// SPDX-License-Identifier: BUSL-1.1
3
4//! Where access records go: a store the deployment reviews them in, or a
5//! connection to external software that does (Regulation (EU) 2025/327
6//! Annex II 3.3).
7//!
8//! [`AccessSink::store`] returns once the record is stored. A sink that
9//! cannot store a record says so, and the caller decides what an access
10//! without its record means; the sink never alters the access.
11//!
12//! An access that changes data cannot be taken back once it is made, so its
13//! caller asks [`AccessSink::reserve`] for the record's place first and makes
14//! the access only once the sink has one: a sink with no room refuses the
15//! access before it happens, and the [`Reservation`] is filled with the
16//! record of how the access ended.
17
18use crate::record::AccessRecord;
19
20/// A store of access records.
21#[async_trait::async_trait]
22pub trait AccessSink: Send + Sync {
23    /// Stores `record`.
24    ///
25    /// # Errors
26    ///
27    /// A [`SinkError`] when the record cannot be stored.
28    async fn store(&self, record: AccessRecord) -> Result<(), SinkError>;
29
30    /// Takes the place of one record before the access it records is made.
31    ///
32    /// The place is held until the [`Reservation`] is filled or dropped, so
33    /// two accesses never both take a sink's last place.
34    ///
35    /// # Errors
36    ///
37    /// A [`SinkError`] when the sink has no room for one more record.
38    async fn reserve(&self) -> Result<Box<dyn Reservation>, SinkError>;
39}
40
41/// The place of one record a sink took before its access was made; dropped
42/// unfilled, it gives the place back.
43#[async_trait::async_trait]
44pub trait Reservation: Send + std::fmt::Debug {
45    /// Stores `record` in this place.
46    ///
47    /// # Errors
48    ///
49    /// A [`SinkError`] when the record cannot be stored even so: it could
50    /// not be written, or not within the sink's bound.
51    async fn store(self: Box<Self>, record: AccessRecord) -> Result<(), SinkError>;
52}
53
54/// Why a sink could not store a record.
55#[derive(Debug, thiserror::Error)]
56#[error("the access record could not be stored")]
57pub struct SinkError(#[source] pub Box<dyn std::error::Error + Send + Sync>);