Skip to main content

mediaframe/arbitrary_impls/
coded.rs

1// Cluster B — the FFmpeg-coded name vocabularies, colour / pixel-format /
2// frame geometry / disposition structs, frame coded enums.
3
4use super::{arb_via_code, arb_via_named_variants};
5
6// Bitflags: uniform `u32` produces reasonable flag combinations directly,
7// and every bit pattern is meaningful — keep `TrackDisposition` on raw u32.
8arb_via_code!(crate::disposition::TrackDisposition);
9
10// The colour / frame / pixel-format vocabularies are open string enums now:
11// `Other(SmolStr)` is their escape, so they generate the same way the codec
12// family does — a curated slug, or an arbitrary string, both routed through
13// `FromStr` so every generated value is canonical. The old numeric
14// generators (`arb_via_code_weighted*`) existed to reach `Unknown(u32)`,
15// which no longer exists.
16//
17// Curated slugs are drawn from each type's own `as_str()` table, favouring
18// values a real file carries; `Matrix::Bt601` is included deliberately —
19// it is the one mediaframe-domain variant, and the numeric generator used
20// to reach it roughly one draw in 8.6 billion.
21super::arb_open_string_enum!(
22  crate::color::Matrix,
23  [
24    "bt709",
25    "bt601",
26    "bt470bg",
27    "smpte170m",
28    "bt2020nc",
29    "unspecified"
30  ]
31);
32super::arb_open_string_enum!(
33  crate::color::Primaries,
34  [
35    "bt709",
36    "bt470bg",
37    "smpte170m",
38    "bt2020",
39    "smpte431",
40    "unspecified"
41  ]
42);
43super::arb_open_string_enum!(
44  crate::color::Transfer,
45  [
46    "bt709",
47    "smpte170m",
48    "iec61966-2-1",
49    "smpte2084",
50    "arib-std-b67",
51    "unspecified"
52  ]
53);
54super::arb_open_string_enum!(crate::color::DynamicRange, ["tv", "pc", "unspecified"]);
55super::arb_open_string_enum!(
56  crate::color::ChromaLocation,
57  [
58    "left",
59    "center",
60    "topleft",
61    "top",
62    "bottomleft",
63    "unspecified"
64  ]
65);
66super::arb_open_string_enum!(
67  crate::color::DcpTargetGamut,
68  ["dci-p3", "rec709", "rec2020"]
69);
70super::arb_open_string_enum!(
71  crate::pixel_format::PixelFormat,
72  ["yuv420p", "yuv422p10le", "nv12", "rgb24", "rgba", "p010le"]
73);
74super::arb_open_string_enum!(crate::frame::Rotation, ["0", "90", "180", "270"]);
75super::arb_open_string_enum!(
76  crate::frame::FieldOrder,
77  ["unknown", "progressive", "tt", "bb", "tb", "bt"]
78);
79super::arb_open_string_enum!(
80  crate::frame::StereoMode,
81  [
82    "mono",
83    "side-by-side",
84    "top-bottom",
85    "frame-sequence",
86    "checkerboard",
87    "lines"
88  ]
89);
90
91// Strictly closed coded enums (no escape arm at all — an unrecognised
92// code has nowhere to go). Uniform u32 would skew to the default; pick
93// uniformly from the named variants instead.
94arb_via_named_variants!(crate::audio::BitRateMode, [Cbr, Vbr, Abr]);
95arb_via_named_variants!(
96  crate::audio::ChannelOrder,
97  [Unspecified, Native, Custom, Ambisonic]
98);
99
100// ─── colour structs ──────────────────────────────────────────────────────────
101
102impl<'a> ::arbitrary::Arbitrary<'a> for crate::color::Info {
103  fn arbitrary(u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
104    Ok(Self::new(
105      crate::color::Primaries::arbitrary(u)?,
106      crate::color::Transfer::arbitrary(u)?,
107      crate::color::Matrix::arbitrary(u)?,
108      crate::color::DynamicRange::arbitrary(u)?,
109      crate::color::ChromaLocation::arbitrary(u)?,
110    ))
111  }
112}
113
114impl<'a> ::arbitrary::Arbitrary<'a> for crate::color::ContentLightLevel {
115  fn arbitrary(u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
116    Ok(Self::new(u32::arbitrary(u)?, u32::arbitrary(u)?))
117  }
118}
119
120impl<'a> ::arbitrary::Arbitrary<'a> for crate::color::ChromaCoord {
121  fn arbitrary(u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
122    Ok(Self::new(u32::arbitrary(u)?, u32::arbitrary(u)?))
123  }
124}
125
126impl<'a> ::arbitrary::Arbitrary<'a> for crate::color::MasteringDisplay {
127  fn arbitrary(u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
128    let primaries = [
129      crate::color::ChromaCoord::arbitrary(u)?,
130      crate::color::ChromaCoord::arbitrary(u)?,
131      crate::color::ChromaCoord::arbitrary(u)?,
132    ];
133    let white_point = crate::color::ChromaCoord::arbitrary(u)?;
134    Ok(Self::new(
135      primaries,
136      white_point,
137      u32::arbitrary(u)?,
138      u32::arbitrary(u)?,
139    ))
140  }
141}
142
143impl<'a> ::arbitrary::Arbitrary<'a> for crate::color::HdrStaticMetadata {
144  fn arbitrary(u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
145    Ok(Self::new(
146      <Option<crate::color::MasteringDisplay> as ::arbitrary::Arbitrary>::arbitrary(u)?,
147      <Option<crate::color::ContentLightLevel> as ::arbitrary::Arbitrary>::arbitrary(u)?,
148    ))
149  }
150}
151
152impl<'a> ::arbitrary::Arbitrary<'a> for crate::color::DolbyVisionConfig {
153  fn arbitrary(u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
154    Ok(Self::new(
155      u8::arbitrary(u)?,
156      u8::arbitrary(u)?,
157      bool::arbitrary(u)?,
158      bool::arbitrary(u)?,
159      u8::arbitrary(u)?,
160    ))
161  }
162}
163
164// ─── frame structs ───────────────────────────────────────────────────────────
165
166impl<'a> ::arbitrary::Arbitrary<'a> for crate::frame::Dimensions {
167  fn arbitrary(u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
168    Ok(Self::new(u32::arbitrary(u)?, u32::arbitrary(u)?))
169  }
170}
171
172impl<'a> ::arbitrary::Arbitrary<'a> for crate::frame::Rect {
173  fn arbitrary(u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
174    Ok(Self::new(
175      u32::arbitrary(u)?,
176      u32::arbitrary(u)?,
177      u32::arbitrary(u)?,
178      u32::arbitrary(u)?,
179    ))
180  }
181}
182
183/// Draws a `Rational` numerator / denominator pair inside the range
184/// [`crate::frame::Rational::new`] accepts.
185///
186/// `NonZeroI64::arbitrary` covers the whole non-zero `i64` range, half
187/// of which is negative and would trip the constructor's assert — a
188/// generator must not be able to panic the type it generates. Folding
189/// an unsigned draw into `0..=i64::MAX` (and `1..=i64::MAX` for the
190/// denominator) keeps every draw legal by construction rather than by
191/// rejection, so no input byte is ever wasted retrying.
192fn parts(
193  u: &mut ::arbitrary::Unstructured<'_>,
194) -> ::arbitrary::Result<(i64, core::num::NonZeroI64)> {
195  #[allow(clippy::cast_possible_wrap)] // masked to 63 bits: always non-negative
196  let num = (<u64 as ::arbitrary::Arbitrary>::arbitrary(u)? >> 1) as i64;
197  #[allow(clippy::cast_possible_wrap)]
198  let den = ((<u64 as ::arbitrary::Arbitrary>::arbitrary(u)? >> 1) as i64).max(1);
199  let den = core::num::NonZeroI64::new(den).unwrap_or(crate::frame::DEN_ONE);
200  Ok((num, den))
201}
202
203impl<'a> ::arbitrary::Arbitrary<'a> for crate::frame::Rational {
204  fn arbitrary(u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
205    let (num, den) = parts(u)?;
206    Ok(Self::new(num, den))
207  }
208}
209
210impl<'a> ::arbitrary::Arbitrary<'a> for crate::frame::SampleAspectRatio {
211  fn arbitrary(u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
212    let (num, den) = parts(u)?;
213    Ok(Self::new(num, den))
214  }
215}
216
217impl<'a> ::arbitrary::Arbitrary<'a> for crate::frame::FrameRate {
218  fn arbitrary(u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
219    Ok(Self::new(
220      crate::frame::Rational::arbitrary(u)?,
221      bool::arbitrary(u)?,
222    ))
223  }
224}
225
226// ─── bayer / RAW development ─────────────────────────────────────────────────
227//
228// Closed vocabularies: pick uniformly from the named variants. The two
229// float structs generate through `try_new`, so every value is valid by
230// construction — an `f32` drawn raw is NaN or ±inf often enough that a
231// field-wise generator would spend most of its draws on values the
232// constructor refuses.
233
234#[cfg(feature = "bayer")]
235arb_via_named_variants!(crate::frame::BayerPattern, [Rggb, Bggr, Grbg, Gbrg]);
236#[cfg(feature = "bayer")]
237arb_via_named_variants!(crate::frame::BayerDemosaic, [Bilinear]);
238#[cfg(feature = "bayer")]
239arb_via_named_variants!(crate::frame::WbChannel, [R, G, B]);
240
241#[cfg(feature = "bayer")]
242impl<'a> ::arbitrary::Arbitrary<'a> for crate::frame::WhiteBalance {
243  fn arbitrary(u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
244    // Gains are finite and non-negative by the type's invariant; `0.0` is
245    // legal (zeroes the channel) so the range is closed at the bottom.
246    let gain = |u: &mut ::arbitrary::Unstructured<'a>| -> ::arbitrary::Result<f32> {
247      Ok(u.int_in_range(0u32..=8_000)? as f32 / 1_000.0)
248    };
249    let (r, g, b) = (gain(u)?, gain(u)?, gain(u)?);
250    crate::frame::WhiteBalance::try_new(r, g, b).map_err(|_| ::arbitrary::Error::IncorrectFormat)
251  }
252}
253
254#[cfg(feature = "bayer")]
255impl<'a> ::arbitrary::Arbitrary<'a> for crate::frame::ColorCorrectionMatrix {
256  fn arbitrary(u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
257    // Real CCMs are O(1-5) and regularly negative (they subtract
258    // crosstalk); stay well inside `MAX_COEFFICIENT_ABS`.
259    let mut m = [[0.0f32; 3]; 3];
260    for row in &mut m {
261      for cell in row {
262        *cell = u.int_in_range(-8_000i32..=8_000)? as f32 / 1_000.0;
263      }
264    }
265    crate::frame::ColorCorrectionMatrix::try_new(m).map_err(|_| ::arbitrary::Error::IncorrectFormat)
266  }
267}