Skip to content

Commit 21fda58

Browse files
committed
feat: uuid
1 parent 8b0607e commit 21fda58

File tree

5 files changed

+166
-0
lines changed

5 files changed

+166
-0
lines changed

rust/catalyst-types/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ name = "catalyst_types"
1818
[dependencies]
1919
anyhow = "1.0.95"
2020
blake2b_simd = "1.0.2"
21+
coset = "0.3.8"
2122
ed25519-dalek = "2.1.1"
2223
hex = "0.4.3"
2324
minicbor = { version = "0.25.1", features = ["std"] }
2425
num-traits = "0.2.19"
2526
orx-concurrent-vec = "3.1.0"
2627
pallas-crypto = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" }
2728
serde = { version = "1.0.217", features = ["derive"] }
29+
uuid = { version = "1.11.0", features = ["v4", "v7", "serde"] }

rust/catalyst-types/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
pub mod conversion;
44
pub mod hashes;
55
pub mod problem_report;
6+
pub mod uuid;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//! `UUID` types.
2+
3+
mod uuid_v4;
4+
mod uuid_v7;
5+
6+
pub use uuid_v4::UuidV4;
7+
pub use uuid_v7::UuidV7;
8+
9+
/// Invalid Doc Type UUID
10+
pub const INVALID_UUID: uuid::Uuid = uuid::Uuid::from_bytes([0x00; 16]);
11+
12+
/// CBOR tag for UUID content.
13+
const UUID_CBOR_TAG: u64 = 37;
14+
15+
/// Decode `CBOR` encoded `UUID`.
16+
pub fn decode_cbor_uuid(val: &coset::cbor::Value) -> anyhow::Result<uuid::Uuid> {
17+
let Some((UUID_CBOR_TAG, coset::cbor::Value::Bytes(bytes))) = val.as_tag() else {
18+
anyhow::bail!("Invalid CBOR encoded UUID type");
19+
};
20+
let uuid = uuid::Uuid::from_bytes(
21+
bytes
22+
.clone()
23+
.try_into()
24+
.map_err(|_| anyhow::anyhow!("Invalid CBOR encoded UUID type, invalid bytes size"))?,
25+
);
26+
Ok(uuid)
27+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//! `UUIDv4` Type.
2+
use std::fmt::{Display, Formatter};
3+
4+
use super::{decode_cbor_uuid, INVALID_UUID};
5+
6+
/// Type representing a `UUIDv4`.
7+
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, serde::Deserialize)]
8+
#[serde(from = "uuid::Uuid")]
9+
pub struct UuidV4 {
10+
/// UUID
11+
uuid: uuid::Uuid,
12+
}
13+
14+
impl UuidV4 {
15+
/// Version for `UUIDv4`.
16+
const UUID_VERSION_NUMBER: usize = 4;
17+
18+
/// Generates a zeroed out `UUIDv4` that can never be valid.
19+
pub fn invalid() -> Self {
20+
Self { uuid: INVALID_UUID }
21+
}
22+
23+
/// Check if this is a valid `UUIDv4`.
24+
pub fn is_valid(&self) -> bool {
25+
self.uuid != INVALID_UUID && self.uuid.get_version_num() == Self::UUID_VERSION_NUMBER
26+
}
27+
28+
/// Returns the `uuid::Uuid` type.
29+
#[must_use]
30+
pub fn uuid(&self) -> uuid::Uuid {
31+
self.uuid
32+
}
33+
}
34+
35+
impl Display for UuidV4 {
36+
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
37+
write!(f, "{}", self.uuid)
38+
}
39+
}
40+
41+
impl TryFrom<&coset::cbor::Value> for UuidV4 {
42+
type Error = anyhow::Error;
43+
44+
fn try_from(cbor_value: &coset::cbor::Value) -> Result<Self, Self::Error> {
45+
match decode_cbor_uuid(cbor_value) {
46+
Ok(uuid) => {
47+
if uuid.get_version_num() == Self::UUID_VERSION_NUMBER {
48+
Ok(Self { uuid })
49+
} else {
50+
anyhow::bail!("UUID {uuid} is not `v{}`", Self::UUID_VERSION_NUMBER);
51+
}
52+
},
53+
Err(e) => {
54+
anyhow::bail!("Invalid UUID. Error: {e}");
55+
},
56+
}
57+
}
58+
}
59+
60+
/// Returns a `UUIDv4` from `uuid::Uuid`.
61+
///
62+
/// NOTE: This does not guarantee that the `UUID` is valid.
63+
impl From<uuid::Uuid> for UuidV4 {
64+
fn from(uuid: uuid::Uuid) -> Self {
65+
Self { uuid }
66+
}
67+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//! `UUIDv7` Type.
2+
use std::fmt::{Display, Formatter};
3+
4+
use super::{decode_cbor_uuid, INVALID_UUID};
5+
6+
/// Type representing a `UUIDv7`.
7+
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, serde::Deserialize)]
8+
#[serde(from = "uuid::Uuid")]
9+
pub struct UuidV7 {
10+
/// UUID
11+
uuid: uuid::Uuid,
12+
}
13+
14+
impl UuidV7 {
15+
/// Version for `UUIDv7`.
16+
const UUID_VERSION_NUMBER: usize = 7;
17+
18+
/// Generates a zeroed out `UUIDv7` that can never be valid.
19+
#[must_use]
20+
pub fn invalid() -> Self {
21+
Self { uuid: INVALID_UUID }
22+
}
23+
24+
/// Check if this is a valid `UUIDv7`.
25+
#[must_use]
26+
pub fn is_valid(&self) -> bool {
27+
self.uuid != INVALID_UUID && self.uuid.get_version_num() == Self::UUID_VERSION_NUMBER
28+
}
29+
30+
/// Returns the `uuid::Uuid` type.
31+
#[must_use]
32+
pub fn uuid(&self) -> uuid::Uuid {
33+
self.uuid
34+
}
35+
}
36+
37+
impl Display for UuidV7 {
38+
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
39+
write!(f, "{}", self.uuid)
40+
}
41+
}
42+
43+
impl TryFrom<&coset::cbor::Value> for UuidV7 {
44+
type Error = anyhow::Error;
45+
46+
fn try_from(cbor_value: &coset::cbor::Value) -> Result<Self, Self::Error> {
47+
match decode_cbor_uuid(cbor_value) {
48+
Ok(uuid) => {
49+
if uuid.get_version_num() == Self::UUID_VERSION_NUMBER {
50+
Ok(Self { uuid })
51+
} else {
52+
anyhow::bail!("UUID {uuid} is not `v{}`", Self::UUID_VERSION_NUMBER);
53+
}
54+
},
55+
Err(e) => {
56+
anyhow::bail!("Invalid UUID. Error: {e}");
57+
},
58+
}
59+
}
60+
}
61+
62+
/// Returns a `UUIDv7` from `uuid::Uuid`.
63+
///
64+
/// NOTE: This does not guarantee that the `UUID` is valid.
65+
impl From<uuid::Uuid> for UuidV7 {
66+
fn from(uuid: uuid::Uuid) -> Self {
67+
Self { uuid }
68+
}
69+
}

0 commit comments

Comments
 (0)