cubecl_environment/bytes/access.rs
1//! Access policy and reader/writer configuration for [`Bytes`](super::Bytes).
2//!
3//! Accessing a [`Bytes`] is parameterized by an [`AccessPolicy`] that dictates what the
4//! backing [`AllocationController`](super::AllocationController) is *allowed* to do to satisfy
5//! the access. The policy makes the previously-implicit decisions explicit:
6//!
7//! - **copy-on-read**: materializing lazy storage (file / device) into a host buffer.
8//! - **copy-on-write**: copying shared storage into a private buffer before mutation.
9//!
10//! A [`Reader`]/[`Writer`] is a small builder over a policy, used with
11//! [`Bytes::read`](super::Bytes::read) / [`Bytes::write`](super::Bytes::write).
12
13use alloc::string::String;
14
15/// What an access is allowed to do to satisfy a read/write of a [`Bytes`](super::Bytes).
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub struct AccessPolicy {
18 allow_copy: bool,
19}
20
21impl Default for AccessPolicy {
22 fn default() -> Self {
23 Self::allow_copy()
24 }
25}
26
27impl AccessPolicy {
28 /// Allow allocating/copying a new buffer to satisfy the access (copy-on-read
29 /// materialization and copy-on-write).
30 pub fn allow_copy() -> Self {
31 Self { allow_copy: true }
32 }
33
34 /// Forbid any copy: the access succeeds only if it can be served from already-resident
35 /// memory, otherwise it fails with [`AccessError::WouldCopy`].
36 pub fn zero_copy() -> Self {
37 Self { allow_copy: false }
38 }
39
40 /// Whether copying is allowed to satisfy the access.
41 pub fn copy_allowed(&self) -> bool {
42 self.allow_copy
43 }
44}
45
46/// Error returned when accessing a [`Bytes`](super::Bytes).
47#[derive(Debug, Clone, PartialEq, Eq)]
48pub enum AccessError {
49 /// The access required allocating/copying a new buffer, which the [`AccessPolicy`]
50 /// forbade.
51 WouldCopy,
52 /// Materializing the data failed (e.g. a file or device read error). The payload is a
53 /// human-readable message.
54 Read(String),
55}
56
57impl core::fmt::Display for AccessError {
58 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
59 match self {
60 Self::WouldCopy => f.write_str("access would require a copy, which the policy forbids"),
61 Self::Read(msg) => write!(f, "failed to materialize bytes: {msg}"),
62 }
63 }
64}
65
66impl core::error::Error for AccessError {}
67
68/// Configures a read of a [`Bytes`](super::Bytes::read).
69///
70/// Defaults to allowing copies (the same behavior as `Deref`). Use [`Reader::no_copy`] to
71/// require resident memory.
72#[derive(Clone, Copy, Debug, Default)]
73pub struct Reader {
74 pub(crate) policy: AccessPolicy,
75}
76
77impl Reader {
78 /// A reader that allows copies to satisfy the read.
79 pub fn new() -> Self {
80 Self::default()
81 }
82
83 /// Require the read to be served without any copy/materialization.
84 pub fn no_copy(mut self) -> Self {
85 self.policy = AccessPolicy::zero_copy();
86 self
87 }
88}
89
90/// Configures a mutable access of a [`Bytes`](super::Bytes::write).
91///
92/// Defaults to allowing copies (copy-on-write). Use [`Writer::no_copy`] to require that the
93/// buffer is already private/mutable.
94#[derive(Clone, Copy, Debug, Default)]
95pub struct Writer {
96 pub(crate) policy: AccessPolicy,
97}
98
99impl Writer {
100 /// A writer that allows copy-on-write to satisfy the access.
101 pub fn new() -> Self {
102 Self::default()
103 }
104
105 /// Require mutable access without any copy-on-write (fails on still-shared buffers).
106 pub fn no_copy(mut self) -> Self {
107 self.policy = AccessPolicy::zero_copy();
108 self
109 }
110}