oct 0.36.2

Octonary transcodings.
Documentation
// Copyright 2024-2026 Gabriel Bjørnager Jensen.
//
// SPDX: MIT OR Apache-2.0

//! The [`Write`] trait.

use oct::serdes::Result;

#[cfg(feature = "std")]
use std::io;

#[cfg(not(feature = "std"))]
use core::mem::take;

#[cfg(not(feature = "std"))]
use oct::serdes::Error;

#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::vec::Vec;

/// Trait for serialisation buffers.
///
/// This trait serves as a stripped-down version of
/// [`std::io::Write`] intended only for
/// serialisation.
///
#[cfg_attr(not(feature = "std"), doc = "[`std::io::Write`]: <https://doc.rust-lang.org/nightly/std/io/trait.Write.html>")]
pub trait Write {
	/// Writes from the buffer into the writer.
	///
	/// *See also [`std::io::Write::write`].*
	///
	#[cfg_attr(not(feature = "std"), doc = "[`std::io::Write::write`]: <https://doc.rust-lang.org/nightly/std/io/trait.Write.html#tymethod.write>")]
	///
	/// # Errors
	///
	/// This method should forward any errors that might
	/// arise from writing. A partial write is not
	/// considered an error.
	fn write(&mut self, buf: &[u8]) -> Result<usize>;

	/// Writes the entirety of provided buffer into the
	/// writer.
	///
	/// *See also [`std::io::Write::write_all`].*
	///
	#[cfg_attr(not(feature = "std"), doc = "[`std::io::Write::write_all`]: <https://doc.rust-lang.org/nightly/std/io/trait.Write.html#tymethod.write_all>")]
	///
	/// # Errors
	///
	/// This method should return an appropriate error
	/// if the writer could not be written to
	/// completely.
	fn write_all(&mut self, buf: &[u8]) -> Result<()>;
}

#[cfg(feature = "std")]
impl<T: ?Sized + io::Write> Write for T {
	#[inline]
	fn write(&mut self, buf: &[u8]) -> Result<usize> {
		io::Write::write(self, buf).map_err(Into::into)
	}

	#[inline]
	fn write_all(&mut self, buf: &[u8]) -> Result<()> {
		io::Write::write_all(self, buf).map_err(Into::into)
	}
}

// SORT: reference
#[cfg(not(feature = "std"))]
impl<T: ?Sized + Write> Write for &mut T {
	#[inline]
	fn write(&mut self, buf: &[u8]) -> Result<usize> {
		T::write(*self, buf)
	}

	#[inline]
	fn write_all(&mut self, buf: &[u8]) -> Result<()> {
		T::write_all(*self, buf)
	}
}

// SORT: slice
#[cfg(not(feature = "std"))]
impl Write for &mut [u8] {
	fn write(&mut self, buf: &[u8]) -> Result<usize> {
		let count = buf.len().min(self.len());

		let (slot, remaining) = take(self).split_at_mut(count);
		slot.copy_from_slice(buf);

		*self = remaining;
		Ok(count)
	}

	#[inline]
	fn write_all(&mut self, buf: &[u8]) -> Result<()> {
		if self.write(buf)? == buf.len() {
			Ok(())
		} else {
			Err(Error::write_zero())
		}
	}
}

#[cfg(all(feature = "alloc", not(feature = "std")))]
impl Write for Vec<u8> {
	fn write(&mut self, buf: &[u8]) -> Result<usize> {
		self.extend_from_slice(buf);
		Ok(buf.len())
	}

	#[inline]
	fn write_all(&mut self, buf: &[u8]) -> Result<()> {
		// NOTE: This always writes the entire buffer.
		self.write(buf)?;
		Ok(())
	}
}