rand_compat/
lib.rs

1//! A compatibility layer for `rand` and `rand_core` providing adaptation between traits for each version
2//!
3//! ## Forward compatibility (using `rand/std` for `rand_0_7::OsRng`)
4//!
5#![cfg_attr(not(feature = "std"), doc = "```ignore")]
6#![cfg_attr(feature = "std", doc = "```")]
7//! use rand_0_7::rngs::OsRng;
8//! use rand_core_0_6::{RngCore, CryptoRng};
9//! use rand_compat::ForwardCompat;
10//!
11//! // RngCore + CryptoRng from rand_core@0.6.x
12//! fn something<R: RngCore + CryptoRng>(r: &mut R) -> u32 {
13//!     r.next_u32()
14//! }
15//!
16//! let mut rng = OsRng;    // OsRng from rand@0.7.x (rand_core@0.5.x)
17//!
18//! let n = something(&mut rng.forward());
19//! ```
20//!
21//! ## Backward compatibility (using `rand/std` for `rand_0_8::OsRng`)
22//!
23#![cfg_attr(not(feature = "std"), doc = "```ignore")]
24#![cfg_attr(feature = "std", doc = "```")]
25//! use rand_0_8::rngs::OsRng;
26//! use rand_core_0_5::{RngCore, CryptoRng};
27//! use rand_compat::BackwardCompat;
28//!
29//! // RngCore + CryptoRng from rand_core@0.5.x
30//! fn something<R: RngCore + CryptoRng>(r: &mut R) -> u32 {
31//!     r.next_u32()
32//! }
33//!
34//! let mut rng = OsRng;    // OsRng from rand@0.8.x (rand_core@0.6.x)
35//!
36//! let n = something(&mut rng.backward());
37//! ```
38//!
39
40#![cfg_attr(not(feature = "std"), no_std)]
41
42use core::fmt::Debug;
43
44/// Re-export of rand_core@0.5.x
45pub use rand_core_0_5;
46
47/// Re-export of rand_core@0.6.x
48pub use rand_core_0_6;
49
50/// Re-export of rand@0.7.x
51pub use rand_0_7;
52
53/// Re-export of rand@0.8.x
54pub use rand_0_8;
55
56/// Forward compatibility container object
57#[derive(Debug, Clone, PartialEq)]
58#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59pub struct Forward<T>(pub T);
60
61/// Helper trait to convert a type for forward compatibility
62pub trait ForwardCompat<T> {
63    fn forward(self) -> Forward<T>;
64}
65
66impl<T: rand_core_0_5::RngCore> ForwardCompat<T> for T {
67    /// Call `.forward()` on an 0.5.x [`rand_core_0_5::RngCore`] to receive a 0.6.x [`rand_core_0_6::RngCore`] compatible instance
68    fn forward(self) -> Forward<T> {
69        Forward(self)
70    }
71}
72
73/// Implementation of [`rand_core_0_6::RngCore`] for forward compatibility
74impl<T: rand_core_0_5::RngCore> rand_core_0_6::RngCore for Forward<T> {
75    fn next_u32(&mut self) -> u32 {
76        self.0.next_u32()
77    }
78
79    fn next_u64(&mut self) -> u64 {
80        self.0.next_u64()
81    }
82
83    fn fill_bytes(&mut self, dest: &mut [u8]) {
84        self.0.fill_bytes(dest)
85    }
86
87    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_0_6::Error> {
88        // Attempt to fill bytes
89        let e = match self.0.try_fill_bytes(dest) {
90            Ok(_) => return Ok(()),
91            Err(e) => e,
92        };
93
94        // Map errors via code if available
95        if let Some(c) = e.code() {
96            return Err(rand_core_0_6::Error::from(c));
97        }
98
99        // Otherwise we have to return an unknown error
100        let c = unsafe { core::num::NonZeroU32::new_unchecked(getrandom::Error::CUSTOM_START) };
101        Err(rand_core_0_6::Error::from(c))
102    }
103}
104
105/// Forward [`rand_core_0_6::CryptoRng`] marker for [`rand_core_0_5::CryptoRng`] types
106impl<T: rand_core_0_5::RngCore + rand_core_0_5::CryptoRng> rand_core_0_6::CryptoRng
107    for Forward<T>
108{
109}
110
111/// Backward compatibility container object
112#[derive(Debug, Clone, PartialEq)]
113#[cfg_attr(feature = "defmt", derive(defmt::Format))]
114pub struct Backward<T>(pub T);
115
116/// Convert a type into a forward compatibility wrapper object
117pub trait BackwardCompat<T> {
118    fn backward(self) -> Backward<T>;
119}
120
121impl<T: rand_core_0_6::RngCore> BackwardCompat<T> for T {
122    /// Call `.backward()` on an 0.6.x [`rand_core_0_6::RngCore`] to receive a 0.5.x [`rand_core_0_5::RngCore`] compatible instance
123    fn backward(self) -> Backward<T> {
124        Backward(self)
125    }
126}
127
128/// Implementation of [`rand_core_0_5::RngCore`] for backward compatibility
129impl<T: rand_core_0_6::RngCore> rand_core_0_5::RngCore for Backward<T> {
130    fn next_u32(&mut self) -> u32 {
131        self.0.next_u32()
132    }
133
134    fn next_u64(&mut self) -> u64 {
135        self.0.next_u64()
136    }
137
138    fn fill_bytes(&mut self, dest: &mut [u8]) {
139        self.0.fill_bytes(dest)
140    }
141
142    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_0_5::Error> {
143        // Attempt to fill bytes
144        let e = match self.0.try_fill_bytes(dest) {
145            Ok(_) => return Ok(()),
146            Err(e) => e,
147        };
148
149        // Map errors via code if available
150        if let Some(c) = e.code() {
151            return Err(rand_core_0_5::Error::from(c));
152        }
153
154        // Otherwise we have to return an unknown error
155        let c = unsafe { core::num::NonZeroU32::new_unchecked(getrandom::Error::CUSTOM_START) };
156        Err(rand_core_0_5::Error::from(c))
157    }
158}
159
160/// Backward [`rand_core_0_5::CryptoRng`] marker for [`rand_core_0_6::CryptoRng`] types
161impl<T: rand_core_0_6::RngCore + rand_core_0_6::CryptoRng> rand_core_0_5::CryptoRng
162    for Backward<T>
163{
164}
165
166#[cfg(test)]
167mod tests {
168    #[test]
169    fn it_works() {
170        let result = 2 + 2;
171        assert_eq!(result, 4);
172    }
173}