Skip to main content

Module slice

Module slice 

Source
Expand description

Slice adapters — view a byte sub-range of any BlockRead as its own device. Useful any time you want to feed a fragment of a larger device to a consumer that expects a whole block source — partition probes, image-file extents, mmap-style views, fuzzer harnesses.

Three variants:

  • SliceReader borrows the parent, lifetime-tied. Cheaper when the parent outlives the slice and you can express that statically.
  • OwnedSlice holds an Arc to the parent. Use when the parent’s lifetime can’t be expressed in a borrow (FFI handles, slice handed across thread boundaries, etc.).
  • OwnedRwSlice holds an Arc<dyn BlockDevice> and propagates writes to the parent.

The first two are strictly read-only: the default Err(ReadOnly) write path from BlockDevice applies.

§Which error an out-of-range request gets

All three share one range check — SliceGeometry::rebase — and it answers in two different currencies depending on the direction of the request:

request outside [0, length)error
readError::ShortRead with got: 0
writeError::OutOfBounds

The asymmetry is deliberate. A slice exists to be substitutable for a real device of size length, and a real device — FileDevice — answers a read that begins at or past its end with exactly ShortRead { offset, want, got: 0 }. A slice that answered OutOfBounds would be distinguishable from the thing it stands in for, and every caller that already handles end-of-device would need a second arm to cope with slices. Writes have no partial-write variant to stay consistent with, and a caller that overran a write needs the device size in order to clamp and retry — which is what Error::OutOfBounds carries and Error::ShortRead does not.

The match is on the variant, not on got. A slice refuses an out-of-range read before it touches the parent, so it reports got: 0 and leaves the buffer untouched — including for a read that begins inside the slice and runs off its end, where FileDevice would have copied the readable prefix and reported its length. got counts bytes actually delivered, and a slice delivers none.

This governs the slice’s own range only. A request that is inside [0, length) is forwarded to the parent, and whatever the parent says about it — including Error::OutOfBounds from a container reader that knows its virtual size — comes back unchanged.

§A slice cannot report more device than its parent holds

All three constructors ask the parent its size and CLAMP length to what is actually there — see window_on_parent for the rule and why it clamps rather than refuses. So size_bytes() is the truth about how much is readable, not a number the caller asserted.

That is load-bearing rather than tidy. size_bytes() is “used for bounds checks” (BlockRead::size_bytes), and a driver mounted on a slice sizes its own structures from it. A slice that claimed a megabyte over a hundred-byte parent kept both promises of the section above and broke them in the same breath: a read inside the declared length but past the real end was forwarded, and the parent — being a real device — answered with a ShortRead carrying its own absolute offset and a non-zero got, having already copied the readable prefix into the caller’s buffer. Substitutable for a real device of size length is exactly what that is not.

A slice whose start is at or past the parent’s end has nothing behind it at all. The constructors are infallible and give it length = 0, which behaves as a zero-byte device does: every read is ShortRead { got: 0 } and every write is OutOfBounds { size: 0 }. The C ABI, which can afford to be fallible, refuses it instead — fs_core_device_slice_ro/_rw return NULL with a message.

Structs§

OwnedRwSlice
Owned, read-WRITE slice over an Arc<dyn BlockDevice>. Use when the parent is writable and the slice should propagate writes (e.g. an individual partition handed to a filesystem driver).
OwnedSlice
Owned slice over an Arc<dyn BlockRead>. Use when the parent’s lifetime can’t be expressed in a borrow — e.g. when the slice is handed across an FFI boundary or stored in a long-lived struct.
SliceReader
Borrowed slice of a parent BlockRead.

Functions§

window_on_parent
How much of the window [start, start + length) is actually on a parent of parent_size bytes, or None when the window begins at or past the parent’s end and there is nothing on it to slice.