Skip to main content

ic_canister_kit/number/
random.rs

1//! 生成随机数
2
3use crate::canister::types::CanisterCallResult;
4
5/// 得到随机数
6/// https://internetcomputer.org/docs/current/references/ic-interface-spec/#ic-raw_rand
7#[inline]
8pub async fn random() -> CanisterCallResult<[u8; 32]> {
9    let call_result = ic_cdk_management_canister::raw_rand().await;
10
11    let random = call_result.map_err(|err| crate::canister::types::CanisterCallError {
12        canister_id: crate::identity::CanisterId::management_canister(),
13        method: "ic#raw_rand".to_string(),
14        message: err.to_string(),
15    })?;
16
17    let mut data = [0; 32];
18
19    data[..32].copy_from_slice(&random[..32]);
20
21    Ok(data)
22}
23
24// ============= 节省生成随机数的时间 =============
25
26// 如果每次只需要使用指定数量的随机数, 通过下面的方式节省随机数
27
28/// 随机数生产对象
29#[derive(Debug)]
30pub struct RandomGenerator {
31    random: [u8; 32],
32    current: u8,
33}
34
35impl RandomGenerator {
36    /// 构建对象
37    pub fn new() -> Self {
38        RandomGenerator {
39            random: [0; 32],
40            current: 32,
41        }
42    }
43    /// 下一组随机数
44    pub async fn next(&mut self, number: usize) -> CanisterCallResult<Vec<u8>> {
45        let mut data = Vec::with_capacity(number);
46        let mut remain = number;
47
48        // 如果大于 32,就直接随机一个
49        while remain > 32 {
50            data.extend_from_slice(&random().await?);
51            remain -= 32;
52        }
53
54        let available = 32 - self.current as usize;
55        if remain <= available {
56            let current = self.current as usize;
57            data.extend_from_slice(&self.random[current..current + remain]);
58            self.current += remain as u8;
59        } else {
60            // 剩下的全加入
61            let current = self.current as usize;
62            data.extend_from_slice(&self.random[current..current + available]);
63            remain -= available;
64
65            // 随机新的一组
66            self.random = random().await?;
67            self.current = 0;
68
69            // 取出剩下的个数
70            data.extend_from_slice(&self.random[0..remain]);
71            self.current += remain as u8;
72        }
73
74        Ok(data)
75    }
76}
77
78impl Default for RandomGenerator {
79    fn default() -> Self {
80        Self::new()
81    }
82}