data_streams/
slice.rs

1// Copyright 2024 - Strixpyrr
2// SPDX-License-Identifier: Apache-2.0
3
4use core::mem::take;
5use crate::{DataSink, Error, Result};
6
7impl DataSink for &mut [u8] {
8	fn write_bytes(&mut self, buf: &[u8]) -> Result {
9		mut_slice_write_bytes(self, buf, <[u8]>::copy_from_slice)
10	}
11
12	fn write_utf8_codepoint(&mut self, value: char) -> Result {
13		if let Some((buf, remaining)) = take(self).split_at_mut_checked(value.len_utf8()) {
14			// Encode directly into the sink slice.
15			value.encode_utf8(buf);
16			*self = remaining;
17			Ok(())
18		} else {
19			// Encode into an intermediate buffer, then write until overflow.
20			let mut buf = [0; 4];
21			self.write_utf8(value.encode_utf8(&mut buf))
22		}
23	}
24
25	fn write_u8(&mut self, value: u8) -> Result {
26		use core::convert::identity;
27		mut_slice_push_u8(self, value, identity)
28	}
29
30	fn write_i8(&mut self, value: i8) -> Result {
31		self.write_u8(value as u8)
32	}
33}
34
35#[cfg(feature = "unstable_uninit_slice")]
36use core::mem::MaybeUninit;
37
38#[cfg(feature = "unstable_uninit_slice")]
39impl DataSink for &mut [MaybeUninit<u8>] {
40	fn write_bytes(&mut self, buf: &[u8]) -> Result {
41		mut_slice_write_bytes(self, buf, |t, s| { t.write_copy_of_slice(s); })
42	}
43
44	fn write_u8(&mut self, value: u8) -> Result {
45		mut_slice_push_u8(self, value, MaybeUninit::new)
46	}
47
48	fn write_i8(&mut self, value: i8) -> Result {
49		self.write_u8(value as u8)
50	}
51}
52
53#[allow(clippy::mut_mut)]
54fn mut_slice_write_bytes<T>(
55	sink: &mut &mut [T],
56	buf: &[u8],
57	copy_from_slice: impl FnOnce(&mut [T], &[u8])
58) -> Result {
59	let len = buf.len().min(sink.len());
60	// From <[_]>::take_mut
61	let (target, empty) = take(sink).split_at_mut(len);
62	*sink = empty;
63	copy_from_slice(target, &buf[..len]);
64	let remaining = buf.len() - len;
65	if remaining > 0 {
66		Err(Error::overflow(remaining))
67	} else {
68		Ok(())
69	}
70}
71
72#[allow(clippy::mut_mut)]
73fn mut_slice_push_u8<T>(
74	sink: &mut &mut [T],
75	value: u8,
76	map: impl FnOnce(u8) -> T
77) -> Result {
78	if sink.is_empty() {
79		Err(Error::overflow(1))
80	} else {
81		sink[0] = map(value);
82		*sink = &mut take(sink)[1..];
83		Ok(())
84	}
85}