Skip to main content

pyo3/buffer/
flags.rs

1use super::PyBufferContiguity;
2
3pub(super) const CONTIGUITY_UNDEFINED: u8 = PyBufferContiguity::Undefined as u8;
4pub(super) const CONTIGUITY_C: u8 = PyBufferContiguity::C as u8;
5pub(super) const CONTIGUITY_F: u8 = PyBufferContiguity::F as u8;
6pub(super) const CONTIGUITY_ANY: u8 = PyBufferContiguity::Any as u8;
7
8pub struct PyBufferFlags<
9    const FORMAT: bool,
10    const SHAPE: bool,
11    const STRIDE: bool,
12    const INDIRECT: bool,
13    const WRITABLE: bool,
14    const CONTIGUITY: u8,
15>;
16
17#[diagnostic::on_unimplemented(
18    message = "format information has already been requested for this buffer request",
19    note = "remove the extra `.format()` call"
20)]
21pub trait CanRequestFormat {}
22#[diagnostic::do_not_recommend]
23impl<
24    const SHAPE: bool,
25    const STRIDE: bool,
26    const INDIRECT: bool,
27    const WRITABLE: bool,
28    const CONTIGUITY: u8,
29> CanRequestFormat for PyBufferFlags<false, SHAPE, STRIDE, INDIRECT, WRITABLE, CONTIGUITY>
30{
31}
32
33#[diagnostic::on_unimplemented(
34    message = "shape information has already been requested for this buffer request",
35    note = "remove the extra `.nd()` call"
36)]
37pub trait CanRequestShape {}
38#[diagnostic::do_not_recommend]
39impl<
40    const FORMAT: bool,
41    const STRIDE: bool,
42    const INDIRECT: bool,
43    const WRITABLE: bool,
44    const CONTIGUITY: u8,
45> CanRequestShape for PyBufferFlags<FORMAT, false, STRIDE, INDIRECT, WRITABLE, CONTIGUITY>
46{
47}
48
49#[diagnostic::on_unimplemented(
50    message = "stride information has already been requested for this buffer request",
51    note = "remove the extra `.strides()` call"
52)]
53pub trait CanRequestStrides {}
54#[diagnostic::do_not_recommend]
55impl<
56    const FORMAT: bool,
57    const SHAPE: bool,
58    const INDIRECT: bool,
59    const WRITABLE: bool,
60    const CONTIGUITY: u8,
61> CanRequestStrides for PyBufferFlags<FORMAT, SHAPE, false, INDIRECT, WRITABLE, CONTIGUITY>
62{
63}
64
65#[diagnostic::on_unimplemented(
66    message = "suboffsets can only be requested on a direct unconstrained buffer request",
67    note = "call `.indirect()` before any contiguity builder, and only once"
68)]
69pub trait CanRequestIndirect {}
70#[diagnostic::do_not_recommend]
71impl<const FORMAT: bool, const SHAPE: bool, const STRIDE: bool, const WRITABLE: bool>
72    CanRequestIndirect
73    for PyBufferFlags<FORMAT, SHAPE, STRIDE, false, WRITABLE, { CONTIGUITY_UNDEFINED }>
74{
75}
76
77#[diagnostic::on_unimplemented(
78    message = "writability has already been requested for this buffer request",
79    note = "remove the extra `.writable()` call"
80)]
81pub trait CanRequestWritable {}
82#[diagnostic::do_not_recommend]
83impl<
84    const FORMAT: bool,
85    const SHAPE: bool,
86    const STRIDE: bool,
87    const INDIRECT: bool,
88    const CONTIGUITY: u8,
89> CanRequestWritable for PyBufferFlags<FORMAT, SHAPE, STRIDE, INDIRECT, false, CONTIGUITY>
90{
91}
92
93#[diagnostic::on_unimplemented(
94    message = "contiguity has already been constrained for this buffer request",
95    note = "only one of `.c_contiguous()`, `.f_contiguous()`, or `.any_contiguous()` may be used"
96)]
97pub trait CanRequestContiguity {}
98#[diagnostic::do_not_recommend]
99impl<
100    const FORMAT: bool,
101    const SHAPE: bool,
102    const STRIDE: bool,
103    const INDIRECT: bool,
104    const WRITABLE: bool,
105> CanRequestContiguity
106    for PyBufferFlags<FORMAT, SHAPE, STRIDE, INDIRECT, WRITABLE, { CONTIGUITY_UNDEFINED }>
107{
108}
109
110#[diagnostic::on_unimplemented(
111    message = "C contiguity is not guaranteed by the requested buffer flags",
112    note = "use `.c_contiguous()` when building a buffer request to guarantee C contiguity"
113)]
114pub trait GuaranteesCContiguous {}
115#[diagnostic::do_not_recommend]
116impl<
117    const FORMAT: bool,
118    const SHAPE: bool,
119    const STRIDE: bool,
120    const INDIRECT: bool,
121    const WRITABLE: bool,
122> GuaranteesCContiguous
123    for PyBufferFlags<FORMAT, SHAPE, STRIDE, INDIRECT, WRITABLE, { CONTIGUITY_C }>
124{
125}
126
127#[diagnostic::on_unimplemented(
128    message = "Fortran contiguity is not guaranteed by the requested buffer flags",
129    note = "use `.f_contiguous()` when building a buffer request to guarantee Fortran contiguity"
130)]
131pub trait GuaranteesFContiguous {}
132#[diagnostic::do_not_recommend]
133impl<
134    const FORMAT: bool,
135    const SHAPE: bool,
136    const STRIDE: bool,
137    const INDIRECT: bool,
138    const WRITABLE: bool,
139> GuaranteesFContiguous
140    for PyBufferFlags<FORMAT, SHAPE, STRIDE, INDIRECT, WRITABLE, { CONTIGUITY_F }>
141{
142}
143
144/// Marker trait for buffer flags which have requested format information.
145#[diagnostic::on_unimplemented(
146    message = "format information is not available with the requested buffer flags",
147    note = "use `.format()` when building a buffer request to request format information",
148    note = "`PyBufferRequest::simple()` and `PyBufferRequest::simple().writable()` also imply u8 format"
149)]
150pub trait IncludesFormat {
151    const ASSUME_U8: bool;
152}
153
154#[diagnostic::do_not_recommend]
155impl<
156    const SHAPE: bool,
157    const STRIDE: bool,
158    const INDIRECT: bool,
159    const WRITABLE: bool,
160    const CONTIGUITY: u8,
161> IncludesFormat for PyBufferFlags<true, SHAPE, STRIDE, INDIRECT, WRITABLE, CONTIGUITY>
162{
163    const ASSUME_U8: bool = false;
164}
165
166// Simple (maybe writable) buffers also have an implied u8 format.
167#[diagnostic::do_not_recommend]
168impl<const WRITABLE: bool> IncludesFormat
169    for PyBufferFlags<false, false, false, false, WRITABLE, { CONTIGUITY_UNDEFINED }>
170{
171    const ASSUME_U8: bool = true;
172}
173
174#[diagnostic::on_unimplemented(
175    message = "shape information is not available with the requested buffer flags",
176    note = "use `.nd()` when building a buffer request to request shape information"
177)]
178pub trait IncludesShape {}
179#[diagnostic::do_not_recommend]
180impl<
181    const FORMAT: bool,
182    const STRIDE: bool,
183    const INDIRECT: bool,
184    const WRITABLE: bool,
185    const CONTIGUITY: u8,
186> IncludesShape for PyBufferFlags<FORMAT, true, STRIDE, INDIRECT, WRITABLE, CONTIGUITY>
187{
188}
189
190#[diagnostic::on_unimplemented(
191    message = "strides information is not available with the requested buffer flags",
192    note = "use `.strides()` when building a buffer request to request stride information"
193)]
194pub trait IncludesStrides {}
195#[diagnostic::do_not_recommend]
196impl<
197    const FORMAT: bool,
198    const SHAPE: bool,
199    const INDIRECT: bool,
200    const WRITABLE: bool,
201    const CONTIGUITY: u8,
202> IncludesStrides for PyBufferFlags<FORMAT, SHAPE, true, INDIRECT, WRITABLE, CONTIGUITY>
203{
204}
205
206#[diagnostic::on_unimplemented(
207    message = "suboffsets information is not available with the requested buffer flags",
208    note = "use `.indirect()` when building a buffer request to request suboffset information"
209)]
210pub trait IncludesSuboffsets {}
211#[diagnostic::do_not_recommend]
212impl<
213    const FORMAT: bool,
214    const SHAPE: bool,
215    const STRIDE: bool,
216    const WRITABLE: bool,
217    const CONTIGUITY: u8,
218> IncludesSuboffsets for PyBufferFlags<FORMAT, SHAPE, STRIDE, true, WRITABLE, CONTIGUITY>
219{
220}
221
222pub trait Sealed {}
223impl<
224    const FORMAT: bool,
225    const SHAPE: bool,
226    const STRIDE: bool,
227    const INDIRECT: bool,
228    const WRITABLE: bool,
229    const CONTIGUITY: u8,
230> Sealed for PyBufferFlags<FORMAT, SHAPE, STRIDE, INDIRECT, WRITABLE, CONTIGUITY>
231{
232}
233
234/// Trait implemented by all hidden [`super::PyBufferRequest`] states.
235pub trait PyBufferRequestType: Sealed {
236    /// Whether this is a simple request, which treats the buffer as unsigned bytes.
237    const IS_SIMPLE: bool;
238
239    /// The contiguity requirement encoded by these flags.
240    const CONTIGUITY: PyBufferContiguity;
241
242    /// Whether these flags require a writable buffer.
243    const WRITABLE: bool;
244
245    /// The state after requesting format information.
246    type WithFormat: PyBufferRequestType + IncludesFormat;
247
248    /// The state after requesting shape information.
249    type WithShape: PyBufferRequestType + IncludesShape;
250
251    /// The state after requesting strides information.
252    type WithStrides: PyBufferRequestType + IncludesShape + IncludesStrides;
253
254    /// The state after requesting indirect / suboffset information.
255    type WithIndirect: PyBufferRequestType + IncludesShape + IncludesStrides + IncludesSuboffsets;
256
257    /// The state after requesting writability.
258    type WithWritable: PyBufferRequestType;
259
260    /// The state after requesting C contiguity.
261    type WithCContiguous: PyBufferRequestType;
262
263    /// The state after requesting Fortran contiguity.
264    type WithFContiguous: PyBufferRequestType;
265
266    /// The state after requesting either C or Fortran contiguity.
267    type WithAnyContiguous: PyBufferRequestType;
268}
269
270impl<
271    const FORMAT: bool,
272    const SHAPE: bool,
273    const STRIDE: bool,
274    const INDIRECT: bool,
275    const WRITABLE: bool,
276    const CONTIGUITY_REQ: u8,
277> PyBufferRequestType for PyBufferFlags<FORMAT, SHAPE, STRIDE, INDIRECT, WRITABLE, CONTIGUITY_REQ>
278{
279    const IS_SIMPLE: bool = !FORMAT && !SHAPE;
280
281    const CONTIGUITY: PyBufferContiguity = match CONTIGUITY_REQ {
282        CONTIGUITY_UNDEFINED => PyBufferContiguity::Undefined,
283        CONTIGUITY_C => PyBufferContiguity::C,
284        CONTIGUITY_F => PyBufferContiguity::F,
285        CONTIGUITY_ANY => PyBufferContiguity::Any,
286        _ => panic!("invalid buffer contiguity"),
287    };
288    const WRITABLE: bool = WRITABLE;
289
290    type WithFormat = PyBufferFlags<true, SHAPE, STRIDE, INDIRECT, WRITABLE, CONTIGUITY_REQ>;
291    type WithShape = PyBufferFlags<FORMAT, true, STRIDE, INDIRECT, WRITABLE, CONTIGUITY_REQ>;
292    type WithStrides = PyBufferFlags<FORMAT, true, true, INDIRECT, WRITABLE, CONTIGUITY_REQ>;
293    type WithIndirect = PyBufferFlags<FORMAT, true, true, true, WRITABLE, CONTIGUITY_UNDEFINED>;
294    type WithWritable = PyBufferFlags<FORMAT, SHAPE, STRIDE, INDIRECT, true, CONTIGUITY_REQ>;
295    type WithCContiguous = PyBufferFlags<FORMAT, true, true, false, WRITABLE, CONTIGUITY_C>;
296    type WithFContiguous = PyBufferFlags<FORMAT, true, true, false, WRITABLE, CONTIGUITY_F>;
297    type WithAnyContiguous = PyBufferFlags<FORMAT, true, true, false, WRITABLE, CONTIGUITY_ANY>;
298}
⚠️ Internal Docs ⚠️ Not Public API 👉 Official Docs Here