Skip to main content

vitaminc_protected/
as_protected_ref.rs

1use crate::Controlled;
2use std::borrow::Cow;
3
4/// Trait for types that can be converted to a `ProtectedRef`.
5/// Conceptually similar to the `AsRef` trait in `std` but for `Protected` types.
6/// This prevents the inner value from being accessed directly.
7/// The trait is sealed so it cannot be implemented outside of this crate.
8///
9/// # Implementing `AsProtectedRef`
10///
11/// Implementing `AsProtectedRef` for a type allows it to be used in functions that take a `ProtectedRef`.
12/// Note, that such implementations must be defined on inner types that already implement `AsProtectedRef`
13/// because `ProtectedRef` cannot be constructed from the inner type directly.
14///
15/// ```
16/// # mod vitaminc { pub mod protected { pub use vitaminc_protected::*; } }
17/// use vitaminc::protected::{AsProtectedRef, Protected, ProtectedRef};
18///
19/// pub struct SensitiveData(Protected<Vec<u8>>);
20///
21/// impl AsProtectedRef<'_, Vec<u8>> for SensitiveData {
22///    fn as_protected_ref(&self) -> ProtectedRef<Vec<u8>> {
23///       self.0.as_protected_ref()
24///   }
25/// }
26///
27/// let data = SensitiveData(Protected::new(Vec::new()));
28/// let pref: ProtectedRef<Vec<u8>> = data.as_protected_ref();
29/// ```
30///
31pub trait AsProtectedRef<'a, A: ?Sized> {
32    fn as_protected_ref(&'a self) -> ProtectedRef<'a, A>;
33}
34
35impl<'a, T> AsProtectedRef<'a, <T as Controlled>::Inner> for T
36where
37    //<T as ControlledPrivate>::Inner: AsRef<A>,
38    T: Controlled,
39{
40    fn as_protected_ref(&'a self) -> ProtectedRef<'a, <T as Controlled>::Inner> {
41        ProtectedRef(self.risky_ref())
42    }
43}
44
45impl<'a, const N: usize> AsProtectedRef<'a, [u8; N]> for [u8; N] {
46    fn as_protected_ref(&'a self) -> ProtectedRef<'a, [u8; N]> {
47        ProtectedRef(self)
48    }
49}
50
51// TODO: This is only really needed for compatability (so that types not using this API don't have to be moved).
52// It might make sense to put this behind a feature flag.
53/// String references cannot be zeroized, so we can't implement `Zeroize` for `Protected<&str>`.
54/// Instead, we implement `AsProtectedRef` to allow the use of string references in functions that take them.
55impl<'a> AsProtectedRef<'a, [u8]> for str {
56    fn as_protected_ref(&'a self) -> ProtectedRef<'a, [u8]> {
57        ProtectedRef(self.as_bytes())
58    }
59}
60
61impl<'a> AsProtectedRef<'a, [u8]> for Cow<'a, str> {
62    fn as_protected_ref(&'a self) -> ProtectedRef<'a, [u8]> {
63        ProtectedRef(self.as_bytes())
64    }
65}
66
67/// A wrapper around a reference to prevent inner access.
68/// Conceptually similar to `&T` but prevents direct access to the inner value outside of this crate.
69pub struct ProtectedRef<'a, T>(&'a T)
70where
71    T: ?Sized;
72
73impl<'a, T: ?Sized> ProtectedRef<'a, T> {
74    pub(crate) fn inner_ref(&self) -> &T {
75        self.0
76    }
77}