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>);