Skip to content

Commit 596b47d

Browse files
Merge branch 'main' into rbac-registration-improvements
2 parents 8287bc0 + 78dfbba commit 596b47d

File tree

19 files changed

+776
-344
lines changed

19 files changed

+776
-344
lines changed

rust/catalyst-types/src/uuid/mod.rs

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
//! `UUID` types.
22
3+
#[allow(clippy::module_name_repetitions)]
4+
pub use uuid_v4::UuidV4;
5+
#[allow(clippy::module_name_repetitions)]
6+
pub use uuid_v7::UuidV7;
7+
38
mod uuid_v4;
49
mod uuid_v7;
510

611
use minicbor::data::Tag;
7-
pub use uuid_v4::UuidV4 as V4;
8-
pub use uuid_v7::UuidV7 as V7;
912

1013
/// Invalid Doc Type UUID
1114
pub const INVALID_UUID: uuid::Uuid = uuid::Uuid::from_bytes([0x00; 16]);
@@ -14,6 +17,19 @@ pub const INVALID_UUID: uuid::Uuid = uuid::Uuid::from_bytes([0x00; 16]);
1417
#[allow(dead_code)]
1518
const UUID_CBOR_TAG: u64 = 37;
1619

20+
/// Uuid validation errors, which could occur during decoding or converting to
21+
/// `UuidV4` or `UuidV7` types.
22+
#[derive(Debug, Clone, thiserror::Error)]
23+
#[allow(clippy::module_name_repetitions)]
24+
pub enum UuidError {
25+
/// `UUIDv4` invalid error
26+
#[error("'{0}' is not a valid UUIDv4")]
27+
InvalidUuidV4(uuid::Uuid),
28+
/// `UUIDv7` invalid error
29+
#[error("'{0}' is not a valid UUIDv7")]
30+
InvalidUuidV7(uuid::Uuid),
31+
}
32+
1733
/// Context for `CBOR` encoding and decoding
1834
pub enum CborContext {
1935
/// Untagged bytes
@@ -77,30 +93,52 @@ fn encode_cbor_uuid<W: minicbor::encode::Write>(
7793
#[cfg(test)]
7894
mod tests {
7995

80-
use super::{V4, V7};
96+
use super::*;
8197
use crate::uuid::CborContext;
8298

8399
#[test]
84100
fn test_cbor_uuid_v4_roundtrip() {
85-
let uuid: V4 = uuid::Uuid::new_v4().into();
101+
let uuid = UuidV4::new();
86102
let mut bytes = Vec::new();
87103
minicbor::encode_with(uuid, &mut bytes, &mut CborContext::Untagged).unwrap();
88104
let decoded = minicbor::decode_with(bytes.as_slice(), &mut CborContext::Untagged).unwrap();
89105
assert_eq!(uuid, decoded);
90106
}
91107

108+
#[test]
109+
fn test_cbor_uuid_v4_invalid_decoding() {
110+
let uuid_v7 = UuidV7::new();
111+
let mut bytes = Vec::new();
112+
minicbor::encode_with(uuid_v7, &mut bytes, &mut CborContext::Untagged).unwrap();
113+
assert!(
114+
minicbor::decode_with::<_, UuidV4>(bytes.as_slice(), &mut CborContext::Untagged)
115+
.is_err()
116+
);
117+
}
118+
92119
#[test]
93120
fn test_cbor_uuid_v7_roundtrip() {
94-
let uuid: V7 = uuid::Uuid::now_v7().into();
121+
let uuid = UuidV7::new();
95122
let mut bytes = Vec::new();
96123
minicbor::encode_with(uuid, &mut bytes, &mut CborContext::Untagged).unwrap();
97124
let decoded = minicbor::decode_with(bytes.as_slice(), &mut CborContext::Untagged).unwrap();
98125
assert_eq!(uuid, decoded);
99126
}
100127

128+
#[test]
129+
fn test_cbor_uuid_v7_invalid_decoding() {
130+
let uuid_v4 = UuidV4::new();
131+
let mut bytes = Vec::new();
132+
minicbor::encode_with(uuid_v4, &mut bytes, &mut CborContext::Untagged).unwrap();
133+
assert!(
134+
minicbor::decode_with::<_, UuidV7>(bytes.as_slice(), &mut CborContext::Untagged)
135+
.is_err()
136+
);
137+
}
138+
101139
#[test]
102140
fn test_tagged_cbor_uuid_v4_roundtrip() {
103-
let uuid: V4 = uuid::Uuid::new_v4().into();
141+
let uuid = UuidV4::new();
104142
let mut bytes = Vec::new();
105143
minicbor::encode_with(uuid, &mut bytes, &mut CborContext::Tagged).unwrap();
106144
let decoded = minicbor::decode_with(bytes.as_slice(), &mut CborContext::Tagged).unwrap();
@@ -109,7 +147,7 @@ mod tests {
109147

110148
#[test]
111149
fn test_tagged_cbor_uuid_v7_roundtrip() {
112-
let uuid: V7 = uuid::Uuid::now_v7().into();
150+
let uuid = UuidV7::new();
113151
let mut bytes = Vec::new();
114152
minicbor::encode_with(uuid, &mut bytes, &mut CborContext::Tagged).unwrap();
115153
let decoded = minicbor::decode_with(bytes.as_slice(), &mut CborContext::Tagged).unwrap();
@@ -118,7 +156,7 @@ mod tests {
118156

119157
#[test]
120158
fn test_optional_cbor_uuid_v4_roundtrip() {
121-
let uuid: V4 = uuid::Uuid::new_v4().into();
159+
let uuid = UuidV4::new();
122160

123161
let mut bytes = Vec::new();
124162
minicbor::encode_with(uuid, &mut bytes, &mut CborContext::Untagged).unwrap();
@@ -133,7 +171,7 @@ mod tests {
133171

134172
#[test]
135173
fn test_optional_cbor_uuid_v7_roundtrip() {
136-
let uuid: V7 = uuid::Uuid::now_v7().into();
174+
let uuid = UuidV7::new();
137175

138176
let mut bytes = Vec::new();
139177
minicbor::encode_with(uuid, &mut bytes, &mut CborContext::Untagged).unwrap();

rust/catalyst-types/src/uuid/uuid_v4.rs

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,51 +2,65 @@
22
use std::fmt::{Display, Formatter};
33

44
use minicbor::{Decode, Decoder, Encode};
5+
use uuid::Uuid;
56

6-
use super::{decode_cbor_uuid, encode_cbor_uuid, CborContext, INVALID_UUID};
7+
use super::{decode_cbor_uuid, encode_cbor_uuid, CborContext, UuidError, INVALID_UUID};
78

89
/// Type representing a `UUIDv4`.
9-
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)]
10-
#[serde(from = "uuid::Uuid")]
11-
#[serde(into = "uuid::Uuid")]
12-
pub struct UuidV4 {
13-
/// UUID
14-
uuid: uuid::Uuid,
15-
}
10+
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, serde::Serialize)]
11+
pub struct UuidV4(Uuid);
1612

1713
impl UuidV4 {
1814
/// Version for `UUIDv4`.
1915
const UUID_VERSION_NUMBER: usize = 4;
2016

17+
/// Generates a random `UUIDv4`.
18+
#[must_use]
19+
#[allow(clippy::new_without_default)]
20+
pub fn new() -> Self {
21+
Self(Uuid::new_v4())
22+
}
23+
2124
/// Generates a zeroed out `UUIDv4` that can never be valid.
2225
#[must_use]
2326
pub fn invalid() -> Self {
24-
Self { uuid: INVALID_UUID }
27+
Self(INVALID_UUID)
2528
}
2629

2730
/// Check if this is a valid `UUIDv4`.
2831
#[must_use]
2932
pub fn is_valid(&self) -> bool {
30-
self.uuid != INVALID_UUID && self.uuid.get_version_num() == Self::UUID_VERSION_NUMBER
33+
is_valid(&self.uuid())
3134
}
3235

3336
/// Returns the `uuid::Uuid` type.
3437
#[must_use]
35-
pub fn uuid(&self) -> uuid::Uuid {
36-
self.uuid
38+
pub fn uuid(&self) -> Uuid {
39+
self.0
3740
}
3841
}
3942

43+
/// Check if this is a valid `UUIDv4`.
44+
fn is_valid(uuid: &Uuid) -> bool {
45+
uuid != &INVALID_UUID && uuid.get_version_num() == UuidV4::UUID_VERSION_NUMBER
46+
}
47+
4048
impl Display for UuidV4 {
4149
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
42-
write!(f, "{}", self.uuid)
50+
write!(f, "{}", self.0)
4351
}
4452
}
4553

4654
impl Decode<'_, CborContext> for UuidV4 {
4755
fn decode(d: &mut Decoder<'_>, ctx: &mut CborContext) -> Result<Self, minicbor::decode::Error> {
4856
let uuid = decode_cbor_uuid(d, ctx)?;
49-
Ok(Self { uuid })
57+
if is_valid(&uuid) {
58+
Ok(Self(uuid))
59+
} else {
60+
Err(minicbor::decode::Error::message(UuidError::InvalidUuidV4(
61+
uuid,
62+
)))
63+
}
5064
}
5165
}
5266

@@ -59,27 +73,41 @@ impl Encode<CborContext> for UuidV4 {
5973
}
6074

6175
/// Returns a `UUIDv4` from `uuid::Uuid`.
62-
///
63-
/// NOTE: This does not guarantee that the `UUID` is valid.
64-
impl From<uuid::Uuid> for UuidV4 {
65-
fn from(uuid: uuid::Uuid) -> Self {
66-
Self { uuid }
76+
impl TryFrom<Uuid> for UuidV4 {
77+
type Error = UuidError;
78+
79+
fn try_from(uuid: Uuid) -> Result<Self, Self::Error> {
80+
if is_valid(&uuid) {
81+
Ok(Self(uuid))
82+
} else {
83+
Err(UuidError::InvalidUuidV4(uuid))
84+
}
6785
}
6886
}
6987

7088
/// Returns a `uuid::Uuid` from `UUIDv4`.
7189
///
7290
/// NOTE: This does not guarantee that the `UUID` is valid.
73-
impl From<UuidV4> for uuid::Uuid {
91+
impl From<UuidV4> for Uuid {
7492
fn from(value: UuidV4) -> Self {
75-
value.uuid
93+
value.0
94+
}
95+
}
96+
97+
impl<'de> serde::Deserialize<'de> for UuidV4 {
98+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
99+
where D: serde::Deserializer<'de> {
100+
let uuid = Uuid::deserialize(deserializer)?;
101+
if is_valid(&uuid) {
102+
Ok(Self(uuid))
103+
} else {
104+
Err(serde::de::Error::custom(UuidError::InvalidUuidV4(uuid)))
105+
}
76106
}
77107
}
78108

79109
#[cfg(test)]
80110
mod tests {
81-
use uuid::Uuid;
82-
83111
use super::*;
84112

85113
#[test]
@@ -95,15 +123,17 @@ mod tests {
95123

96124
#[test]
97125
fn test_valid_uuid() {
98-
let valid_uuid = UuidV4::from(Uuid::new_v4());
126+
let valid_uuid = UuidV4::try_from(Uuid::new_v4()).unwrap();
127+
assert!(valid_uuid.is_valid(), "Valid UUID should be valid");
128+
129+
let valid_uuid = UuidV4::new();
99130
assert!(valid_uuid.is_valid(), "Valid UUID should be valid");
100131
}
101132

102133
#[test]
103134
fn test_invalid_version_uuid() {
104-
let invalid_version_uuid = UuidV4::from(Uuid::from_u128(0));
105135
assert!(
106-
!invalid_version_uuid.is_valid(),
136+
UuidV4::try_from(INVALID_UUID).is_err(),
107137
"Zero UUID should not be valid"
108138
);
109139
}

0 commit comments

Comments
 (0)