Skip to main content

rustymath_core/
buffer.rs

1//! Compact buffers: owned items of one element type, borrowed views of them, and the [`DType`] that names each. Booleans take one byte each. Integers come in four widths, floats in three and complex numbers in two, named by the width of their parts. [`Source`] reads an item of one element type as another.
2use crate::error::{Error, Kind};
3use num_complex::{Complex32, Complex64};
4use std::borrow::Cow;
5
6/// Declares the owned buffers `$owned`, their borrowed view `$view` and the width `$tag` that names a variant, with one variant for each element type, which fills with `$fill`. `$outer` is the family's variant in `Buffer` and `View`, and `$widest` its widest type, which `widened` reads every width as. Code that needs a variant's element type matches on the variant, as `with_ints!` does.
7macro_rules! buffers {
8    ($owned:ident, $view:ident, $tag:ident, $outer:ident, $kind:ident, $widest:ty: $($variant:ident($t:ty = $fill:expr)),+) => {
9        #[derive(Clone, Debug)]
10        pub enum $owned { $($variant(Vec<$t>)),+ }
11        #[derive(Clone, Copy, Debug)]
12        pub enum $view<'a> { $($variant(&'a [$t])),+ }
13        #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
14        pub enum $tag { $($variant),+ }
15        impl $owned {
16            pub fn with_capacity(tag: $tag, capacity: usize) -> Self { match tag { $($tag::$variant => Self::$variant(Vec::with_capacity(capacity))),+ } }
17            #[inline]
18            pub fn view(&self) -> $view<'_> { match self { $(Self::$variant(v) => $view::$variant(v)),+ } }
19            #[inline]
20            pub fn capacity(&self) -> usize { match self { $(Self::$variant(v) => v.capacity()),+ } }
21            #[inline]
22            pub fn as_mut_ptr(&mut self) -> *mut u8 { match self { $(Self::$variant(v) => v.as_mut_ptr().cast()),+ } }
23            /// Sets the length to `n` after a writer outside Rust, such as compiled code, filled the first `n` items through `as_mut_ptr`.
24            ///
25            /// # Safety
26            /// `n` is at most the capacity, and the first `n` items are initialized.
27            #[inline]
28            pub unsafe fn set_len(&mut self, n: usize) { match self { $(Self::$variant(v) => unsafe { v.set_len(n) }),+ } }
29            /// Copies `range` of `source` when it has this buffer's element type, and gives whether it could.
30            pub fn extend_from(&mut self, source: $view<'_>, range: std::ops::Range<usize>) -> bool {
31                match (self, source) {
32                    $((Self::$variant(d), $view::$variant(s)) => d.extend_from_slice(&s[range]),)+
33                    #[allow(unreachable_patterns)]
34                    _ => return false,
35                }
36                true
37            }
38        }
39        impl $view<'_> {
40            #[inline]
41            pub fn len(self) -> usize { match self { $(Self::$variant(v) => v.len()),+ } }
42            #[inline]
43            pub fn is_empty(self) -> bool { self.len() == 0 }
44            #[inline]
45            pub fn as_ptr(self) -> *const u8 { match self { $(Self::$variant(v) => v.as_ptr().cast()),+ } }
46            #[inline]
47            pub fn tag(self) -> $tag { match self { $(Self::$variant(_) => $tag::$variant),+ } }
48        }
49        impl<'a> $view<'a> {
50            /// The items at the widest width, borrowed when they have it. A narrower item converts exactly.
51            pub fn widened(self) -> Cow<'a, [$widest]> {
52                match self { $(Self::$variant(v) => Source::<$widest>::borrowed(v).map_or_else(|| Cow::Owned(read_all(v)), Cow::Borrowed)),+ }
53            }
54        }
55        // Views are equal when they hold the same values, whatever their widths. A float NaN equals nothing, as in IEEE.
56        impl PartialEq for $view<'_> {
57            fn eq(&self, other: &Self) -> bool {
58                match (*self, *other) { $((Self::$variant(x), Self::$variant(y)) => x == y,)+ (x, y) => x.widened() == y.widened() }
59            }
60        }
61        $(impl Element for $t {
62            const FILL: Self = $fill;
63            const DTYPE: DType = DType::$kind($tag::$variant);
64            #[inline]
65            fn of(view: View<'_>) -> Option<&[Self]> { match view { View::$outer($view::$variant(v)) => Some(v), _ => None } }
66            #[inline]
67            fn of_mut(buffer: &mut Buffer) -> Option<&mut [Self]> { match buffer { Buffer::$outer($owned::$variant(v)) => Some(v), _ => None } }
68            #[inline]
69            fn view(items: &[Self]) -> View<'_> { View::$outer($view::$variant(items)) }
70            #[inline]
71            fn buffer(data: Vec<Self>) -> Buffer { Buffer::$outer($owned::$variant(data)) }
72            #[inline]
73            fn vec(buffer: Buffer) -> Option<Vec<Self>> { match buffer { Buffer::$outer($owned::$variant(v)) => Some(v), _ => None } }
74            #[inline]
75            fn vec_mut(buffer: &mut Buffer) -> Option<&mut Vec<Self>> { match buffer { Buffer::$outer($owned::$variant(v)) => Some(v), _ => None } }
76            #[inline]
77            fn truth(b: bool) -> Self { Source::<Self>::read(b) }
78        })+
79    };
80}
81buffers!(IntBuf, Ints, Width, Integers, Integer, i64: U8(u8 = 0), I16(i16 = 0), I32(i32 = 0), I64(i64 = 0));
82// Floats come in three widths, which sort from narrowest to widest. A narrower width takes less memory. The CPU computes each operation on 16-bit floats in f32 and rounds the result, through `half`.
83buffers!(FloatBuf, Floats, FloatWidth, Floats, Float, f64: F16(half::f16 = half::f16::ZERO), F32(f32 = 0.0), F64(f64 = 0.0));
84// Complex numbers come in two widths, named by the width of their parts. A 16-bit float that becomes complex takes 32-bit parts.
85buffers!(ComplexBuf, Complexes, ComplexWidth, Complexes, Complex, Complex64: F32(Complex32 = Complex32::new(0.0, 0.0)), F64(Complex64 = Complex64::new(0.0, 0.0)));
86/// Booleans and characters each have one element type.
87macro_rules! single {
88    ($($t:ty: $variant:ident($dtype:ident) = $fill:expr, $truth:expr),+) => {$(
89        impl Element for $t {
90            const FILL: Self = $fill;
91            const DTYPE: DType = DType::$dtype;
92            #[inline]
93            fn of(view: View<'_>) -> Option<&[Self]> { match view { View::$variant(v) => Some(v), _ => None } }
94            #[inline]
95            fn of_mut(buffer: &mut Buffer) -> Option<&mut [Self]> { match buffer { Buffer::$variant(v) => Some(v), _ => None } }
96            #[inline]
97            fn view(items: &[Self]) -> View<'_> { View::$variant(items) }
98            #[inline]
99            fn buffer(data: Vec<Self>) -> Buffer { Buffer::$variant(data) }
100            #[inline]
101            fn vec(buffer: Buffer) -> Option<Vec<Self>> { match buffer { Buffer::$variant(v) => Some(v), _ => None } }
102            #[inline]
103            fn vec_mut(buffer: &mut Buffer) -> Option<&mut Vec<Self>> { match buffer { Buffer::$variant(v) => Some(v), _ => None } }
104            #[inline]
105            fn truth(b: bool) -> Self { ($truth)(b) }
106        }
107    )+};
108}
109single!(bool: Booleans(Boolean) = false, |b| b, char: Characters(Character) = ' ', |b| if b { '\u{1}' } else { '\0' });
110
111/// The narrowest complex width whose parts hold floats of `width`.
112impl From<FloatWidth> for ComplexWidth {
113    fn from(width: FloatWidth) -> Self { match width { FloatWidth::F64 => Self::F64, FloatWidth::F16 | FloatWidth::F32 => Self::F32 } }
114}
115impl From<ComplexWidth> for FloatWidth {
116    fn from(width: ComplexWidth) -> Self { match width { ComplexWidth::F32 => Self::F32, ComplexWidth::F64 => Self::F64 } }
117}
118
119/// Writes the two dispatch macros of a family of widths from each width's variant name and element type. `$slices` is the family's view and `$widths` its enum of widths, whose variants share names. `$values!(v, |x| body)` runs `body` with `x` bound to the slice that `v` holds. `$types!(w, T => body)` runs `body` with the type `T` standing for the element type of the width `w`. Each expands to one `match` with an arm for each variant. With `kernel` before `v` or `w`, each variant listed before the `;` gives `None`, and `body` runs only for the others, for a caller whose own kernels take no 16-bit floats. rustymath's function objects have 16-bit forms, which compute in 32 bits. `$d` is a `$` token, which the written macros need for their own metavariables. Element types come in brackets as token trees. A type from another crate is written `$ crate::half::f16`, so a caller that doesn't depend on `half` reaches it through rustymath's re-export.
120macro_rules! width_macros {
121    ($d:tt $values:ident: $slices:ident, $types:ident: $widths:ident { $($skip:ident => [$($st:tt)+]),* ; $($kept:ident => [$($kt:tt)+]),+ }) => {
122        #[macro_export]
123        macro_rules! $values {
124            (kernel $d v:expr, |$d x:ident| $d body:expr) => {
125                match $d v {
126                    $($crate::buffer::$slices::$skip(_) => None,)*
127                    $($crate::buffer::$slices::$kept($d x) => $d body,)+
128                }
129            };
130            ($d v:expr, |$d x:ident| $d body:expr) => {
131                match $d v {
132                    $($crate::buffer::$slices::$skip($d x) => $d body,)*
133                    $($crate::buffer::$slices::$kept($d x) => $d body,)+
134                }
135            };
136        }
137        #[macro_export]
138        macro_rules! $types {
139            (kernel $d w:expr, $d t:ident => $d body:expr) => {
140                match $d w {
141                    $($crate::buffer::$widths::$skip => None,)*
142                    $($crate::buffer::$widths::$kept => { type $d t = $($kt)+; $d body })+
143                }
144            };
145            ($d w:expr, $d t:ident => $d body:expr) => {
146                match $d w {
147                    $($crate::buffer::$widths::$skip => { type $d t = $($st)+; $d body })*
148                    $($crate::buffer::$widths::$kept => { type $d t = $($kt)+; $d body })+
149                }
150            };
151        }
152    };
153}
154width_macros!($ with_ints: Ints, with_width: Width { ; U8 => [u8], I16 => [i16], I32 => [i32], I64 => [i64] });
155width_macros!($ with_floats: Floats, with_float_width: FloatWidth { F16 => [$ crate::half::f16]; F32 => [f32], F64 => [f64] });
156width_macros!($ with_complexes: Complexes, with_complex_width: ComplexWidth { ; F32 => [$ crate::num_complex::Complex32], F64 => [$ crate::num_complex::Complex64] });
157
158/// Runs `$body` with `$t` standing for the element type of `$dtype`, a computing dtype that [`DType::inexact`] gives: a 32- or 64-bit float, or a complex number. Any other dtype panics.
159#[macro_export]
160macro_rules! with_inexact {
161    ($dtype:expr, $t:ident => $body:expr) => {
162        match $dtype {
163            $crate::buffer::DType::Float($crate::buffer::FloatWidth::F32) => { type $t = f32; $body }
164            $crate::buffer::DType::Float($crate::buffer::FloatWidth::F64) => { type $t = f64; $body }
165            $crate::buffer::DType::Complex($crate::buffer::ComplexWidth::F32) => { type $t = $crate::num_complex::Complex32; $body }
166            $crate::buffer::DType::Complex($crate::buffer::ComplexWidth::F64) => { type $t = $crate::num_complex::Complex64; $body }
167            _ => panic!("with_inexact! takes a computing dtype that DType::inexact gives"),
168        }
169    };
170}
171
172/// Runs `$body` with `$x` and `$y` bound to the integers of `$a` and `$b` at one width: their own when they share it, and otherwise both widened to 64 bits.
173#[macro_export]
174macro_rules! with_int_pair {
175    ($a:expr, $b:expr, |$x:ident, $y:ident| $body:expr) => {
176        match ($a, $b) {
177            ($crate::buffer::Ints::U8($x), $crate::buffer::Ints::U8($y)) => $body,
178            ($crate::buffer::Ints::I16($x), $crate::buffer::Ints::I16($y)) => $body,
179            ($crate::buffer::Ints::I32($x), $crate::buffer::Ints::I32($y)) => $body,
180            (a, b) => {
181                let (a, b) = (a.widened(), b.widened());
182                let ($x, $y) = (&*a, &*b);
183                $body
184            }
185        }
186    };
187}
188
189impl Width {
190    /// The bytes that one integer of this width takes.
191    #[inline]
192    fn bytes(self) -> usize { with_width!(self, T => std::mem::size_of::<T>()) }
193    #[inline]
194    pub fn holds(self, n: i64) -> bool { with_width!(self, T => T::try_from(n).is_ok()) }
195    /// The narrowest width that holds `min`, `max` and every integer between. Every width holds the empty range, where `min` is above `max`.
196    #[inline]
197    pub fn narrowest<T: Into<i64>>(min: T, max: T) -> Self {
198        let (min, max) = (min.into(), max.into());
199        for w in [Self::U8, Self::I16, Self::I32] { if min > max || w.holds(min) && w.holds(max) { return w; } }
200        Self::I64
201    }
202    /// The narrowest width that holds every position below `bound`.
203    #[inline]
204    pub fn below(bound: usize) -> Self { Self::narrowest(0, bound as i64 - 1) }
205    /// The narrowest width that holds the integers of both widths.
206    #[inline]
207    pub fn join(self, other: Self) -> Self { if self.bytes() >= other.bytes() { self } else { other } }
208    /// The next wider width, if there is one.
209    #[inline]
210    pub fn wider(self) -> Option<Self> {
211        match self { Self::U8 => Some(Self::I16), Self::I16 => Some(Self::I32), Self::I32 => Some(Self::I64), Self::I64 => None }
212    }
213    /// The float width that integers of this width become beside a float, no wider than `limit`. With a `limit` of `f64`, this is NumPy's rule: the narrowest float that holds each of them exactly. That's `f16` for `u8`, `f32` for `i16` and `f64` for `i32`. `i64` also gives `f64`, which holds its integers exactly only up to 2^53. A session whose default float is narrower passes that width as `limit`.
214    #[inline]
215    pub fn float(self, limit: FloatWidth) -> FloatWidth {
216        (match self { Self::U8 => FloatWidth::F16, Self::I16 => FloatWidth::F32, Self::I32 | Self::I64 => FloatWidth::F64 }).min(limit)
217    }
218}
219
220impl FloatWidth {
221    /// The gap between 1 and the next float of this width.
222    pub fn epsilon(self) -> f64 { with_float_width!(self, F => <F as num_traits::Float>::epsilon().into()) }
223    /// The bits of a float of this width.
224    pub fn bits(self) -> i64 { with_float_width!(self, F => 8 * std::mem::size_of::<F>() as i64) }
225    /// The width of floats of `bits` bits.
226    pub fn of_bits(bits: i64) -> Option<Self> { match bits { 16 => Some(Self::F16), 32 => Some(Self::F32), 64 => Some(Self::F64), _ => None } }
227}
228
229impl<'a> Ints<'a> {
230    /// Item `i` as an `i64`.
231    #[inline]
232    pub fn get(self, i: usize) -> i64 { with_ints!(self, |x| x[i].into()) }
233}
234
235impl<'a> Floats<'a> {
236    /// Item `i` as an `f64`, which a narrower float converts to exactly.
237    #[inline]
238    pub fn get(self, i: usize) -> f64 { with_floats!(self, |v| v[i].into()) }
239}
240
241impl<'a> Complexes<'a> {
242    /// Item `i` as a `Complex64`, which a narrower complex number converts to exactly.
243    #[inline]
244    pub fn get(self, i: usize) -> Complex64 { with_complexes!(self, |v| Source::<Complex64>::read(v[i])) }
245}
246impl FloatBuf {
247    /// The floats `values` at `width`, each rounded to it.
248    pub fn collect(width: FloatWidth, values: impl Iterator<Item = f64>) -> Self {
249        match width {
250            FloatWidth::F16 => Self::F16(values.map(Source::read).collect()), FloatWidth::F32 => Self::F32(values.map(Source::read).collect()),
251            FloatWidth::F64 => Self::F64(values.collect())
252        }
253    }
254}
255
256impl ComplexBuf {
257    /// The complex numbers `values` at `width`, each part rounded to it.
258    pub fn collect(width: ComplexWidth, values: impl Iterator<Item = Complex64>) -> Self {
259        match width { ComplexWidth::F32 => Self::F32(values.map(Source::read).collect()), ComplexWidth::F64 => Self::F64(values.collect()) }
260    }
261}
262
263/// The element type of a compact buffer. Numbers widen from Boolean through the integer widths to the float widths to the complex widths.
264#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
265pub enum DType { Boolean, Integer(Width), Float(FloatWidth), Complex(ComplexWidth), Character }
266
267impl DType {
268    /// Whether items of this dtype are whole numbers: Booleans and integers.
269    #[inline]
270    pub fn is_integral(self) -> bool { matches!(self, Self::Boolean | Self::Integer(_)) }
271    /// Whether Mathish forms (`tolerant::MathishFloorDivide` and the rest) apply to a call that computes at this dtype: 64-bit floats and complex numbers with 64-bit parts.
272    #[inline]
273    pub fn mathish(self) -> bool { matches!(self, Self::Float(FloatWidth::F64) | Self::Complex(ComplexWidth::F64)) }
274    /// Whether items of this dtype are real numbers: Booleans, integers and floats.
275    #[inline]
276    pub fn is_real(self) -> bool { matches!(self, Self::Boolean | Self::Integer(_) | Self::Float(_)) }
277    /// This dtype's kind, in the order that NEP 50 promotes kinds: 0 for Booleans, 1 for integers, 2 for floats, 3 for complex numbers and 4 for characters, which don't mix with numbers.
278    pub fn kind(self) -> u8 {
279        match self { Self::Boolean => 0, Self::Integer(_) => 1, Self::Float(_) => 2, Self::Complex(_) => 3, Self::Character => 4 }
280    }
281    /// The dtype's name, as NumPy names its dtypes: `"bool"`, `"uint8"`, `"int16"`, `"int32"`, `"int64"`, `"float16"`, `"float32"`, `"float64"`, `"complex64"` and `"complex128"`. NumPy has no dtype for characters, which are `"character"`. Rustymath's Python API and BPL's `•storage` both use these names.
282    pub fn name(self) -> &'static str {
283        match self {
284            Self::Boolean => "bool", Self::Integer(Width::U8) => "uint8", Self::Integer(Width::I16) => "int16", Self::Integer(Width::I32) => "int32",
285            Self::Integer(Width::I64) => "int64", Self::Float(FloatWidth::F16) => "float16", Self::Float(FloatWidth::F32) => "float32",
286            Self::Float(FloatWidth::F64) => "float64", Self::Complex(ComplexWidth::F32) => "complex64", Self::Complex(ComplexWidth::F64) => "complex128",
287            Self::Character => "character"
288        }
289    }
290    /// The dtype that [`DType::name`] calls `name`, or `None` for any other name.
291    pub fn named(name: &str) -> Option<Self> { Self::ALL.into_iter().find(|d| d.name() == name) }
292    /// Whether this dtype widens to `to`: whether [`DType::common`] promotes this dtype and `to` to `to`. An integer widens to every float and complex dtype.
293    pub fn widens_to(self, to: DType) -> bool { self.common(to) == Some(to) }
294    /// The dtypes that a function of floats or complex numbers computes in and gives, for arguments of this dtype. A Boolean or an integer takes the float that [`Width::float`] gives under `limit`, but at least `f32`, which computes faster than `f16`. Under NumPy's limit, `f64`, that's `f32` for Booleans, `u8` and `i16`, and `f64` for `i32` and `i64`. `f16` computes in `f32`, and its results round back. Other floats and complex numbers stay as they are. `None` for characters.
295    pub fn inexact(self, limit: FloatWidth) -> Option<(DType, DType)> {
296        let at_least_f32 = |w: FloatWidth| { let f = Self::Float(w.max(FloatWidth::F32)); (f, f) };
297        Some(match self {
298            Self::Boolean => at_least_f32(FloatWidth::F16), Self::Integer(w) => at_least_f32(w.float(limit)),
299            Self::Float(FloatWidth::F16) => (Self::Float(FloatWidth::F32), self), Self::Float(_) | Self::Complex(_) => (self, self),
300            Self::Character => return None
301        })
302    }
303    /// The float width that a Boolean or integer computes in under rustymath's own policy, NumPy's: the float that [`DType::inexact`] gives it under `f64`. `f64` for any other dtype.
304    pub fn numpy_float(self) -> FloatWidth { match self.inexact(FloatWidth::F64) { Some((DType::Float(w), _)) => w, _ => FloatWidth::F64 } }
305
306    /// The dtype that an argument of this dtype computes in, for a function with a kernel at each dtype where `has` holds. That's this dtype where it has a kernel. Otherwise it's the first with a kernel of these: for a Boolean or an integer, integers of `int` or of this dtype's width, whichever is wider, then floats of `float`; for a float or a complex number, the dtype that [`DType::inexact`] gives it; then each wider float, and each complex dtype whose parts are at least as wide; and last, for a float, integers of `int`, which compute it as the whole number it holds (`operation::whole_numbers`). `int` and `float` are the caller's policy for exact numbers. NumPy's is `i64` and the float that `inexact` gives under `f64`. `None` where no dtype on the way has a kernel.
307    pub fn computes_in(self, int: Width, float: FloatWidth, has: impl Fn(DType) -> bool) -> Option<DType> {
308        if has(self) { return Some(self); }
309        let (integer, float, whole) = match self {
310            Self::Boolean => (Some(Self::Integer(int)), Self::Float(float), None),
311            Self::Integer(w) => (Some(Self::Integer(w.join(int))), Self::Float(float), None),
312            Self::Float(_) => (None, self.inexact(float)?.0, Some(Self::Integer(int))), _ => (None, self.inexact(float)?.0, None)
313        };
314        integer.into_iter().chain(Self::ALL.into_iter().filter(|&d| float.widens_to(d))).chain(whole).find(|&d| has(d))
315    }
316    /// The dtype that arguments of this dtype and `other` promote to: the higher kind, wide enough for both. A Boolean takes the other dtype. An integer beside a float or complex dtype takes that dtype, as in JAX, where NumPy widens the float to hold every integer exactly. A float beside a complex dtype takes parts at least as wide. `None` for characters beside numbers.
317    pub fn common(self, other: DType) -> Option<DType> {
318        use DType::*;
319        let (low, high) = if self.kind() <= other.kind() { (self, other) } else { (other, self) };
320        Some(match (low, high) {
321            (Character, Character) => Character, (_, Character) => return None, (Boolean, d) | (Integer(_), d @ (Float(_) | Complex(_))) => d,
322            (Integer(a), Integer(b)) => Integer(a.join(b)), (Float(a), Float(b)) => Float(a.max(b)), (Float(f), Complex(c)) => Complex(c.max(f.into())),
323            (Complex(a), Complex(b)) => Complex(a.max(b)), _ => unreachable!("the pair is ordered by kind")
324        })
325    }
326    /// The dtype that NEP 50 promotes an array of this dtype and a weak value of dtype `weak` to. A weak value is a Python scalar, which has no dtype of its own. BPL's weak numbers follow the same rule. The caller gives the weak value's dtype at the default width of its kind. Where its kind is no higher, the array's dtype wins. A weak complex value beside floats takes their width. Otherwise the weak dtype wins. `None` for characters beside numbers.
327    pub fn common_weak(self, weak: DType) -> Option<DType> {
328        use DType::*;
329        Some(match (self, weak) {
330            (Character, Character) => Character, (Character, _) | (_, Character) => return None, (Float(_) | Complex(_), Complex(_)) => self.complex(),
331            _ if weak.kind() > self.kind() => weak, _ => self
332        })
333    }
334    /// The real dtype of a complex dtype's parts. Other dtypes are their own.
335    pub fn real(self) -> DType {
336        match self {
337            Self::Complex(ComplexWidth::F32) => Self::Float(FloatWidth::F32), Self::Complex(ComplexWidth::F64) => Self::Float(FloatWidth::F64), d => d
338        }
339    }
340    /// The complex dtype that numbers of this dtype take: `complex64` for `f16`, `f32` and `complex64`, and `complex128` for everything else.
341    pub fn complex(self) -> DType {
342        Self::Complex(match self {
343            Self::Float(FloatWidth::F16 | FloatWidth::F32) | Self::Complex(ComplexWidth::F32) => ComplexWidth::F32, _ => ComplexWidth::F64
344        })
345    }
346}
347
348/// `element_types!((callback) args)` calls `callback!` with `args`, then a bracketed list of every element type: `name: (dtype) type` for each, in the order that numbers widen, with characters last. Each name is unique. [`DType::ALL`], [`DType::index`] and [`kernels!`](crate::kernels) come from this list, so their orders agree.
349#[doc(hidden)]
350#[macro_export]
351macro_rules! element_types {
352    (($($callback:tt)+) $($args:tt)*) => {
353        $($callback)+! {$($args)* [
354            Boolean: ($crate::buffer::DType::Boolean) bool, U8: ($crate::buffer::DType::Integer($crate::buffer::Width::U8)) u8,
355            I16: ($crate::buffer::DType::Integer($crate::buffer::Width::I16)) i16, I32: ($crate::buffer::DType::Integer($crate::buffer::Width::I32)) i32,
356            I64: ($crate::buffer::DType::Integer($crate::buffer::Width::I64)) i64,
357            F16: ($crate::buffer::DType::Float($crate::buffer::FloatWidth::F16)) $crate::half::f16,
358            F32: ($crate::buffer::DType::Float($crate::buffer::FloatWidth::F32)) f32, F64: ($crate::buffer::DType::Float($crate::buffer::FloatWidth::F64)) f64,
359            C32: ($crate::buffer::DType::Complex($crate::buffer::ComplexWidth::F32)) $crate::num_complex::Complex32,
360            C64: ($crate::buffer::DType::Complex($crate::buffer::ComplexWidth::F64)) $crate::num_complex::Complex64,
361            Character: ($crate::buffer::DType::Character) char
362        ]}
363    };
364}
365
366/// Writes [`DType::ALL`] and [`DType::index`] from the list that [`element_types!`] gives.
367macro_rules! dtypes {
368    ([$($name:ident: ($($d:tt)+) $t:ty),+]) => {
369        impl DType {
370            /// Every dtype, in the order that numbers widen, with characters last.
371            pub const ALL: [DType; [$(stringify!($name)),+].len()] = [$($($d)+),+];
372            /// This dtype's position in [`DType::ALL`].
373            #[inline]
374            pub const fn index(self) -> usize {
375                enum Position { $($name),+ }
376                match self { $($($d)+ => Position::$name as usize),+ }
377            }
378        }
379    };
380}
381element_types!((dtypes));
382
383/// Writes the flat dtype dispatch from the element table, without a second width/type list.
384macro_rules! dtype_macro {
385    ($d:tt [$($name:ident: ($($dtype:tt)+) $t:ty),+]) => {
386        /// Runs the body with its type name standing for the element type of the dtype.
387        #[macro_export]
388        macro_rules! with_dtype {
389            ($d dtype:expr, $d t:ident => $d body:expr) => {
390                match $d dtype { $($($dtype)+ => { type $d t = $t; $d body }),+ }
391            };
392        }
393    };
394}
395element_types!((dtype_macro) $);
396
397impl DType {
398    /// The bytes that one item of this dtype takes.
399    pub fn bytes(self) -> usize { with_dtype!(self, T => std::mem::size_of::<T>()) }
400}
401
402/// Items of one element type.
403#[derive(Clone, Debug)]
404pub enum Buffer { Booleans(Vec<bool>), Integers(IntBuf), Floats(FloatBuf), Complexes(ComplexBuf), Characters(Vec<char>) }
405
406/// A buffer's items, borrowed in their element type.
407#[derive(Clone, Copy, Debug)]
408pub enum View<'a> { Booleans(&'a [bool]), Integers(Ints<'a>), Floats(Floats<'a>), Complexes(Complexes<'a>), Characters(&'a [char]) }
409
410/// Compact items at one dtype, borrowed or prepared by gathering and conversion.
411pub enum Items<'a> { Borrowed(View<'a>), Owned(Buffer) }
412
413impl<'a> Items<'a> {
414    pub fn view(&self) -> View<'_> { match self { Self::Borrowed(v) => *v, Self::Owned(b) => b.view() } }
415    pub fn of<T: Element>(&self) -> &[T] { T::of(self.view()).expect("items at their own element type") }
416    /// Unpacks typed items, without allocating or converting again.
417    pub fn items<T: Element>(self) -> Cow<'a, [T]> {
418        match self {
419            Self::Borrowed(v) => Cow::Borrowed(T::of(v).expect("items at their own element type")),
420            Self::Owned(b) => Cow::Owned(T::vec(b).expect("items at their own element type")),
421        }
422    }
423}
424
425impl Buffer {
426    /// An empty buffer of `dtype`, with room for `capacity` items.
427    pub fn with_capacity(dtype: DType, capacity: usize) -> Self {
428        match dtype {
429            DType::Boolean => Self::Booleans(Vec::with_capacity(capacity)), DType::Integer(width) => Self::Integers(IntBuf::with_capacity(width, capacity)),
430            DType::Float(width) => Self::Floats(FloatBuf::with_capacity(width, capacity)),
431            DType::Complex(width) => Self::Complexes(ComplexBuf::with_capacity(width, capacity)),
432            DType::Character => Self::Characters(Vec::with_capacity(capacity))
433        }
434    }
435    #[inline]
436    pub fn view(&self) -> View<'_> {
437        match self {
438            Self::Booleans(v) => View::Booleans(v), Self::Integers(v) => View::Integers(v.view()), Self::Floats(v) => View::Floats(v.view()),
439            Self::Complexes(v) => View::Complexes(v.view()), Self::Characters(v) => View::Characters(v)
440        }
441    }
442    #[inline]
443    pub fn len(&self) -> usize { self.view().len() }
444    #[inline]
445    pub fn is_empty(&self) -> bool { self.len() == 0 }
446    #[inline]
447    pub fn dtype(&self) -> DType { self.view().dtype() }
448    pub fn capacity(&self) -> usize {
449        match self {
450            Self::Booleans(v) => v.capacity(), Self::Integers(v) => v.capacity(), Self::Floats(v) => v.capacity(), Self::Complexes(v) => v.capacity(),
451            Self::Characters(v) => v.capacity()
452        }
453    }
454    /// Reserve room for `additional` items after the current length.
455    pub fn reserve(&mut self, additional: usize) { with_dtype!(self.dtype(), T => T::vec_mut(self).expect("the buffer has its dtype").reserve(additional)) }
456    /// The address of the first item, for writing through, as an exported buffer may.
457    pub fn as_mut_ptr(&mut self) -> *mut u8 {
458        match self {
459            Self::Booleans(v) => v.as_mut_ptr().cast(), Self::Integers(v) => v.as_mut_ptr(), Self::Floats(v) => v.as_mut_ptr(),
460            Self::Complexes(v) => v.as_mut_ptr(), Self::Characters(v) => v.as_mut_ptr().cast()
461        }
462    }
463    /// Copies `range` of `source` when it has this buffer's dtype, and gives whether it could. Integers of another width don't copy.
464    pub fn extend_from(&mut self, source: View<'_>, range: std::ops::Range<usize>) -> bool {
465        match (self, source) {
466            (Self::Booleans(d), View::Booleans(s)) => d.extend_from_slice(&s[range]), (Self::Integers(d), View::Integers(s)) => return d.extend_from(s, range),
467            (Self::Floats(d), View::Floats(s)) => return d.extend_from(s, range), (Self::Complexes(d), View::Complexes(s)) => return d.extend_from(s, range),
468            (Self::Characters(d), View::Characters(s)) => d.extend_from_slice(&s[range]), _ => return false
469        }
470        true
471    }
472    /// Sets the length to `n` after a writer outside Rust, such as compiled code, filled the first `n` items through `as_mut_ptr`.
473    ///
474    /// # Safety
475    /// `n` is at most the capacity, and the first `n` items are initialized.
476    pub unsafe fn set_len(&mut self, n: usize) {
477        match self {
478            Self::Booleans(v) => unsafe { v.set_len(n) }, Self::Integers(v) => unsafe { v.set_len(n) }, Self::Floats(v) => unsafe { v.set_len(n) },
479            Self::Complexes(v) => unsafe { v.set_len(n) }, Self::Characters(v) => unsafe { v.set_len(n) }
480        }
481    }
482    /// Removes the items, keeping the allocation.
483    pub fn clear(&mut self) {
484        // SAFETY: no items remain, and items have no destructors.
485        unsafe { self.set_len(0) }
486    }
487}
488
489/// A fill that a call chooses: the item that a read gives at each position that reaches no item, as one native item, checked at the dtype that reads it. A read with no chosen fill gives its dtype's [`Element::FILL`]. A frontend's own storage, such as basedpl's nested arrays, keeps its fills in the frontend.
490#[derive(Clone, Debug)]
491pub struct Fill(Buffer);
492
493impl Fill {
494    /// The one item of `value` at `dtype`, where the conversion keeps its value, as [`Buffer::kept`] converts it. A Length error where `value` doesn't hold one item, and a Domain error where the item doesn't keep its value.
495    pub fn new(value: View<'_>, dtype: DType) -> Result<Self, Error> {
496        if value.len() != 1 { return Err(Error::new(Kind::Length, "a fill must contain one item")); }
497        Buffer::kept(value, dtype).map(Self)
498    }
499    pub fn view(&self) -> View<'_> { self.0.view() }
500    /// Convert with the source's items, including its rounding and truncation.
501    pub fn cast(&self, dtype: DType) -> Result<Self, Error> { Buffer::cast(self.view(), dtype).map(Self) }
502    /// The item that a read of items of type `A` gives at a position that reaches no item: the chosen `fill`, made for items of type `A`, or `A`'s own fill where there's none.
503    #[inline]
504    pub fn item<A: Element>(fill: Option<&std::sync::Arc<Self>>) -> A { fill.map_or(A::FILL, |f| A::of(f.view()).expect("a fill has its source's dtype")[0]) }
505}
506impl PartialEq for Fill { fn eq(&self, other: &Self) -> bool { self.view().identical(other.view()) } }
507impl Eq for Fill {}
508// Buffers are equal when they hold the same items. Numbers of one kind compare by value across widths. Buffers of different kinds are never equal.
509impl PartialEq for Buffer { fn eq(&self, other: &Self) -> bool { self.view() == other.view() } }
510
511impl<'a> View<'a> {
512    /// Borrows a consecutive range without copying or changing its dtype.
513    #[inline]
514    pub fn slice(self, range: std::ops::Range<usize>) -> Self { with_dtype!(self.dtype(), T => T::view(&T::of(self).expect("the view has its dtype")[range])) }
515    #[inline]
516    pub fn len(self) -> usize {
517        match self {
518            Self::Booleans(v) => v.len(), Self::Integers(v) => v.len(), Self::Floats(v) => v.len(), Self::Complexes(v) => v.len(),
519            Self::Characters(v) => v.len()
520        }
521    }
522    #[inline]
523    pub fn is_empty(self) -> bool { self.len() == 0 }
524    #[inline]
525    pub fn as_ptr(self) -> *const u8 {
526        match self {
527            Self::Booleans(v) => v.as_ptr().cast(), Self::Integers(v) => v.as_ptr(), Self::Floats(v) => v.as_ptr(), Self::Complexes(v) => v.as_ptr(),
528            Self::Characters(v) => v.as_ptr().cast()
529        }
530    }
531    #[inline]
532    pub fn dtype(self) -> DType {
533        match self {
534            Self::Booleans(_) => DType::Boolean, Self::Integers(v) => DType::Integer(v.tag()), Self::Floats(v) => DType::Float(v.tag()),
535            Self::Complexes(v) => DType::Complex(v.tag()), Self::Characters(_) => DType::Character
536        }
537    }
538    /// Whether the views hold the same items of one dtype, bit for bit. `-0.0` differs from `0.0`, and a NaN is identical to a NaN with the same bits. `==` instead compares values across widths.
539    pub fn identical(self, other: View<'_>) -> bool {
540        // SAFETY: every element type is plain data with no padding, so a view's items read as initialized bytes.
541        let bytes = |v: View<'_>| unsafe { std::slice::from_raw_parts(v.as_ptr(), v.len() * v.dtype().bytes()) };
542        self.dtype() == other.dtype() && bytes(self) == bytes(other)
543    }
544}
545impl PartialEq for View<'_> {
546    fn eq(&self, other: &Self) -> bool {
547        match (*self, *other) {
548            (Self::Booleans(x), Self::Booleans(y)) => x == y, (Self::Integers(x), Self::Integers(y)) => x == y, (Self::Floats(x), Self::Floats(y)) => x == y,
549            (Self::Complexes(x), Self::Complexes(y)) => x == y, (Self::Characters(x), Self::Characters(y)) => x == y, _ => false
550        }
551    }
552}
553
554/// An element type of compact buffers: `bool`, the integer widths `u8`, `i16`, `i32` and `i64`, the float widths `half::f16`, `f32` and `f64`, `Complex32` and `Complex64`, and `char`.
555pub trait Element: Copy + Send + Sync + 'static + crate::gather::Item {
556    /// The item that a missing keyed entry reads as: zero, false or a space.
557    const FILL: Self;
558    /// The dtype of buffers of this type.
559    const DTYPE: DType;
560    /// The items of `view`, when they have this type.
561    fn of(view: View<'_>) -> Option<&[Self]>;
562    /// The writable items of `buffer`, when they have this type. The allocation and length don't change.
563    fn of_mut(buffer: &mut Buffer) -> Option<&mut [Self]>;
564    /// `items` as a view.
565    fn view(items: &[Self]) -> View<'_>;
566    /// A buffer that holds `data`.
567    fn buffer(data: Vec<Self>) -> Buffer;
568    /// The items of `buffer`, moved out, when they have this type.
569    fn vec(buffer: Buffer) -> Option<Vec<Self>>;
570    /// The items of `buffer` as their vector, when they have this type, for a writer that appends or clears them.
571    fn vec_mut(buffer: &mut Buffer) -> Option<&mut Vec<Self>>;
572    /// `b` as an item of this type: 1 or 0 for a number, the Boolean itself, or the characters U+0001 and U+0000. A Boolean mask becomes lanes of the items that a kernel such as [`Choose`](crate::Choose) chooses between. A number converts through an integer, which suits stored Booleans. A comparison's lane mask turns into 1 or 0 faster by a choice between the two, so `Indicator` writes its own (`tolerant::indicated`).
573    fn truth(b: bool) -> Self;
574}
575
576/// An item that reads as type `A`: a Boolean as a number, an integer as a wider integer, a float or a complex number, a float as a float of another width or a complex number, and a complex number as one of the other width.
577pub trait Source<A>: Element {
578    fn read(self) -> A;
579    /// `items` as `A` with no copy, where the items already have type `A`.
580    fn borrowed(_items: &[Self]) -> Option<&[A]> { None }
581}
582impl<A: Element> Source<A> for A {
583    #[inline]
584    fn read(self) -> A { self }
585    #[inline]
586    fn borrowed(items: &[A]) -> Option<&[A]> { Some(items) }
587}
588macro_rules! truth {
589    ($($a:ty),+) => {$(
590        impl Source<$a> for bool { #[inline] fn read(self) -> $a { self.into() } }
591    )+};
592}
593truth!(u8, i16, i32, i64);
594/// A narrower integer reads as a wider one exactly.
595macro_rules! wider {
596    ($($s:ty => $($a:ty),+);+) => {$($(
597        impl Source<$a> for $s { #[inline] fn read(self) -> $a { self.into() } }
598    )+)+};
599}
600wider!(u8 => i16, i32, i64; i16 => i32, i64; i32 => i64);
601/// An integer reads as a float through `convert`, whose conversions vectorize on every target.
602macro_rules! numbers {
603    ($($s:ty),+) => {$(
604        impl Source<f64> for $s { #[inline] fn read(self) -> f64 { crate::convert::float(self) } }
605        impl Source<f32> for $s { #[inline] fn read(self) -> f32 { crate::convert::float(self) } }
606        impl Source<half::f16> for $s { #[inline] fn read(self) -> half::f16 { crate::convert::float(self) } }
607    )+};
608}
609numbers!(u8, i16, i32, i64);
610/// A Boolean reads as a float through its byte.
611macro_rules! truths {
612    ($($a:ty),+) => {$(
613        impl Source<$a> for bool { #[inline] fn read(self) -> $a { Source::<$a>::read(u8::from(self)) } }
614    )+};
615}
616truths!(f64, f32, half::f16);
617/// A float reads as a wider float exactly, and as a narrower one rounded to the nearest.
618macro_rules! floats {
619    ($($s:ty => $a:ty: |$x:ident| $read:expr),+) => {$(
620        impl Source<$a> for $s { #[inline] fn read(self) -> $a { let $x = self; $read } }
621    )+};
622}
623floats!(
624    half::f16 => f64: |x| x.into(), f32 => f64: |x| x.into(), half::f16 => f32: |x| x.into(),
625    f64 => f32: |x| x as f32, f32 => half::f16: |x| half::f16::from_f32(x), f64 => half::f16: |x| half::f16::from_f64(x)
626);
627/// A real number reads as a complex number with no imaginary part.
628macro_rules! complex {
629    ($($s:ty),+) => {$(
630        impl Source<Complex64> for $s { #[inline] fn read(self) -> Complex64 { Complex64::new(Source::<f64>::read(self), 0.0) } }
631        impl Source<Complex32> for $s { #[inline] fn read(self) -> Complex32 { Complex32::new(Source::<f32>::read(self), 0.0) } }
632    )+};
633}
634complex!(bool, u8, i16, i32, i64, half::f16, f32, f64);
635impl Source<Complex64> for Complex32 {
636    #[inline]
637    fn read(self) -> Complex64 { Complex64::new(self.re.into(), self.im.into()) }
638}
639impl Source<Complex32> for Complex64 {
640    #[inline]
641    fn read(self) -> Complex32 { Complex32::new(self.re as f32, self.im as f32) }
642}
643
644/// Every item of `items`, read as type `A`, through the same scheduler as native elementwise calls.
645pub fn read_all<A: Element, S: Source<A>>(items: &[S]) -> Vec<A> {
646    let mut out = Vec::with_capacity(items.len());
647    crate::pairs(crate::Arg::Many(items), crate::Arg::One(()), items.len(), &mut out, |x, ()| (x.read(), true));
648    out
649}
650
651/// An Overflow error for a value `x` that doesn't fit the dtype it converts to.
652fn overflow(x: impl std::fmt::Display) -> Error { Error::new(Kind::Overflow, format!("{x} doesn't fit the dtype it converts to")) }
653
654/// The real part of `z`, or a Domain error where its imaginary part isn't zero.
655fn real_part(z: Complex64) -> Result<f64, Error> {
656    if z.im == 0.0 { Ok(z.re) } else { Err(Error::new(Kind::Domain, format!("{z} has an imaginary part, so it doesn't convert to a real dtype"))) }
657}
658
659/// Item `i` of a numeric `view` as an `i64`. A float truncates toward zero, and gives an Overflow error where it doesn't fit, as do NaN and infinities.
660fn integer(view: View<'_>, i: usize) -> Result<i64, Error> {
661    let x = match view {
662        View::Booleans(v) => return Ok(v[i].into()), View::Integers(v) => return Ok(v.get(i)), View::Floats(v) => v.get(i),
663        View::Complexes(v) => real_part(v.get(i))?, View::Characters(_) => unreachable!("cast refuses characters first")
664    };
665    let cast =
666        crate::convert::Conversion { input: DType::Float(FloatWidth::F64), output: DType::Integer(Width::I64), kind: crate::convert::ConversionKind::Cast };
667    if cast.validity::<f64, _>(&crate::recipe::NativeOps::<{ crate::FUSED }>::DEFAULT, x).is_some_and(|(_, valid)| valid) { Ok(x as i64) }
668    else { Err(overflow(x)) }
669}
670
671/// Item `i` of a numeric `view` as a Boolean. Only exactly 0 and 1 convert, and anything else gives an Overflow error.
672fn boolean(view: View<'_>, i: usize) -> Result<bool, Error> {
673    let x = match view {
674        View::Booleans(v) => return Ok(v[i]), View::Integers(v) => Source::<f64>::read(v.get(i)), View::Floats(v) => v.get(i),
675        View::Complexes(v) => real_part(v.get(i))?, View::Characters(_) => unreachable!("cast refuses characters first")
676    };
677    if truth(x) { Ok(x != 0.0) } else { Err(overflow(x)) }
678}
679/// Whether `x` converts to a Boolean, by [`crate::convert::Conversion::validity`]'s rule: only exactly 0 and 1 do.
680#[inline]
681fn truth(x: f64) -> bool {
682    let cast = crate::convert::Conversion { input: DType::Float(FloatWidth::F64), output: DType::Boolean, kind: crate::convert::ConversionKind::Cast };
683    cast.validity::<f64, _>(&crate::recipe::NativeOps::<{ crate::FUSED }>::DEFAULT, x).is_some_and(|(_, valid)| valid)
684}
685/// Appends the Booleans that the real items `v` stand for. A checked cast fails at the first item that isn't a [`truth`]; an unchecked one gives the fill, false, for it. Each item is tested against 0 and 1 in its own type, by `truth`'s rule, without widening integers to floats.
686fn truths<S: Copy + PartialEq + From<u8> + Source<f64>>(v: &[S], checked: bool, out: &mut Vec<bool>) -> Result<(), Error> {
687    let (zero, one) = (S::from(0), S::from(1));
688    // One fold checks every item and vectorizes. Only a failure then looks for the first item that isn't a truth.
689    if checked && !v.iter().fold(true, |ok, &x| ok & ((x == zero) | (x == one))) {
690        let x = v.iter().map(|&x| Source::<f64>::read(x)).find(|&x| !truth(x)).expect("an item that isn't a truth");
691        return Err(overflow(x));
692    }
693    out.extend(v.iter().map(|&x| x == one));
694    Ok(())
695}
696
697/// Convert stored items using the destination dtype's checked conversion.
698pub trait Cast: Element + crate::gather::Item {
699    /// Item `item` of `view`, or an error where it doesn't convert.
700    fn cast(view: View<'_>, item: usize) -> Result<Self, Error>;
701    /// Appends the first `len` items of `view` to `out`, each as [`Cast::cast`] converts it and [`kept`] keeps it. Element types override this with one typed loop for each source dtype they read often.
702    fn extend_cast(view: View<'_>, len: usize, checked: bool, out: &mut Vec<Self>) -> Result<(), Error> { itemwise(view, len, checked, out) }
703}
704/// `value`, or the fill where it didn't convert, unless `checked`.
705pub(crate) fn kept<T: Element>(value: Result<T, Error>, checked: bool) -> Result<T, Error> {
706    match value { Ok(value) => Ok(value), Err(error) if checked => Err(error), Err(_) => Ok(T::FILL) }
707}
708/// [`Cast::extend_cast`] one item at a time, through [`Cast::cast`].
709fn itemwise<T: Cast>(view: View<'_>, len: usize, checked: bool, out: &mut Vec<T>) -> Result<(), Error> {
710    out.reserve(len);
711    for i in 0..len { out.push(kept(T::cast(view, i), checked)?); }
712    Ok(())
713}
714fn numeric(view: View<'_>) -> Result<(), Error> {
715    if matches!(view, View::Characters(_)) { Err(Error::new(Kind::Domain, "characters convert only to characters")) } else { Ok(()) }
716}
717fn real(view: View<'_>, item: usize) -> Result<f64, Error> {
718    Ok(match view {
719        View::Booleans(v) => u8::from(v[item]).into(), View::Integers(v) => Source::<f64>::read(v.get(item)), View::Floats(v) => v.get(item),
720        View::Complexes(v) => real_part(v.get(item))?, View::Characters(_) => return Err(Error::new(Kind::Domain, "characters convert only to characters"))
721    })
722}
723impl Cast for bool {
724    fn cast(view: View<'_>, item: usize) -> Result<Self, Error> { numeric(view)?; boolean(view, item) }
725    fn extend_cast(view: View<'_>, len: usize, checked: bool, out: &mut Vec<Self>) -> Result<(), Error> {
726        match view {
727            View::Booleans(v) => out.extend_from_slice(&v[..len]), View::Integers(v) => with_ints!(v, |v| truths(&v[..len], checked, out)?),
728            View::Floats(v) => with_floats!(v, |v| truths(&v[..len], checked, out)?), _ => return itemwise(view, len, checked, out)
729        }
730        Ok(())
731    }
732}
733impl Cast for char {
734    fn cast(view: View<'_>, item: usize) -> Result<Self, Error> {
735        match view { View::Characters(v) => Ok(v[item]), _ => Err(Error::new(Kind::Domain, "characters convert only to characters")) }
736    }
737}
738macro_rules! casts {
739    (integers $($t:ty),+) => {$(impl Cast for $t {
740        fn cast(view: View<'_>, item: usize) -> Result<Self, Error> {
741            numeric(view)?;
742            let value = integer(view, item)?;
743            Self::try_from(value).map_err(|_| overflow(value))
744        }
745        // A checked cast first looks for an item that doesn't fit. The typed loop gives the fill for one.
746        fn extend_cast(view: View<'_>, len: usize, checked: bool, out: &mut Vec<Self>) -> Result<(), Error> {
747            match view {
748                View::Booleans(v) => out.extend(v[..len].iter().map(|&b| Self::from(b))),
749                View::Integers(v) => with_ints!(v, |v| {
750                    let v = &v[..len];
751                    if checked { if let Some(&x) = v.iter().find(|&&x| Self::try_from(x).is_err()) { return Err(overflow(x)); } }
752                    out.extend(v.iter().map(|&x| Self::try_from(x).unwrap_or(Self::FILL)));
753                }),
754                _ => return itemwise(view, len, checked, out),
755            }
756            Ok(())
757        }
758    })+};
759    (floats $($t:ty),+) => {$(impl Cast for $t {
760        fn cast(view: View<'_>, item: usize) -> Result<Self, Error> { real(view, item).map(Source::<Self>::read) }
761        // Converting a real item can't fail.
762        fn extend_cast(view: View<'_>, len: usize, checked: bool, out: &mut Vec<Self>) -> Result<(), Error> {
763            match view {
764                View::Booleans(v) => out.extend(v[..len].iter().map(|&b| Source::<Self>::read(f64::from(u8::from(b))))),
765                View::Integers(v) => with_ints!(v, |v| out.extend(v[..len].iter().map(|&x| Source::<Self>::read(Source::<f64>::read(x))))),
766                View::Floats(v) => with_floats!(v, |v| out.extend(v[..len].iter().map(|&x| Source::<Self>::read(f64::from(x))))),
767                _ => return itemwise(view, len, checked, out),
768            }
769            Ok(())
770        }
771    })+};
772    (complex $($t:ty),+) => {$(impl Cast for $t {
773        fn cast(view: View<'_>, item: usize) -> Result<Self, Error> {
774            let value = match view { View::Complexes(v) => v.get(item), _ => Complex64::new(real(view, item)?, 0.0) };
775            Ok(Source::<Self>::read(value))
776        }
777    })+};
778}
779casts!(integers u8, i16, i32, i64);
780casts!(floats half::f16, f32, f64);
781casts!(complex Complex32, Complex64);
782
783impl Buffer {
784    /// Flattened positions whose item differs from its type's fill (zero, false or a space).
785    pub fn nonzero(view: View<'_>) -> Vec<usize> {
786        with_dtype!(view.dtype(), T => T::of(view).expect("matching dtype").iter().enumerate().filter_map(|(i, &x)| (x != T::FILL).then_some(i)).collect())
787    }
788    /// Whether any item equals its type's fill: zero, false or a space.
789    pub fn any_fill(view: View<'_>) -> bool {
790        with_dtype!(view.dtype(), T => T::of(view).expect("matching dtype").iter().fold(false, |found, &x| found | (x == T::FILL)))
791    }
792    /// Whether every item has the first item's bits, as an array of one repeated value does: `0` and `¯0` differ, and a NaN matches only a NaN with its bits. An empty view gives true.
793    pub fn same(view: View<'_>) -> bool {
794        let size = view.dtype().bytes();
795        // SAFETY: a view holds `len` initialised items of `size` bytes each at `as_ptr`, and no element type has padding.
796        let bytes = unsafe { std::slice::from_raw_parts(view.as_ptr(), view.len() * size) };
797        // Every item has the first one's bits exactly where each item matches the next.
798        bytes.len() <= size || bytes[size..] == bytes[..bytes.len() - size]
799    }
800    /// Copies the first `n` items of a structural walk from `base`, using the type's fill for missing positions and whole-slice copies for contiguous runs. `n` can be shorter than the walk, as it is for a view whose mapping reaches past its own items.
801    pub fn walked(view: View<'_>, base: usize, steps: &[crate::gather::Steps], n: usize) -> Self {
802        with_dtype!(view.dtype(), T => {
803            let mut out = Vec::with_capacity(n);
804            let (base, plan) = crate::gather::Steps::simplify(base, steps);
805            crate::gather::walk_plan(&mut out, T::of(view).expect("matching dtype"), base, &plan, T::FILL, 0, n, crate::gather::Same);
806            T::buffer(out)
807        })
808    }
809    /// The items in the order that `order` reads them, or the buffer itself without one. `Kernel::fold_read` gives such an order with totals that stay in their source's order.
810    pub fn ordered(self, order: Option<Vec<crate::gather::Steps>>) -> Self {
811        match order { Some(order) => Self::walked(self.view(), 0, &order, crate::gather::Steps::count(&order)), None => self }
812    }
813    /// A new buffer holding the items of `view` in `range`.
814    pub fn copied(view: View<'_>, range: std::ops::Range<usize>) -> Self {
815        let mut b = Self::with_capacity(view.dtype(), range.len());
816        b.extend_from(view, range);
817        b
818    }
819    /// The items of `view` at `indices`, as [`take`](crate::gather::take) reads them: a negative index counts back from the end.
820    pub fn gathered<I: crate::gather::IndexValue>(view: View<'_>, indices: &[I]) -> Self {
821        fn taken<T: Element, I: crate::gather::IndexValue>(items: &[T], indices: &[I]) -> Buffer {
822            let mut out = Vec::with_capacity(indices.len());
823            crate::gather::take(&mut out, items, indices, |x| x);
824            T::buffer(out)
825        }
826        match view {
827            View::Booleans(v) => taken(v, indices), View::Characters(v) => taken(v, indices), View::Integers(v) => with_ints!(v, |v| taken(v, indices)),
828            View::Floats(v) => with_floats!(v, |v| taken(v, indices)), View::Complexes(v) => with_complexes!(v, |v| taken(v, indices))
829        }
830    }
831    /// The items of `view` at `dtype`. Matching dtypes copy. Otherwise each item converts as [`Source`] reads it, and conversions to a narrower dtype follow these rules. A float converts to an integer by truncating toward zero. A value that doesn't fit its target gives an Overflow error, as do NaN, infinities and anything but exactly 0 or 1 for Booleans. A complex number converts to a real dtype only when its imaginary part is zero, and otherwise gives a Domain error. Characters convert only to characters.
832    pub fn cast(view: View<'_>, dtype: DType) -> Result<Self, Error> { Self::cast_mapped(view, &crate::agreement::Mapping::Linear(1), view.len(), dtype) }
833    /// The items of `view` at `dtype`, where every item keeps its value. Items convert as [`Buffer::cast`] converts them, and a float that becomes a Boolean or an integer must be whole. A float rounds to a float of another width. A Domain error where an item doesn't keep its value.
834    pub fn kept(view: View<'_>, dtype: DType) -> Result<Self, Error> {
835        let whole = match view {
836            View::Floats(v) => (0..v.len()).all(|i| v.get(i).fract() == 0.0), View::Complexes(v) => (0..v.len()).all(|i| v.get(i).re.fract() == 0.0), _ => true
837        };
838        let lost = || Error::new(Kind::Domain, format!("a {} item doesn't keep its value as {}", view.dtype().name(), dtype.name()));
839        if dtype.is_integral() && !whole { return Err(lost()); }
840        Self::cast(view, dtype).map_err(|_| lost())
841    }
842    /// Shared conversion dispatch for compact and mapped logical items. Unselected storage never participates in checked conversion.
843    pub fn cast_mapped(view: View<'_>, mapping: &crate::agreement::Mapping, n: usize, dtype: DType) -> Result<Self, Error> {
844        use crate::agreement::{Binding, Missing, Read, ReadPlan};
845        let mut sources = vec![Binding::full(view)];
846        let missing = Missing::prototype(view.dtype(), &mut sources);
847        let plan = ReadPlan::copy(0, view.len(), mapping.clone(), n, missing);
848        let mut output = Self::with_capacity(dtype, n);
849        Read { sources: &sources, plan: &plan }.read_into(0..n, dtype, true, &mut output)?;
850        Ok(output)
851    }
852}
853
854impl Buffer {
855    /// The items of `view` as integers of `dtype`, as BPL's `ₓ` marks and Python's `astype` convert them: a float takes its floor within `t` and saturates at the range, NaN giving 0 ([`crate::convert::floored`]); an integer wraps to the width; a Boolean gives 0 or 1. Other items and targets convert as [`Buffer::cast`] converts them.
856    pub fn floored(view: View<'_>, dtype: DType, t: impl crate::tolerant::Tolerant) -> Result<Self, Error> {
857        match (view, dtype) {
858            (View::Floats(values), DType::Integer(width)) => {
859                Ok(with_width!(width, I => I::buffer(with_floats!(values, |values| values.iter().map(|&x| crate::convert::floored::<I, _>(x, t)).collect()))))
860            }
861            (View::Integers(_) | View::Booleans(_), DType::Integer(_)) => Self::cast_results(view, dtype, false),
862            _ => Self::cast(view, dtype),
863        }
864    }
865    pub fn cast_results(view: View<'_>, dtype: DType, checked: bool) -> Result<Self, Error> {
866        match (view, dtype) {
867            (View::Floats(values), DType::Integer(width)) => {
868                Ok(with_width!(width, I => I::buffer(with_floats!(values, |values| values.iter().map(|&x| crate::convert::saturated::<I, _>(x)).collect()))))
869            }
870            (View::Integers(values), DType::Integer(width)) if !checked => {
871                Ok(with_width!(width, T => with_ints!(values, |values| T::buffer(values.iter().map(|&x| x as T).collect()))))
872            }
873            (View::Booleans(values), DType::Integer(width)) => Ok(with_width!(width, T => T::buffer(values.iter().map(|&x| x as T).collect()))),
874            (_, DType::Character) if view.dtype().is_integral() => {
875                let items = (0..view.len()).map(|i| {
876                    let value = integer(view, i).ok().and_then(|x| u32::try_from(x).ok()).and_then(char::from_u32);
877                    match value {
878                        Some(value) => Ok(value), None if checked => Err(Error::new(Kind::Domain, "result is not a Unicode character")), None => Ok(char::FILL)
879                    }
880                }).collect::<Result<Vec<_>, _>>()?;
881                Ok(Self::Characters(items))
882            }
883            _ => with_dtype!(dtype, T => {
884                let mut items = Vec::new();
885                T::extend_cast(view, view.len(), checked, &mut items)?;
886                Ok(T::buffer(items))
887            }),
888        }
889    }
890}