feat(slice-4): v0.0.49 — core2 yanked unblock + sc-service WIP (crates.io API gap found)

Slice 4 Ship 2 parcial. RESUELVE el blocker real que difirió sc-service 3
sesiones (core2 yanked), pero DESCUBRE un segundo bloqueo arquitectural que
requiere decisión de David. Build verde, 213 tests, sin regresiones.

=== RESUELTO: core2 yanked (el muro de 3 sesiones) ===
sc-network-types 0.16 → cid ^0.9 (0.9.0 yanked) → core2 ^0.4 (0.4.0 yanked,
las no-yanked son 0.3.x que no satisfacen ^0.4). Cargo no auto-selecciona
versiones yanked → resolución fallaba. Era exactamente lo documentado en
chain_spec.rs Slice 3 que difirió sc-service.
Fix: vendorizado el .crate publicado de core2 0.4.0 (yanked pero descargable)
en vendor/core2-0.4.0/ + [patch.crates-io] core2 = { path = ... }. Una path
source es seleccionable independiente del estado yanked. El git source
(technocreatives/core2 master) resultó ser workspace ≤0.3.x, no servía.

=== DESCUBIERTO: crates.io consensus crates ≠ git tag API ===
Las crates sc-/sp- consensus PUBLICADAS (sc-consensus-aura 0.52.0 +
sp-consensus-aura 0.45.0) tienen API DISTINTA al git tag polkadot-stable2509-3
bajo el MISMO número de versión:
- git tag: sc_consensus_aura::standalone::slot_duration_at +
  sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration
- crates.io: slot_duration_at en root + NO existe slot InherentDataProvider
  (Slot no implementa el trait; Slot::from_timestamp toma 1 arg)
polkadot-sdk reusa números de versión con cambios git no publicados.

Construir un node service real requiere migrar TODO el stack sc-/sp- consensus
a git sources del tag — la misma cirugía duplicate-crate que golpeó pallet-revive
(Ship 2 v0.0.39). Decisión arquitectural para David.

Cambios:
- Cargo.toml: [patch.crates-io] core2 path vendor + sp-timestamp 39 + sp-blockchain 41
- vendor/core2-0.4.0/: crate vendorizado (yanked artifact original)
- node Cargo.toml: 13 sc-* + sp- consensus deps + jsonrpsee/rpc + core2 unblock dep
- node src/service.rs + rpc.rs: WIP escritos (verbatim stable2509-3 + 2 fixes API
  crates.io), NO mod-declarados (preservados para siguiente fase)
- node src/main.rs: finding documentado, mods service/rpc neutralizados

Verificación:
- cargo check -p origin-chain-node: EXIT 0 (deps resuelven vía core2, mods off)
- cargo test --workspace: 213 verde, 0 fail, sin regresiones
- core2 0.4.0 + cid 0.9.0 ahora en Cargo.lock (vía path patch)

Próximo: decisión David — (A) migrar sc-/sp- consensus a git sources tag
stable2509-3 (real node, riesgo duplicate-crate) vs (B) mantener publicadas
(node service diferido a futura generación Substrate). Ver SLICE_4 plan §10.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
davidherranandClaude Opus 4.8 committed 2026-05-30 11:33:57 -05:00
1 parent 05b6c70fca
commit e0e0b907b7
24 files changed
+12242 -227

No files matched your search

File diff suppressed because it is too large. Load diff
+272
View File
@@ -0,0 +1,272 @@
use super::{BufRead, Error, ErrorKind, Read, Result, Seek, SeekFrom, Write};
use core::cmp;
/// A `Cursor` wraps an in-memory buffer and provides it with a
/// [`Seek`] implementation.
///
/// `Cursor`s are used with in-memory buffers, anything implementing
/// [`AsRef`]`<[u8]>`, to allow them to implement [`Read`] and/or [`Write`],
/// allowing these buffers to be used anywhere you might use a reader or writer
/// that does actual I/O.
///
/// The standard library implements some I/O traits on various types which
/// are commonly used as a buffer, like `Cursor<`[`Vec`]`<u8>>` and
/// `Cursor<`[`&[u8]`][bytes]`>`.
///
/// # Examples
///
/// We may want to write bytes to a [`File`] in our production
/// code, but use an in-memory buffer in our tests. We can do this with
/// `Cursor`:
///
/// [bytes]: crate::slice
/// [`File`]: crate::fs::File
///
/// ```
/// use std::io::prelude::*;
/// use core2::io::{self, Seek, SeekFrom, Write};
/// use std::fs::File;
///
/// // a library function we've written
/// fn write_ten_bytes_at_end<W: Write + Seek>(writer: &mut W) -> io::Result<()> {
/// writer.seek(SeekFrom::End(-10))?;
///
/// for i in 0..10 {
/// writer.write(&[i])?;
/// }
///
/// // all went well
/// Ok(())
/// }
///
/// # #[cfg(feature = "std")]
/// # fn foo() -> io::Result<()> {
/// // Here's some code that uses this library function.
/// //
/// // We might want to use a BufReader here for efficiency, but let's
/// // keep this example focused.
/// let mut file = File::create("foo.txt").map_err(|e| io::Error::from(e))?;
///
/// write_ten_bytes_at_end(&mut file)?;
/// # Ok(())
/// # }
///
/// // now let's write a test
/// #[test]
/// fn test_writes_bytes() {
/// // setting up a real File is much slower than an in-memory buffer,
/// // let's use a cursor instead
/// use core2::io::Cursor;
/// let mut buff = Cursor::new(vec![0; 15]);
///
/// write_ten_bytes_at_end(&mut buff).unwrap();
///
/// assert_eq!(&buff.get_ref()[5..15], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
/// }
/// ```
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Cursor<T> {
inner: T,
pos: u64,
}
impl<T> Cursor<T> {
/// Creates a new cursor wrapping the provided underlying in-memory buffer.
///
/// Cursor initial position is `0` even if underlying buffer (e.g., [`Vec`])
/// is not empty. So writing to cursor starts with overwriting [`Vec`]
/// content, not with appending to it.
///
/// # Examples
///
/// ```
/// use core2::io::Cursor;
///
/// let buff = Cursor::new(Vec::new());
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
/// # force_inference(&buff);
/// ```
pub fn new(inner: T) -> Cursor<T> {
Cursor { pos: 0, inner }
}
/// Consumes this cursor, returning the underlying value.
///
/// # Examples
///
/// ```
/// use core2::io::Cursor;
///
/// let buff = Cursor::new(Vec::new());
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
/// # force_inference(&buff);
///
/// let vec = buff.into_inner();
/// ```
pub fn into_inner(self) -> T {
self.inner
}
/// Gets a reference to the underlying value in this cursor.
///
/// # Examples
///
/// ```
/// use core2::io::Cursor;
///
/// let buff = Cursor::new(Vec::new());
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
/// # force_inference(&buff);
///
/// let reference = buff.get_ref();
/// ```
pub fn get_ref(&self) -> &T {
&self.inner
}
/// Gets a mutable reference to the underlying value in this cursor.
///
/// Care should be taken to avoid modifying the internal I/O state of the
/// underlying value as it may corrupt this cursor's position.
///
/// # Examples
///
/// ```
/// use core2::io::Cursor;
///
/// let mut buff = Cursor::new(Vec::new());
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
/// # force_inference(&buff);
///
/// let reference = buff.get_mut();
/// ```
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner
}
/// Returns the current position of this cursor.
///
/// # Examples
///
/// ```
/// use core2::io::{Cursor, Seek, SeekFrom};
/// use std::io::prelude::*;
///
/// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
///
/// assert_eq!(buff.position(), 0);
///
/// buff.seek(SeekFrom::Current(2)).unwrap();
/// assert_eq!(buff.position(), 2);
///
/// buff.seek(SeekFrom::Current(-1)).unwrap();
/// assert_eq!(buff.position(), 1);
/// ```
pub fn position(&self) -> u64 {
self.pos
}
/// Sets the position of this cursor.
///
/// # Examples
///
/// ```
/// use core2::io::Cursor;
///
/// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
///
/// assert_eq!(buff.position(), 0);
///
/// buff.set_position(2);
/// assert_eq!(buff.position(), 2);
///
/// buff.set_position(4);
/// assert_eq!(buff.position(), 4);
/// ```
pub fn set_position(&mut self, pos: u64) {
self.pos = pos;
}
}
impl<T> Seek for Cursor<T>
where
T: AsRef<[u8]>,
{
fn seek(&mut self, style: SeekFrom) -> Result<u64> {
let (base_pos, offset) = match style {
SeekFrom::Start(n) => {
self.pos = n;
return Ok(n);
}
SeekFrom::End(n) => (self.inner.as_ref().len() as u64, n),
SeekFrom::Current(n) => (self.pos, n),
};
let new_pos = if offset >= 0 {
base_pos.checked_add(offset as u64)
} else {
base_pos.checked_sub((offset.wrapping_neg()) as u64)
};
match new_pos {
Some(n) => {
self.pos = n;
Ok(self.pos)
}
None => Err(Error::new(
ErrorKind::InvalidInput,
"invalid seek to a negative or overflowing position",
)),
}
}
}
impl<T> Read for Cursor<T>
where
T: AsRef<[u8]>,
{
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let n = Read::read(&mut self.fill_buf()?, buf)?;
self.pos += n as u64;
Ok(n)
}
fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
let n = buf.len();
Read::read_exact(&mut self.fill_buf()?, buf)?;
self.pos += n as u64;
Ok(())
}
}
impl<T> BufRead for Cursor<T>
where
T: AsRef<[u8]>,
{
fn fill_buf(&mut self) -> Result<&[u8]> {
let amt = cmp::min(self.pos, self.inner.as_ref().len() as u64);
Ok(&self.inner.as_ref()[(amt as usize)..])
}
fn consume(&mut self, amt: usize) {
self.pos += amt as u64;
}
}
// Non-resizing write implementation
#[inline]
fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> Result<usize> {
let pos = cmp::min(*pos_mut, slice.len() as u64);
let amt = (&mut slice[(pos as usize)..]).write(buf)?;
*pos_mut += amt as u64;
Ok(amt)
}
impl Write for Cursor<&mut [u8]> {
#[inline]
fn write(&mut self, buf: &[u8]) -> Result<usize> {
slice_write(&mut self.pos, self.inner, buf)
}
#[inline]
fn flush(&mut self) -> Result<()> {
Ok(())
}
}
+458
View File
@@ -0,0 +1,458 @@
use core::{convert::From, fmt, result};
/// A specialized [`Result`] type for I/O operations.
///
/// This type is broadly used across [`std::io`] for any operation which may
/// produce an error.
///
/// This typedef is generally used to avoid writing out [`io::Error`] directly and
/// is otherwise a direct mapping to [`Result`].
///
/// While usual Rust style is to import types directly, aliases of [`Result`]
/// often are not, to make it easier to distinguish between them. [`Result`] is
/// generally assumed to be [`std::result::Result`][`Result`], and so users of this alias
/// will generally use `io::Result` instead of shadowing the [prelude]'s import
/// of [`std::result::Result`][`Result`].
///
/// [`std::io`]: crate::io
/// [`io::Error`]: Error
/// [`Result`]: crate::result::Result
/// [prelude]: crate::prelude
///
/// # Examples
///
/// A convenience function that bubbles an `io::Result` to its caller:
///
/// ```
/// use core2::io;
///
/// #[cfg(feature = "std")]
/// fn get_string() -> io::Result<String> {
/// let mut buffer = String::new();
///
/// std::io::stdin().read_line(&mut buffer).map_err(|e| io::Error::from(e))?;
///
/// Ok(buffer)
/// }
/// ```
pub type Result<T> = result::Result<T, Error>;
/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and
/// associated traits.
///
/// Errors mostly originate from the underlying OS, but custom instances of
/// `Error` can be created with crafted error messages and a particular value of
/// [`ErrorKind`].
///
/// [`Read`]: crate::io::Read
/// [`Write`]: crate::io::Write
/// [`Seek`]: crate::io::Seek
pub struct Error {
repr: Repr,
}
impl crate::error::Error for Error {}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.repr, f)
}
}
enum Repr {
Simple(ErrorKind),
Custom(Custom),
}
#[derive(Debug)]
struct Custom {
kind: ErrorKind,
error: &'static str,
}
/// A list specifying general categories of I/O error.
///
/// This list is intended to grow over time and it is not recommended to
/// exhaustively match against it.
///
/// It is used with the [`io::Error`] type.
///
/// [`io::Error`]: Error
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
// #[allow(deprecated)]
#[non_exhaustive]
pub enum ErrorKind {
/// An entity was not found, often a file.
NotFound,
/// The operation lacked the necessary privileges to complete.
PermissionDenied,
/// The connection was refused by the remote server.
ConnectionRefused,
/// The connection was reset by the remote server.
ConnectionReset,
/// The connection was aborted (terminated) by the remote server.
ConnectionAborted,
/// The network operation failed because it was not connected yet.
NotConnected,
/// A socket address could not be bound because the address is already in
/// use elsewhere.
AddrInUse,
/// A nonexistent interface was requested or the requested address was not
/// local.
AddrNotAvailable,
/// The operation failed because a pipe was closed.
BrokenPipe,
/// An entity already exists, often a file.
AlreadyExists,
/// The operation needs to block to complete, but the blocking operation was
/// requested to not occur.
WouldBlock,
/// A parameter was incorrect.
InvalidInput,
/// Data not valid for the operation were encountered.
///
/// Unlike [`InvalidInput`], this typically means that the operation
/// parameters were valid, however the error was caused by malformed
/// input data.
///
/// For example, a function that reads a file into a string will error with
/// `InvalidData` if the file's contents are not valid UTF-8.
///
/// [`InvalidInput`]: ErrorKind::InvalidInput
InvalidData,
/// The I/O operation's timeout expired, causing it to be canceled.
TimedOut,
/// An error returned when an operation could not be completed because a
/// call to [`write`] returned [`Ok(0)`].
///
/// This typically means that an operation could only succeed if it wrote a
/// particular number of bytes but only a smaller number of bytes could be
/// written.
///
/// [`write`]: crate::io::Write::write
/// [`Ok(0)`]: Ok
WriteZero,
/// This operation was interrupted.
///
/// Interrupted operations can typically be retried.
Interrupted,
/// Any I/O error not part of this list.
///
/// Errors that are `Other` now may move to a different or a new
/// [`ErrorKind`] variant in the future. It is not recommended to match
/// an error against `Other` and to expect any additional characteristics,
/// e.g., a specific [`Error::raw_os_error`] return value.
Other,
/// An error returned when an operation could not be completed because an
/// "end of file" was reached prematurely.
///
/// This typically means that an operation could only succeed if it read a
/// particular number of bytes but only a smaller number of bytes could be
/// read.
UnexpectedEof,
/// Any I/O error from the standard library that's not part of this list.
///
/// Errors that are `Uncategorized` now may move to a different or a new
/// [`ErrorKind`] variant in the future. It is not recommended to match
/// an error against `Uncategorized`; use a wildcard match (`_`) instead.
#[doc(hidden)]
Uncategorized,
}
impl ErrorKind {
pub(crate) fn as_str(&self) -> &'static str {
match *self {
ErrorKind::NotFound => "entity not found",
ErrorKind::PermissionDenied => "permission denied",
ErrorKind::ConnectionRefused => "connection refused",
ErrorKind::ConnectionReset => "connection reset",
ErrorKind::ConnectionAborted => "connection aborted",
ErrorKind::NotConnected => "not connected",
ErrorKind::AddrInUse => "address in use",
ErrorKind::AddrNotAvailable => "address not available",
ErrorKind::BrokenPipe => "broken pipe",
ErrorKind::AlreadyExists => "entity already exists",
ErrorKind::WouldBlock => "operation would block",
ErrorKind::InvalidInput => "invalid input parameter",
ErrorKind::InvalidData => "invalid data",
ErrorKind::TimedOut => "timed out",
ErrorKind::WriteZero => "write zero",
ErrorKind::Interrupted => "operation interrupted",
ErrorKind::Other => "other os error",
ErrorKind::UnexpectedEof => "unexpected end of file",
ErrorKind::Uncategorized => "uncategorized",
}
}
}
#[cfg(feature = "std")]
impl From<std::io::ErrorKind> for ErrorKind {
/// Converts an [`std::io::ErrorKind`] into an [`ErrorKind`].
///
/// This conversion allocates a new error with a simple representation of error kind.
///
/// # Examples
///
/// ```
/// use core2::io::{Error, ErrorKind};
///
/// let not_found = ErrorKind::from(std::io::ErrorKind::NotFound);
/// let err: Error = not_found.into();
/// assert_eq!("entity not found", format!("{}", err));
/// ```
fn from(k: std::io::ErrorKind) -> Self {
match k {
std::io::ErrorKind::NotFound => ErrorKind::NotFound,
std::io::ErrorKind::PermissionDenied => ErrorKind::PermissionDenied,
std::io::ErrorKind::ConnectionRefused => ErrorKind::ConnectionRefused,
std::io::ErrorKind::ConnectionReset => ErrorKind::ConnectionReset,
std::io::ErrorKind::ConnectionAborted => ErrorKind::ConnectionAborted,
std::io::ErrorKind::NotConnected => ErrorKind::NotConnected,
std::io::ErrorKind::AddrInUse => ErrorKind::AddrInUse,
std::io::ErrorKind::AddrNotAvailable => ErrorKind::AddrNotAvailable,
std::io::ErrorKind::BrokenPipe => ErrorKind::BrokenPipe,
std::io::ErrorKind::AlreadyExists => ErrorKind::AlreadyExists,
std::io::ErrorKind::WouldBlock => ErrorKind::WouldBlock,
std::io::ErrorKind::InvalidInput => ErrorKind::InvalidInput,
std::io::ErrorKind::InvalidData => ErrorKind::InvalidData,
std::io::ErrorKind::TimedOut => ErrorKind::TimedOut,
std::io::ErrorKind::WriteZero => ErrorKind::WriteZero,
std::io::ErrorKind::Interrupted => ErrorKind::Interrupted,
std::io::ErrorKind::Other => ErrorKind::Other,
std::io::ErrorKind::UnexpectedEof => ErrorKind::UnexpectedEof,
_ => ErrorKind::Uncategorized,
}
}
}
/// Intended for use for errors not exposed to the user, where allocating onto
/// the heap (for normal construction via Error::new) is too costly.
impl From<ErrorKind> for Error {
/// Converts an [`ErrorKind`] into an [`Error`].
///
/// This conversion allocates a new error with a simple representation of error kind.
///
/// # Examples
///
/// ```
/// use core2::io::{Error, ErrorKind};
///
/// let not_found = ErrorKind::NotFound;
/// let error = Error::from(not_found);
/// assert_eq!("entity not found", format!("{}", error));
/// ```
#[inline]
fn from(kind: ErrorKind) -> Error {
Error {
repr: Repr::Simple(kind),
}
}
}
#[cfg(feature = "std")]
impl From<std::io::Error> for Error {
/// Converts an [`std::io::ErrorKind`] into an [`Error`].
///
/// This conversion allocates a new error with a simple representation of error kind.
///
/// # Examples
///
/// ```
/// use core2::io::{Error, ErrorKind};
///
/// let not_found = std::io::Error::from(std::io::ErrorKind::NotFound);
/// let error = Error::from(not_found);
/// assert_eq!("entity not found", format!("{}", error));
/// ```
#[inline]
fn from(err: std::io::Error) -> Self {
Self::from(ErrorKind::from(err.kind()))
}
}
impl Error {
/// Creates a new I/O error from a known kind of error as well as an
/// arbitrary error payload.
///
/// This function is used to generically create I/O errors which do not
/// originate from the OS itself. The `error` argument is an arbitrary
/// payload which will be contained in this [`Error`].
///
/// # Examples
///
/// ```
/// use core2::io::{Error, ErrorKind};
///
/// // errors can be created from strings
/// let custom_error = Error::new(ErrorKind::Other, "oh no!");
///
/// // errors can also be created from other errors
/// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error.into_inner().unwrap());
/// ```
pub fn new(kind: ErrorKind, error: &'static str) -> Error {
Self::_new(kind, error.into())
}
fn _new(kind: ErrorKind, error: &'static str) -> Error {
Error {
repr: Repr::Custom(Custom { kind, error }),
}
}
/// Returns a reference to the inner error wrapped by this error (if any).
///
/// If this [`Error`] was constructed via [`new`] then this function will
/// return [`Some`], otherwise it will return [`None`].
///
/// [`new`]: Error::new
///
/// # Examples
///
/// ```
/// use core2::io::{Error, ErrorKind};
///
/// fn print_error(err: &Error) {
/// if let Some(inner_err) = err.get_ref() {
/// println!("Inner error: {:?}", inner_err);
/// } else {
/// println!("No inner error");
/// }
/// }
///
/// #[cfg(feature = "std")]
/// fn emit_error() {
/// // Will print "No inner error".
/// print_error(&Error::from(std::io::Error::last_os_error()));
/// // Will print "Inner error: ...".
/// print_error(&Error::new(ErrorKind::Other, "oh no!"));
/// }
///
/// #[cfg(not(feature = "std"))]
/// fn emit_error() {
/// // Will print "No inner error".
/// print_error(&ErrorKind::Other.into());
/// // Will print "Inner error: ...".
/// print_error(&Error::new(ErrorKind::Other, "oh no!"));
/// }
///
/// fn main() {
/// emit_error();
/// }
/// ```
pub fn get_ref(&self) -> Option<&&'static str> {
match self.repr {
Repr::Simple(..) => None,
Repr::Custom(ref c) => Some(&c.error),
}
}
/// Consumes the `Error`, returning its inner error (if any).
///
/// If this [`Error`] was constructed via [`new`] then this function will
/// return [`Some`], otherwise it will return [`None`].
///
/// [`new`]: Error::new
///
/// # Examples
///
/// ```
/// use core2::io::{Error, ErrorKind};
///
/// fn print_error(err: Error) {
/// if let Some(inner_err) = err.into_inner() {
/// println!("Inner error: {}", inner_err);
/// } else {
/// println!("No inner error");
/// }
/// }
///
/// #[cfg(feature = "std")]
/// fn emit_error() {
/// // Will print "No inner error".
/// print_error(std::io::Error::last_os_error().into());
/// // Will print "Inner error: ...".
/// print_error(Error::new(ErrorKind::Other, "oh no!"));
/// }
///
/// #[cfg(not(feature = "std"))]
/// fn emit_error() {
/// // Will print "No inner error".
/// print_error(ErrorKind::Other.into());
/// // Will print "Inner error: ...".
/// print_error(Error::new(ErrorKind::Other, "oh no!"));
/// }
///
/// fn main() {
/// emit_error();
/// }
/// ```
pub fn into_inner(self) -> Option<&'static str> {
match self.repr {
Repr::Simple(..) => None,
Repr::Custom(c) => Some(c.error),
}
}
/// Returns the corresponding [`ErrorKind`] for this error.
///
/// # Examples
///
/// ```
/// use core2::io::{Error, ErrorKind};
///
/// fn print_error(err: Error) {
/// println!("{:?}", err.kind());
/// }
///
/// #[cfg(feature = "std")]
/// fn emit_error() {
/// // Will print "Other".
/// print_error(std::io::Error::last_os_error().into());
/// // Will print "AddrInUse".
/// print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
/// }
///
/// #[cfg(not(feature = "std"))]
/// fn emit_error() {
/// // Will print "Other".
/// print_error(ErrorKind::Other.into());
/// // Will print "AddrInUse".
/// print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
/// }
///
/// fn main() {
/// emit_error();
/// }
/// ```
pub fn kind(&self) -> ErrorKind {
match self.repr {
Repr::Custom(ref c) => c.kind,
Repr::Simple(kind) => kind,
}
}
}
impl fmt::Debug for Repr {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt),
Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.repr {
Repr::Custom(ref c) => c.error.fmt(fmt),
Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()),
}
}
}
fn _assert_error_is_sync_send() {
fn _is_sync_send<T: Sync + Send>() {}
_is_sync_send::<Error>();
}
+176
View File
@@ -0,0 +1,176 @@
use super::error::{Error, ErrorKind, Result};
use super::traits::{BufRead, Read, Seek, SeekFrom, Write};
use core::{cmp, fmt, mem};
// =============================================================================
// Forwarding implementations
impl<R: Read + ?Sized> Read for &mut R {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
(**self).read(buf)
}
#[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
(**self).read_exact(buf)
}
}
impl<W: Write + ?Sized> Write for &mut W {
#[inline]
fn write(&mut self, buf: &[u8]) -> Result<usize> {
(**self).write(buf)
}
#[inline]
fn flush(&mut self) -> Result<()> {
(**self).flush()
}
#[inline]
fn write_all(&mut self, buf: &[u8]) -> Result<()> {
(**self).write_all(buf)
}
#[inline]
fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<()> {
(**self).write_fmt(fmt)
}
}
impl<S: Seek + ?Sized> Seek for &mut S {
#[inline]
fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
(**self).seek(pos)
}
}
impl<B: BufRead + ?Sized> BufRead for &mut B {
#[inline]
fn fill_buf(&mut self) -> Result<&[u8]> {
(**self).fill_buf()
}
#[inline]
fn consume(&mut self, amt: usize) {
(**self).consume(amt)
}
}
// =============================================================================
// In-memory buffer implementations
/// Read is implemented for `&[u8]` by copying from the slice.
///
/// Note that reading updates the slice to point to the yet unread part.
/// The slice will be empty when EOF is reached.
impl Read for &[u8] {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let amt = cmp::min(buf.len(), self.len());
let (a, b) = self.split_at(amt);
// First check if the amount of bytes we want to read is small:
// `copy_from_slice` will generally expand to a call to `memcpy`, and
// for a single byte the overhead is significant.
if amt == 1 {
buf[0] = a[0];
} else {
buf[..amt].copy_from_slice(a);
}
*self = b;
Ok(amt)
}
#[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
if buf.len() > self.len() {
return Err(Error::new(
ErrorKind::UnexpectedEof,
"failed to fill whole buffer",
));
}
let (a, b) = self.split_at(buf.len());
// First check if the amount of bytes we want to read is small:
// `copy_from_slice` will generally expand to a call to `memcpy`, and
// for a single byte the overhead is significant.
if buf.len() == 1 {
buf[0] = a[0];
} else {
buf.copy_from_slice(a);
}
*self = b;
Ok(())
}
}
impl BufRead for &[u8] {
#[inline]
fn fill_buf(&mut self) -> Result<&[u8]> {
Ok(*self)
}
#[inline]
fn consume(&mut self, amt: usize) {
*self = &self[amt..];
}
}
/// Write is implemented for `&mut [u8]` by copying into the slice, overwriting
/// its data.
///
/// Note that writing updates the slice to point to the yet unwritten part.
/// The slice will be empty when it has been completely overwritten.
impl Write for &mut [u8] {
#[inline]
fn write(&mut self, data: &[u8]) -> Result<usize> {
let amt = cmp::min(data.len(), self.len());
let (a, b) = mem::replace(self, &mut []).split_at_mut(amt);
a.copy_from_slice(&data[..amt]);
*self = b;
Ok(amt)
}
#[inline]
fn write_all(&mut self, data: &[u8]) -> Result<()> {
if self.write(data)? == data.len() {
Ok(())
} else {
Err(Error::new(
ErrorKind::WriteZero,
"failed to write whole buffer",
))
}
}
#[inline]
fn flush(&mut self) -> Result<()> {
Ok(())
}
}
/// Write is implemented for `Vec<u8>` by appending to the vector.
/// The vector will grow as needed.
#[cfg(feature = "alloc")]
impl Write for alloc::vec::Vec<u8> {
#[inline]
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<()> {
self.extend_from_slice(buf);
Ok(())
}
#[inline]
fn flush(&mut self) -> Result<()> {
Ok(())
}
}
+26
View File
@@ -0,0 +1,26 @@
#[cfg(feature = "nightly")]
mod buffered;
mod cursor;
mod error;
mod impls;
mod traits;
mod util;
#[cfg(not(feature = "std"))]
pub use cursor::Cursor;
#[cfg(not(feature = "std"))]
pub use error::{Error, ErrorKind, Result};
#[cfg(not(feature = "std"))]
pub use traits::{BufRead, Bytes, Chain, Read, Seek, SeekFrom, Take, Write};
#[cfg(feature = "std")]
pub use std::io::{
BufRead, Bytes, Chain, Cursor, Error, ErrorKind, Read, Result, Seek, SeekFrom, Take, Write,
};
// Use this crate's implementation on both std and no_std
#[cfg(feature = "nightly")]
pub use buffered::{BufReader, BufWriter, LineWriter};
#[cfg(feature = "nightly")]
pub use util::copy;
File diff suppressed because it is too large. Load diff
+40
View File
@@ -0,0 +1,40 @@
#[cfg(feature = "nightly")]
use core::mem::MaybeUninit;
#[cfg(feature = "nightly")]
use crate::io::{ErrorKind, Read, Write};
#[cfg(feature = "nightly")]
pub fn copy<R: ?Sized, W: ?Sized, const S: usize>(
reader: &mut R,
writer: &mut W,
) -> crate::io::Result<u64>
where
R: Read,
W: Write,
{
let mut buf = MaybeUninit::<[u8; S]>::uninit();
// FIXME: #42788
//
// - This creates a (mut) reference to a slice of
// _uninitialized_ integers, which is **undefined behavior**
//
// - Only the standard library gets to soundly "ignore" this,
// based on its privileged knowledge of unstable rustc
// internals;
unsafe {
reader.initializer().initialize(buf.assume_init_mut());
}
let mut written = 0;
loop {
let len = match reader.read(unsafe { buf.assume_init_mut() }) {
Ok(0) => return Ok(written),
Ok(len) => len,
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
};
writer.write_all(unsafe { &buf.assume_init_ref()[..len] })?;
written += len as u64;
}
}