Skip to content

Commit c9a384c

Browse files
committed
Various API improvements and instrumentation
1 parent c5258b4 commit c9a384c

File tree

4 files changed

+108
-46
lines changed

4 files changed

+108
-46
lines changed

src/cbor.rs

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,6 @@ impl Equivalent<HashableCborValue> for HashableCborValueRef<'_> {
7171
}
7272
}
7373

74-
#[derive(Debug, Error)]
75-
pub enum DateTimeParseError {
76-
#[error("Invalid CBOR type")]
77-
InvalidCborType,
78-
#[error("Invalid format: {0}")]
79-
Format(#[from] chrono::ParseError),
80-
}
81-
8274
#[derive(Clone, Debug, PartialEq, Default)]
8375
pub struct Map(IndexMap<HashableCborValue, Value>);
8476

@@ -103,38 +95,16 @@ impl Map {
10395
self.0.shift_remove(&HashableCborValueRef(key))
10496
}
10597

106-
pub fn get_date_time(
107-
&self,
108-
key: impl Into<Value>,
109-
) -> std::result::Result<Option<DateTime<FixedOffset>>, DateTimeParseError> {
110-
let Some(value) = self.get(key) else {
111-
return Ok(None);
112-
};
113-
let string = match value {
114-
Value::Tag(tag, deref!(Value::Text(string)))
115-
if *tag == iana::CborTag::DateTime as u64 =>
116-
{
117-
string
118-
}
119-
Value::Text(string) => string,
120-
_ => return Err(DateTimeParseError::InvalidCborType),
121-
};
122-
let date_time = DateTime::parse_from_rfc3339(string)?;
123-
124-
Ok(Some(date_time))
98+
pub fn get_date_time(&self, key: impl Into<Value>) -> Option<DateTime<FixedOffset>> {
99+
self.get(key)?.as_datetime()
125100
}
126101

127102
pub fn insert_date_time<Tz: TimeZone>(
128103
&mut self,
129104
key: impl Into<Value>,
130105
date_time: DateTime<Tz>,
131106
) -> Option<Value> {
132-
let string = date_time.to_rfc3339();
133-
let value = Value::Tag(
134-
iana::CborTag::DateTime as u64,
135-
Box::new(Value::Text(string)),
136-
);
137-
self.insert(key, value)
107+
self.insert(key, Value::new_datetime(&date_time))
138108
}
139109

140110
pub fn iter(&self) -> impl Iterator<Item = (&HashableCborValue, &Value)> {
@@ -258,7 +228,7 @@ where
258228
// }
259229
// }
260230

261-
pub(crate) mod iana {
231+
pub mod iana {
262232
#[repr(u64)]
263233
pub enum CborTag {
264234
DateTime = 0,
@@ -327,9 +297,16 @@ pub(crate) mod iana {
327297
// }
328298
// }
329299

330-
pub trait ValueExt {
300+
pub trait ValueExt
301+
where
302+
Self: Sized,
303+
{
331304
fn canonicalize(&mut self);
332305
fn is_canonical(&self) -> bool;
306+
fn new_datetime(datetime: &DateTime<impl TimeZone>) -> Self;
307+
fn is_datetime(&self) -> bool;
308+
fn as_datetime(&self) -> Option<DateTime<FixedOffset>>;
309+
fn into_datetime(self) -> ::std::result::Result<DateTime<FixedOffset>, Self>;
333310
}
334311

335312
impl ValueExt for Value {
@@ -385,6 +362,35 @@ impl ValueExt for Value {
385362
_ => panic!("Unsupported CBOR type."),
386363
}
387364
}
365+
366+
fn new_datetime(datetime: &DateTime<impl TimeZone>) -> Self {
367+
Value::Tag(
368+
iana::CborTag::DateTime as u64,
369+
Box::new(Value::Text(datetime.to_rfc3339())),
370+
)
371+
}
372+
373+
fn is_datetime(&self) -> bool {
374+
self.as_datetime().is_some()
375+
}
376+
377+
fn as_datetime(&self) -> Option<DateTime<FixedOffset>> {
378+
let string = match self {
379+
Value::Tag(tag, deref!(Value::Text(string)))
380+
if *tag == iana::CborTag::DateTime as u64 =>
381+
{
382+
string
383+
}
384+
_ => return None,
385+
};
386+
let date_time = DateTime::parse_from_rfc3339(string).ok()?;
387+
388+
Some(date_time)
389+
}
390+
391+
fn into_datetime(self) -> ::std::result::Result<DateTime<FixedOffset>, Self> {
392+
self.as_datetime().ok_or(self)
393+
}
388394
}
389395

390396
pub struct AsCanonicalValue<T>(pub PhantomData<T>);

src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#![feature(array_windows)]
2-
#![feature(async_closure)]
32
#![feature(deref_patterns)]
43
#![feature(fn_traits)]
54
#![feature(try_blocks)]

src/record/mod.rs

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::cbor::{self, DateTimeParseError, TAG_RRR_RECORD};
1+
use crate::cbor::{self, TAG_RRR_RECORD};
22
use crate::crypto::encryption::EncryptionAlgorithm;
33
use crate::crypto::signature::SigningKey;
44
use crate::error::{Error, IoResultExt, Result};
@@ -8,6 +8,7 @@ use crate::utils::serde::{BytesOrAscii, BytesOrHexString, Secret};
88
use async_fd_lock::LockWrite;
99
use chrono::{DateTime, FixedOffset, TimeZone};
1010
use coset::cbor::tag;
11+
use coset::cbor::value::Integer;
1112
use derive_more::{Deref, DerefMut};
1213
use futures::{pin_mut, Stream, StreamExt};
1314
use itertools::Itertools;
@@ -21,6 +22,7 @@ use segment::{
2122
RecordVersion, Segment, SegmentEncryption, SegmentMetadata,
2223
};
2324
use serde::{Deserialize, Serialize};
25+
use std::fmt::Display;
2426
use std::iter;
2527
use std::ops::{Deref, DerefMut};
2628
use std::{borrow::Cow, fmt::Debug, io::Cursor};
@@ -54,28 +56,78 @@ impl DerefMut for SuccessionNonce {
5456
}
5557
}
5658

59+
#[repr(u64)]
60+
pub enum RecordMetadataId {
61+
CreatedAt = 1,
62+
}
63+
64+
impl Display for RecordMetadataId {
65+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66+
match self {
67+
Self::CreatedAt => write!(f, "Created At"),
68+
}
69+
}
70+
}
71+
72+
impl TryFrom<&Integer> for RecordMetadataId {
73+
type Error = ();
74+
75+
fn try_from(value: &Integer) -> std::result::Result<Self, ()> {
76+
// Consider using the `num_enum` crate if this becomes cumbersome.
77+
let value: u64 = value.clone().try_into().map_err(|_| ())?;
78+
Ok(match value {
79+
_ if value == Self::CreatedAt as u64 => Self::CreatedAt,
80+
_ => return Err(()),
81+
})
82+
}
83+
}
84+
85+
impl TryFrom<&cbor::Value> for RecordMetadataId {
86+
type Error = ();
87+
88+
fn try_from(value: &cbor::Value) -> std::result::Result<Self, ()> {
89+
let integer = value.as_integer().ok_or(())?;
90+
91+
Self::try_from(&integer)
92+
}
93+
}
94+
95+
pub enum RecordMetadataKey<'a> {
96+
Id(RecordMetadataId),
97+
Custom(cbor::HashableCborValueRef<'a>),
98+
}
99+
57100
/// A CBOR map of metadata.
58101
#[derive(Clone, Debug, Default, Deref, DerefMut, PartialEq, Serialize, Deserialize)]
59102
pub struct RecordMetadata(pub cbor::Map);
60103

61104
impl RecordMetadata {
62-
pub const KEY_CREATED_AT: u64 = 1;
63-
64-
pub fn get_created_at(
65-
&self,
66-
) -> std::result::Result<Option<DateTime<FixedOffset>>, DateTimeParseError> {
67-
self.get_date_time(Self::KEY_CREATED_AT)
105+
pub fn get_created_at(&self) -> Option<DateTime<FixedOffset>> {
106+
self.get_date_time(RecordMetadataId::CreatedAt as u64)
68107
}
69108

70109
pub fn insert_created_at<Tz: TimeZone>(
71110
&mut self,
72111
date_time: DateTime<Tz>,
73112
) -> Option<cbor::Value> {
74-
self.insert_date_time(Self::KEY_CREATED_AT, date_time)
113+
self.insert_date_time(RecordMetadataId::CreatedAt as u64, date_time)
75114
}
76115

77116
pub fn shift_remove_created_at(&mut self) -> Option<cbor::Value> {
78-
self.shift_remove(Self::KEY_CREATED_AT)
117+
self.shift_remove(RecordMetadataId::CreatedAt as u64)
118+
}
119+
120+
pub fn iter_with_semantic_keys<'a>(
121+
&'a self,
122+
) -> impl Iterator<Item = (RecordMetadataKey<'a>, &'a cbor::Value)> {
123+
self.iter()
124+
.map(|(key, value)| match RecordMetadataId::try_from(&key.0) {
125+
Ok(id) => (RecordMetadataKey::Id(id), value),
126+
Err(()) => (
127+
RecordMetadataKey::Custom(cbor::HashableCborValueRef(&key.0)),
128+
value,
129+
),
130+
})
79131
}
80132
}
81133

@@ -343,6 +395,7 @@ impl Record {
343395
}
344396
}
345397

398+
/// Returns the available record versions, sorted from least to most recent.
346399
#[instrument(level = Level::TRACE, ret, err)]
347400
pub async fn list_versions<L>(
348401
registry: &Registry<L>,

src/registry.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use tokio::{
3535
io::{AsyncRead, AsyncWrite},
3636
};
3737
use tokio_util::io::SyncIoBridge;
38-
use tracing::warn;
38+
use tracing::{info, instrument, warn};
3939

4040
pub const BYTES_HASH_PEPPER_RECOMMENDED: usize = 32;
4141

@@ -578,6 +578,7 @@ impl<L: FileLock> PartialEq for Registry<L> {
578578
}
579579

580580
impl Registry<ReadLock> {
581+
#[instrument]
581582
pub async fn open(directory_path: PathBuf) -> Result<Self> {
582583
let open_options = {
583584
let mut open_options = File::options();
@@ -595,6 +596,7 @@ impl Registry<ReadLock> {
595596
})
596597
}
597598

599+
#[instrument]
598600
pub async fn lock_write(self) -> Result<Registry<WriteLock>> {
599601
let open_options = {
600602
let mut open_options = File::options();
@@ -616,6 +618,7 @@ impl Registry<ReadLock> {
616618
}
617619

618620
impl Registry<WriteLock> {
621+
#[instrument]
619622
pub async fn create(
620623
directory_path: PathBuf,
621624
config: RegistryConfig,
@@ -683,6 +686,7 @@ impl Registry<WriteLock> {
683686
.await
684687
}
685688

689+
#[instrument]
686690
pub async fn lock_read(self) -> Result<Registry<ReadLock>> {
687691
let open_options = {
688692
let mut open_options = File::options();

0 commit comments

Comments
 (0)