Skip to main content

kasane_logic/spatial_id/range_id/
random.rs

1use crate::RangeId;
2
3#[cfg(any(test))]
4use proptest::prelude::Strategy;
5#[cfg(any(test, feature = "random"))]
6use rand::Rng;
7#[cfg(any(test, feature = "random"))]
8use std::ops::RangeInclusive;
9
10impl RangeId {
11    #[cfg(any(test, feature = "random"))]
12    fn pick_zoom_using<R: Rng>(rng: &mut R, z_range: RangeInclusive<u8>) -> u8 {
13        use crate::MAX_ZOOM_LEVEL;
14
15        let start = *z_range.start();
16        let end = (*z_range.end()).min(MAX_ZOOM_LEVEL as u8);
17
18        if start > end {
19            end
20        } else {
21            rng.random_range(start..=end)
22        }
23    }
24
25    /// 外部から渡された乱数生成器を使って、全ズーム範囲からランダムな [`RangeId`] を生成します。
26    #[cfg(any(test, feature = "random"))]
27    pub fn random_using<R: Rng>(rng: &mut R) -> Self {
28        use crate::MAX_ZOOM_LEVEL;
29
30        Self::random_within_using(rng, 0..=MAX_ZOOM_LEVEL as u8)
31    }
32
33    /// 外部から渡された乱数生成器を使用して、指定したズームレベルでランダムにRangeIdを生成
34    #[cfg(any(test, feature = "random"))]
35    pub fn random_at_using<R: Rng>(rng: &mut R, z: u8) -> Self {
36        Self::random_within_using(rng, z..=z)
37    }
38
39    /// 外部から渡された乱数生成器を使用して、指定したズームレベル範囲内でランダムにRangeIdを生成
40    #[cfg(any(test, feature = "random"))]
41    pub fn random_within_using<R: Rng>(rng: &mut R, z_range: RangeInclusive<u8>) -> Self {
42        use crate::{F_MAX, F_MIN, XY_MAX};
43
44        let z = Self::pick_zoom_using(rng, z_range);
45        let z_idx = z as usize;
46
47        let f_min = F_MIN[z_idx];
48        let f_max = F_MAX[z_idx];
49        let xy_max = XY_MAX[z_idx];
50
51        // 範囲の両端をランダムに生成
52        let f1 = rng.random_range(f_min..=f_max);
53        let f2 = rng.random_range(f_min..=f_max);
54
55        let x1 = rng.random_range(0..=xy_max);
56        let x2 = rng.random_range(0..=xy_max);
57
58        let y1 = rng.random_range(0..=xy_max);
59        let y2 = rng.random_range(0..=xy_max);
60
61        // RangeId::new 内部で min/max の入れ替え等は処理される前提
62        RangeId::new(z, [f1, f2], [x1, x2], [y1, y2])
63            .expect("Generated parameters should be always valid")
64    }
65
66    /// 全空間(Z=0〜MAX)からランダムにRangeIdを生成
67    #[cfg(any(test, feature = "random"))]
68    pub fn random() -> Self {
69        let mut rng = rand::rng();
70        Self::random_using(&mut rng)
71    }
72
73    /// 指定したズームレベルでランダムにRangeIdを生成
74    #[cfg(any(test, feature = "random"))]
75    pub fn random_at(z: u8) -> Self {
76        let mut rng = rand::rng();
77        Self::random_at_using(&mut rng, z)
78    }
79
80    /// 指定ズーム範囲からランダムな [`RangeId`] を生成します。
81    ///
82    /// 内部で `rand::rng()` を作って [`random_within_using`](Self::random_within_using) に委譲します。
83    #[cfg(any(test, feature = "random"))]
84    pub fn random_within(z_range: RangeInclusive<u8>) -> Self {
85        let mut rng = rand::rng();
86        Self::random_within_using(&mut rng, z_range)
87    }
88
89    /// `proptest` 用に、全ズーム範囲から [`RangeId`] を生成する戦略を返します。
90    #[cfg(any(test))]
91    pub fn arb() -> impl Strategy<Value = Self> {
92        use crate::MAX_ZOOM_LEVEL;
93
94        Self::arb_within(0..=MAX_ZOOM_LEVEL as u8)
95    }
96
97    /// `proptest` 用に、指定ズームの [`RangeId`] を生成する戦略を返します。
98    #[cfg(any(test))]
99    pub fn arb_at(z: u8) -> impl Strategy<Value = Self> {
100        Self::arb_within(z..=z)
101    }
102
103    /// `proptest` 用に、指定ズーム範囲の [`RangeId`] を生成する戦略を返します。
104    ///
105    /// `z_range` の終端は `MAX_ZOOM_LEVEL` でクリップされ、`start > end` の場合は `end` のみを使います。
106    #[cfg(any(test))]
107    pub fn arb_within(z_range: RangeInclusive<u8>) -> impl Strategy<Value = Self> {
108        use crate::MAX_ZOOM_LEVEL;
109
110        let start = *z_range.start();
111        let end = (*z_range.end()).min(MAX_ZOOM_LEVEL as u8);
112        let (start, end) = if start > end {
113            (end, end)
114        } else {
115            (start, end)
116        };
117
118        (start..=end).prop_flat_map(|z| {
119            use proptest::prelude::Just;
120
121            use crate::{F_MAX, F_MIN, XY_MAX};
122
123            let z_idx = z as usize;
124
125            let f_min = F_MIN[z_idx];
126            let f_max = F_MAX[z_idx];
127            let xy_max = XY_MAX[z_idx];
128
129            let f_strat = (f_min..=f_max, f_min..=f_max);
130            let x_strat = (0..=xy_max, 0..=xy_max);
131            let y_strat = (0..=xy_max, 0..=xy_max);
132
133            (Just(z), f_strat, x_strat, y_strat).prop_map(
134                move |(z, (f1, f2), (x1, x2), (y1, y2))| {
135                    RangeId::new(z, [f1, f2], [x1, x2], [y1, y2])
136                        .expect("Generated parameters should be always valid")
137                },
138            )
139        })
140    }
141}