Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 11 additions & 2 deletions benzina/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@ repository.workspace = true
rust-version.workspace = true

[package.metadata.docs.rs]
features = ["postgres", "mysql", "serde", "typed-uuid", "example-generated"]
features = [
"postgres",
"mysql",
"serde",
"typed-uuid",
"example-generated",
"dangerous-construction",
]
rustdoc-args = ["--cfg", "docsrs"]

[dependencies]
Expand All @@ -21,7 +28,8 @@ benzina-derive = { path = "../benzina-derive", version = "=0.3.3", optional = tr
uuid = { version = ">=0.7.0, <2.0.0", default-features = false, optional = true }

[dev-dependencies]
serde_test = "1"
serde_test = "1"
uuid = { version = ">=0.7.0, <2.0.0", default-features = false, features = ["v4"] }

[features]
default = ["derive"]
Expand All @@ -35,6 +43,7 @@ serde = ["dep:serde", "uuid?/serde"]
utoipa = ["dep:utoipa"]

example-generated = ["typed-uuid"]
dangerous-construction = ["typed-uuid"]

[lints]
workspace = true
32 changes: 30 additions & 2 deletions benzina/src/typed_uuid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/// generates code which implements many useful traits, including the ones needed to work with
/// [`diesel`].
///
/// The generated structs do not expose any method or trait to create an arbitrary instance, in
/// The generated structs do not expose any method or trait to create an arbitrary instance[^See note], in
/// order to provide the guarantee that the `UUID` is valid. However, it is possible to choose to
/// add traits and methods to customize the behavior.
///
Expand Down Expand Up @@ -48,7 +48,7 @@
/// }
/// ```
///
/// Keep in mind that there is no way to construct an instance unless the instantiation is done
/// Keep in mind that there is no way[^See note] to construct an instance unless the instantiation is done
/// inside the module containing the new type or a submodule of it:
///
/// ```compile_fail,E0603
Expand All @@ -62,6 +62,12 @@
/// let foo = inner::Foo(Uuid::default());
/// // ^^^ private tuple struct constructor
/// ```
///
/// [^See note]: There is no way in normal usage to construct an instance. The exception is with the
/// `dangerous_new` method, which is gated behind the `dangerous-construction` feature and intended
/// for special cases (including testing). If the `dangerous-construction` feature is enabled, it is
/// recommended to use [`clippy::disallowed_methods`](https://rust-lang.github.io/rust-clippy/stable/index.html#disallowed_methods) to prevent the usage of `dangerous_new` outside
/// of the desired situations.
#[macro_export]
macro_rules! typed_uuid {
(
Expand All @@ -85,6 +91,15 @@ macro_rules! typed_uuid {
$vis struct $name($crate::__private::uuid::Uuid);

impl $name {
/// Creates a new typed [`Uuid`] which does not come from the database.
///
/// [`Uuid`]: $crate::__private::uuid::Uuid
#[must_use]
#[cfg(feature = "dangerous-construction")]
pub fn dangerous_new(inner: $crate::__private::uuid::Uuid) -> Self {
Self(inner)
}

/// Gets the actual [`Uuid`].
///
/// [`Uuid`]: $crate::__private::uuid::Uuid
Expand Down Expand Up @@ -361,3 +376,16 @@ macro_rules! __typed_uuid__impl_serde {
macro_rules! __typed_uuid__impl_serde {
($name:ident) => {};
}

#[cfg(test)]
mod test {
use uuid::Uuid;

#[test]
fn creates_new_typed_uuid() {
crate::typed_uuid!(pub FooId);
let inner = Uuid::new_v4();
let new = FooId::dangerous_new(inner);
assert_eq!(new.get(), inner);
}
}