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}