Skip to content

Commit

Permalink
feat: impl Deref and DerefMut without exposing Secret
Browse files Browse the repository at this point in the history
I'm not sure what the usecase for this is.
Originally I thought it was required for #58 but I was wrong.

It was fun implementing this with a bit of unsafe but I don't know if I'll merge it.
  • Loading branch information
eopb committed Sep 4, 2024
1 parent 931019c commit fc770d7
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ serde = ["dep:serde"]
zeroize = ["dep:zeroize"]

[dependencies]
bytemuck = { version = "1.15", default-features = false }
fake = { version = "2.5", optional = true, default-features = false }
rand = { version = "0.8", optional = true, default-features = false }
serde = { version = "1.0", optional = true, default-features = false }
Expand Down
1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#![doc = include_str!("../README.md")]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![cfg_attr(not(feature = "std"), no_std)]
#![forbid(unsafe_code)]

#[cfg(feature = "std")]
mod error;
Expand Down
37 changes: 36 additions & 1 deletion src/ops.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::Secret;

use core::ops;
use core::{
ops,
ops::{Deref, DerefMut},
};

macro_rules! ops {
{ ($type:tt, $trait:ident, $method:ident), $($tt:tt)* } => {
Expand Down Expand Up @@ -69,3 +72,35 @@ ops! {
(unary, Neg, neg),
(unary, Not, not),
}

use bytemuck::TransparentWrapper;

/// We introduce this private wrapper around `Secret` to safely implement [TransparentWrapper] without
/// inadvertently providing a way for `Secret`s to be exposed without using `Secret::expose_secret`
#[repr(transparent)]
struct Wrapper<T: ?Sized>(Secret<T>);

// SAFETY: `Secret` and `Wrapper` both contains only a single field and are `#[repr(transparent)]`.
// This meets the documented requirements [bytemuck::TransparentWrapper] as long as we
// do not override any of its methods.
unsafe impl<T: ?Sized> bytemuck::TransparentWrapper<T> for Wrapper<T> {}

impl<T> Deref for Secret<T>
where
T: Deref,
{
type Target = Secret<T::Target>;

fn deref(&self) -> &Self::Target {
&Wrapper::wrap_ref(self.0.deref()).0
}
}

impl<T> DerefMut for Secret<T>
where
T: DerefMut,
{
fn deref_mut(&mut self) -> &mut Secret<T::Target> {
&mut Wrapper::wrap_mut(self.0.deref_mut()).0
}
}

0 comments on commit fc770d7

Please sign in to comment.