diff --git a/Cargo.toml b/Cargo.toml index cedccc8..e3ece6d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,6 @@ [workspace] resolver = "2" members = [ - "byst", - "byst-macros", "skunk", "skunk-api-client", "skunk-api-protocol", diff --git a/byst-macros/Cargo.toml b/byst-macros/Cargo.toml deleted file mode 100644 index aeeea25..0000000 --- a/byst-macros/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "byst-macros" -version = "0.1.0" -edition = "2021" - -[lib] -proc-macro = true - -[dependencies] -thiserror = "1" -syn = { version = "2", features = ["full", "extra-traits", "parsing", "printing"] } -proc-macro2 = "1" -quote = "1" -darling = "0.20" -proc-macro-error = "1" diff --git a/byst-macros/src/bitmask.rs b/byst-macros/src/bitmask.rs deleted file mode 100644 index aedfc1c..0000000 --- a/byst-macros/src/bitmask.rs +++ /dev/null @@ -1,57 +0,0 @@ -use proc_macro2::{ - Span, - TokenStream, -}; -use quote::quote; -use syn::{ - parse::{ - Parse, - ParseStream, - }, - LitInt, - Token, -}; - -use crate::error::Error; - -pub fn bit_range(input: BitRangeInput) -> Result { - let mut mask = 0u128; - let mut bits = input.max - input.min; - while bits > 0 { - mask = (mask << 1) | 1; - bits -= 1; - } - mask <<= input.min; - - let lit = LitInt::new(&format!("{mask}"), Span::call_site()); - Ok(quote! { #lit }) -} - -#[derive(Debug)] -pub struct BitRangeInput { - pub min: usize, - pub max: usize, -} - -impl Parse for BitRangeInput { - fn parse(input: ParseStream) -> Result { - let min = input - .parse::>()? - .map(|n| n.base10_parse::()) - .transpose()? - .unwrap_or_default(); - - let dotdoteq = input.parse::>()?; - let max = if dotdoteq.is_some() { - input.parse::()?.base10_parse::()? + 1 - } - else if input.parse::>()?.is_some() { - input.parse::()?.base10_parse::()? - } - else { - min - }; - - Ok(Self { min, max }) - } -} diff --git a/byst-macros/src/error.rs b/byst-macros/src/error.rs deleted file mode 100644 index c939aaa..0000000 --- a/byst-macros/src/error.rs +++ /dev/null @@ -1,19 +0,0 @@ -use proc_macro2::TokenStream; - -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("syn error")] - Syn(#[from] syn::Error), - - #[error("darling error")] - Darling(#[from] darling::Error), -} - -impl Error { - pub fn write_errors(self) -> TokenStream { - match self { - Error::Syn(e) => e.into_compile_error(), - Error::Darling(e) => e.write_errors(), - } - } -} diff --git a/byst-macros/src/for_tuple.rs b/byst-macros/src/for_tuple.rs deleted file mode 100644 index 3efba2d..0000000 --- a/byst-macros/src/for_tuple.rs +++ /dev/null @@ -1,87 +0,0 @@ -use proc_macro2::{ - Span, - TokenStream, -}; -use quote::quote; -use syn::{ - parse::{ - Parse, - ParseStream, - }, - Ident, - Index, - LitInt, - Path, - Token, -}; - -use crate::error::Error; - -#[derive(Debug)] -pub struct ForTupleInput { - pub callback: Path, - pub min: usize, - pub max: usize, -} - -impl Parse for ForTupleInput { - fn parse(input: ParseStream) -> Result { - let callback: Path = input.parse()?; - - input.parse::()?; - input.parse::()?; - - let min = input - .parse::>()? - .map(|n| n.base10_parse::()) - .transpose()? - .unwrap_or_default(); - - let dotdoteq = input.parse::>()?; - let to_inclusive = if dotdoteq.is_some() { - true - } - else { - if input.parse::>()?.is_none() { - return Err(input.error("Expected either `..` or `..=`")); - } - false - }; - - let max = input.parse::()?.base10_parse::()? - + to_inclusive.then_some(1).unwrap_or_default(); - - Ok(Self { callback, min, max }) - } -} - -pub fn for_tuple(input: ForTupleInput) -> Result { - let callback = &input.callback; - - let mut indices = Vec::with_capacity(input.max); - let mut names = Vec::with_capacity(input.max); - let mut tys = Vec::with_capacity(input.max); - for i in 0..input.max { - indices.push(Index { - index: i as u32, - span: Span::call_site(), - }); - names.push(Ident::new(&format!("_{}", i + 1), Span::call_site())); - tys.push(Ident::new(&format!("T{}", i + 1), Span::call_site())); - } - let mut output = vec![]; - - for i in input.min..input.max { - let index = &indices[..i]; - let name = &names[..i]; - let ty = &tys[..i]; - - output.push(quote! { - #callback!(#(#index => #name: #ty),*); - }); - } - - Ok(quote! { - #(#output)* - }) -} diff --git a/byst-macros/src/lib.rs b/byst-macros/src/lib.rs deleted file mode 100644 index 5ae52e0..0000000 --- a/byst-macros/src/lib.rs +++ /dev/null @@ -1,124 +0,0 @@ -//! Macros for the `byst` crate. - -#![allow(dead_code, rustdoc::broken_intra_doc_links)] -mod bitmask; -mod error; -mod for_tuple; -mod read_write; -mod util; - -use proc_macro_error::proc_macro_error; -use syn::parse_macro_input; -use util::Deriver; - -use crate::{ - bitmask::BitRangeInput, - for_tuple::ForTupleInput, -}; - -/// Derive [`Read`][1] implementation. -/// -/// # Example -/// -/// Deriving [`Read`][1] on a struct will generate an implementation that reads -/// the fields in the order they appear in the declaration. -/// -/// ```ignore -/// # use byst_macros::Read; -/// # type NetworkEndian = (); -/// # type Bar = (); -/// -/// #[derive(Read)] -/// struct Foo { -/// // Can contain integers. -/// // -/// // For anything other than `u8` and `i8` you need to specify the endianness. Valid attributes are `little`, `big`, `network`, `native`. -/// #[skunk(little)] -/// x: u32, -/// -/// // Can contain other stucts that can be read. -/// bar: Bar, -/// } -/// ``` -/// -/// [1]: skunk::util::bytes::rw::Read -#[proc_macro_error] -#[proc_macro_derive(Read, attributes(byst))] -pub fn derive_read(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - self::read_write::DeriveRead::process(input) -} - -#[proc_macro_error] -#[proc_macro_derive(Write, attributes(byst))] -pub fn derive_write(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - self::read_write::DeriveWrite::process(input) -} - -/// Calls another macro with tuples of specified lengths. -/// -/// This is useful to implement for tuple types. -/// -/// The callback macro will be passed a comma-separated list of -/// -/// ```no_rust -/// $index:tt => $name:ident : $ty:ident -/// ``` -/// -/// where: -/// -/// - `$index` is the index for that entry, to be used for field access. -/// - `$name` is a generated identifier of form `_$index`, to be used as -/// variables. -/// - `$ty` is the type of that entry. -/// -/// # Example -/// -/// ``` -/// # use byst_macros::for_tuple; -/// # trait Foo { fn foo(&self); } -/// macro_rules! impl_tuple { -/// ($($index:tt => $name:ident : $ty:ident),*) => { -/// impl<$($ty),*> Foo for ($($ty,)*) { -/// fn foo(&self) { -/// $( -/// let $name = &self.$index; -/// )* -/// // do something with variables -/// } -/// } -/// // do stuff here -/// } -/// } -/// -/// // Implements Foo for tuples of size 1 to 8 (inclusive). -/// for_tuple!(impl_tuple! for 1..=8); -/// ``` -/// -/// Note that the `impl` is on the type `($($ty,))` with the comma inside, such -/// that `(T,)` is a tuple. -#[proc_macro] -pub fn for_tuple(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let input = parse_macro_input!(input as ForTupleInput); - match crate::for_tuple::for_tuple(input) { - Ok(output) => output.into(), - Err(e) => e.write_errors().into(), - } -} - -/// Generates a bit mask for the given range. The output will be an integer -/// literal. -/// -/// # Example -/// -/// ``` -/// # use byst_macros::bit_range; -/// let x = bit_range!(4..=8); -/// ``` -#[proc_macro] -pub fn bit_range(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let input = parse_macro_input!(input as BitRangeInput); - match crate::bitmask::bit_range(input) { - Ok(output) => output.into(), - Err(e) => e.write_errors().into(), - } -} diff --git a/byst-macros/src/read_write/mod.rs b/byst-macros/src/read_write/mod.rs deleted file mode 100644 index 91e5aba..0000000 --- a/byst-macros/src/read_write/mod.rs +++ /dev/null @@ -1,359 +0,0 @@ -mod read; -mod write; - -use darling::{ - FromDeriveInput, - FromField, - FromMeta, - FromVariant, -}; -use proc_macro2::{ - Span, - TokenStream, -}; -use proc_macro_error::{ - abort, - abort_call_site, -}; -use quote::quote; -use syn::{ - parse::Parser, - parse_quote, - parse_quote_spanned, - Expr, - ExprLit, - Ident, - Lit, - Pat, - Path, - Type, - WhereClause, -}; - -pub use self::{ - read::DeriveRead, - write::DeriveWrite, -}; - -#[derive(FromDeriveInput)] -#[darling(attributes(byst), forward_attrs(allow, doc, cfg))] -pub struct DeriveOptions { - #[darling(default)] - pub transparent: bool, - - pub context: Option, - pub error: Option, - - pub tag: Option, - pub match_expr: Option, - #[darling(default)] - pub no_wild: bool, -} - -impl DeriveOptions { - pub fn check_for_struct(&self) { - if self.tag.is_some() { - abort_call_site!("Cant use `tag` for structs."); - } - if self.match_expr.is_some() { - abort_call_site!("Cant use `match_expr` for structs."); - } - if self.no_wild { - abort_call_site!("Cant use `no_wild` for structs."); - } - } - - pub fn check_for_transparent(&self) { - if self.context.is_some() - || self.error.is_some() - || self.tag.is_some() - || self.match_expr.is_some() - || self.no_wild - { - abort_call_site!("No other options are valid when deriving as view."); - } - } - - pub fn context(&self) -> (Ident, Type) { - let (ident, ty) = if let Some(context) = &self.context { - (context.name.clone(), Some(context.ty.clone())) - } - else { - (None, None) - }; - ( - ident.unwrap_or_else(|| parse_quote! { __context }), - ty.unwrap_or_else(|| parse_quote! { () }), - ) - } - - pub fn tag_expr(&self, track: &mut DeriveBounds) -> Expr { - if let Some(expr) = &self.match_expr { - expr.clone() - } - else if let Some(tag) = &self.tag { - let tag_ty = &tag.ty; - let (context_ty, context_expr) = tag.context(); - - track.reads(tag_ty, &context_ty); - - parse_quote! { - <#tag_ty as ::byst::io::Read::<_, #context_ty>>::read(&mut __reader, #context_expr)? - } - } - else { - abort_call_site!("Either a tag type, or a match expression must be specified"); - } - } - - pub fn tag_ty(&self) -> Option<&Type> { - self.tag.as_ref().map(|d| &d.ty) - } -} - -#[derive(FromMeta)] -pub struct ContextDeriveOptions { - pub name: Option, - pub ty: Type, -} - -#[derive(FromMeta)] -pub struct TagDeriveOptions { - pub ty: Type, - #[darling(flatten)] - pub endianness: Endianness, - pub context: Option, -} - -impl TagDeriveOptions { - pub fn context(&self) -> (Type, Expr) { - context(&self.endianness, self.context.as_ref()) - } -} - -#[derive(FromField)] -#[darling(attributes(byst))] -pub struct FieldOptions { - pub ident: Option, - pub ty: Type, - - pub skip: Option, - - #[darling(flatten)] - pub endianness: Endianness, - - pub context: Option, - pub map_err: Option, -} - -impl FieldOptions { - pub fn span(&self) -> Span { - if let Some(ident) = &self.ident { - ident.span() - } - else { - Span::call_site() - } - } - - pub fn skip(&self) -> Option { - self.skip.as_ref().map(|skip| { - if let Some(with) = &skip.with { - with.clone() - } - else { - let ty = &self.ty; - parse_quote_spanned! { self.span() => <#ty as ::std::default::Default>::default() } - } - }) - } - - pub fn context(&self) -> (Type, Expr) { - context(&self.endianness, self.context.as_ref()) - } - - pub fn map_err(&self) -> Path { - self.map_err - .clone() - .unwrap_or_else(|| parse_quote! { std::convert::identity }) - } -} - -fn context(endianness: &Endianness, context: Option<&ContextFieldOptions>) -> (Type, Expr) { - match (endianness.ty(), context) { - (None, None) => (parse_quote! { () }, parse_quote! { () }), - (Some(endianness), None) => (endianness.clone(), parse_quote! { #endianness }), - (None, Some(context)) => { - ( - context.ty.clone(), - context - .with - .clone() - .unwrap_or_else(|| parse_quote! { ::std::default::Default::default() }), - ) - } - _ => abort_call_site!("Endianness can not be specified, when also specifying context."), - } -} - -#[derive(FromVariant)] -#[darling(attributes(byst))] -pub struct VariantOptions { - ident: Ident, - discriminant: Option, - #[darling(rename = "tag")] - pat: Option, -} - -impl VariantOptions { - pub fn span(&self) -> Span { - self.ident.span() - } - - pub fn pat(&self) -> Pat { - if let Some(pat) = &self.pat { - pat.0.clone() - } - else if let Some(discriminant) = &self.discriminant { - parse_quote_spanned! { self.span() => #discriminant } - } - else { - abort!( - self.span(), - "The variant `{}` either needs a discriminant, or a pattern specified.", - self.ident - ) - } - } -} - -pub struct DiscriminantPat(pub Pat); - -impl FromMeta for DiscriminantPat { - fn from_value(value: &Lit) -> Result { - match value { - Lit::Str(value) => Self::from_string(&value.value()), - _ => { - Ok(Self(Pat::Lit(ExprLit { - attrs: vec![], - lit: value.clone(), - }))) - } - } - } - - fn from_string(value: &str) -> Result { - Ok(Self(Parser::parse_str(Pat::parse_single, value)?)) - } -} - -#[derive(FromMeta)] -pub struct SkipFieldOptions { - pub with: Option, -} - -#[derive(FromMeta)] -pub struct ContextFieldOptions { - pub ty: Type, - pub with: Option, -} - -#[derive(FromMeta)] -pub struct Endianness { - #[darling(default)] - pub big: bool, - - #[darling(default)] - pub little: bool, - - #[darling(default)] - pub network: bool, - - #[darling(default)] - pub native: bool, -} - -impl Endianness { - pub fn ty(&self) -> Option { - match (self.big, self.little, self.network, self.native) { - (false, false, false, false) => None, - (true, false, false, false) => Some(parse_quote! { ::byst::endianness::BigEndian }), - (false, true, false, false) => Some(parse_quote! { ::byst::endianness::LittleEndian }), - (false, false, true, false) => Some(parse_quote! { ::byst::endianness::NetworkEndian }), - (false, false, false, true) => Some(parse_quote! { ::byst::endianness::NativeEndian }), - _ => { - abort_call_site!( - "Only one of `big`, `little`, `network`, `native`, or `endianness = PATH` may be specified." - ) - } - } - } -} - -pub struct DeriveBounds { - pub where_clause: WhereClause, - pub error_ty: Option, -} - -impl DeriveBounds { - pub fn new(where_clause: WhereClause, error_ty: Option) -> Self { - Self { - where_clause, - error_ty, - } - } - - pub fn reads(&mut self, field_ty: &Type, context_ty: &Type) { - self.add_bounds(field_ty, context_ty, quote! { __R }, quote! { Read }) - } - - pub fn writes(&mut self, field_ty: &Type, context_ty: &Type) { - self.add_bounds(field_ty, context_ty, quote! { __W }, quote! { Write }) - } - - fn add_bounds( - &mut self, - field_ty: &Type, - context_ty: &Type, - io_ty: TokenStream, - io_trait: TokenStream, - ) { - self.where_clause - .predicates - .push(parse_quote! { #field_ty: ::byst::io::#io_trait::<#io_ty, #context_ty> }); - - if let Some(error_ty) = &self.error_ty { - self.where_clause.predicates.push( - parse_quote! { #error_ty: ::std::convert::From<<#field_ty as ::byst::io::#io_trait::<#io_ty, #context_ty>>::Error> }, - ); - } - else { - self.error_ty = Some(parse_quote! { - <#field_ty as ::byst::io::#io_trait::<#io_ty, #context_ty>>::Error - }); - } - } - - pub fn finish(self) -> (WhereClause, Type) { - let error_ty = self - .error_ty - .unwrap_or_else(|| parse_quote! { ::std::convert::Infallible }); - (self.where_clause, error_ty) - } -} - -#[derive(FromMeta)] -pub struct Bitfield { - pub ty: Path, - - #[darling(flatten)] - pub endianness: Endianness, -} - -#[derive(FromField)] -#[darling(attributes(byst))] -pub struct BitfieldFieldOptions { - pub bits: Option, - pub start: Option, - pub end: Option, -} diff --git a/byst-macros/src/read_write/read.rs b/byst-macros/src/read_write/read.rs deleted file mode 100644 index ed79bd3..0000000 --- a/byst-macros/src/read_write/read.rs +++ /dev/null @@ -1,361 +0,0 @@ -use darling::{ - FromField, - FromVariant, -}; -use proc_macro2::TokenStream; -use proc_macro_error::{ - abort, - abort_call_site, -}; -use quote::quote; -use syn::{ - self, - parse_quote, - Data, - DataEnum, - DataStruct, - DeriveInput, - Fields, -}; - -use super::{ - Bitfield, - BitfieldFieldOptions, - DeriveBounds, - DeriveOptions, - FieldOptions, - VariantOptions, -}; -use crate::{ - error::Error, - util::{ - Deriver, - FieldName, - SplitGenerics, - }, -}; - -pub struct DeriveRead; - -impl Deriver for DeriveRead { - const NAME: &'static str = "Read"; - type Options = DeriveOptions; - - fn derive_for_item(item: DeriveInput, options: Self::Options) -> Result { - if options.transparent { - derive_transparent(item, options) - } - else { - match &item.data { - Data::Struct(s) => Self::derive_for_struct(s, &item, options), - Data::Enum(e) => Self::derive_for_enum(e, &item, options), - Data::Union(u) => Self::derive_for_union(u, &item, options), - } - } - } - - fn derive_for_struct( - data: &DataStruct, - item: &DeriveInput, - options: Self::Options, - ) -> Result { - let ident = &item.ident; - let (context_name, context_ty) = options.context(); - - let SplitGenerics { - mut impl_generics, - type_generics, - where_clause, - } = SplitGenerics::from_generics(&item.generics); - impl_generics.type_params.push(parse_quote! { __R }); - let mut bounds = DeriveBounds::new(where_clause, options.error.clone()); - - let (read_fields, struct_init) = make_struct_init(&data.fields, &mut bounds)?; - - let (where_clause, error_ty) = bounds.finish(); - - Ok(quote! { - #[automatically_derived] - impl #impl_generics ::byst::io::Read<__R, #context_ty> for #ident #type_generics #where_clause { - type Error = #error_ty; - - fn read(mut __reader: &mut __R, #context_name: #context_ty) -> ::std::result::Result { - #read_fields - ::std::result::Result::Ok(Self #struct_init) - } - } - }) - } - - fn derive_for_enum( - data: &DataEnum, - item: &DeriveInput, - options: Self::Options, - ) -> Result { - let ident = &item.ident; - let (context_name, context_ty) = options.context(); - - let SplitGenerics { - mut impl_generics, - type_generics, - where_clause, - } = SplitGenerics::from_generics(&item.generics); - impl_generics.type_params.push(parse_quote! { __R }); - let mut bounds = DeriveBounds::new(where_clause, options.error.clone()); - - let tag_expr = options.tag_expr(&mut bounds); - let mut match_arms = Vec::with_capacity(data.variants.len()); - - for variant in &data.variants { - let variant_options = VariantOptions::from_variant(variant)?; - let variant_name = &variant.ident; - let pat = variant_options.pat(); - - let (read_fields, struct_init) = make_struct_init(&variant.fields, &mut bounds)?; - - match_arms.push(quote! { - #pat => { - #read_fields - Self::#variant_name #struct_init - }, - }); - } - - if !options.no_wild { - match_arms.push(quote! { - _ => { - return ::std::result::Result::Err(::byst::io::InvalidDiscriminant(__tag).into()); - }, - }); - - let tag_ty = options.tag_ty().unwrap_or_else(|| { - abort_call_site!("Can't derive `Read::Error` without knowing the tag type.") - }); - - if let Some(error_ty) = &bounds.error_ty { - bounds.where_clause.predicates.push( - parse_quote! { #error_ty: ::std::convert::From<::byst::io::InvalidDiscriminant<#tag_ty>> }, - ); - } - else { - bounds.error_ty = Some(parse_quote! { - ::byst::io::InvalidDiscriminant<#tag_ty> - }); - } - } - - let (where_clause, error_ty) = bounds.finish(); - - Ok(quote! { - #[automatically_derived] - #[allow(unreachable_code)] - impl #impl_generics ::byst::io::Read<__R, #context_ty> for #ident #type_generics #where_clause { - type Error = #error_ty; - - fn read(mut __reader: &mut __R, #context_name: #context_ty) -> ::std::result::Result { - let __tag = #tag_expr; - ::std::result::Result::Ok( - match __tag { - #(#match_arms)* - } - ) - } - } - }) - } -} - -fn make_struct_init( - fields: &Fields, - bounds: &mut DeriveBounds, -) -> Result<(TokenStream, TokenStream), Error> { - let mut read_fields = Vec::with_capacity(fields.len()); - let mut struct_init = Vec::with_capacity(fields.len()); - - for (i, field) in fields.iter().enumerate() { - let FieldName { - span: _, - member: field_name, - var: field_var, - } = FieldName::from_field(i, field); - let field_options = FieldOptions::from_field(field)?; - let field_ty = &field.ty; - - if let Some(skip_with) = field_options.skip() { - // todo: trait bound for type - - read_fields.push(quote! { - let #field_var = #skip_with; - }); - } - else { - let (context_ty, context_expr) = field_options.context(); - let map_err = field_options.map_err(); - - bounds.reads(field_ty, &context_ty); - - read_fields.push(quote!{ - let #field_var = <#field_ty as ::byst::io::Read::<__R, #context_ty>>::read(&mut __reader, #context_expr).map_err(#map_err)?; - }); - } - - struct_init.push((field_name, field_var)); - } - - let struct_init = match fields { - Fields::Named(_) => { - let struct_init = struct_init - .iter() - .map(|(name, var)| quote! { #name: #var, }); - quote! { { #(#struct_init)* } } - } - Fields::Unnamed(_) => { - let struct_init = struct_init.iter().map(|(_name, var)| quote! { #var, }); - quote! { ( #(#struct_init)* ) } - } - Fields::Unit => { - quote! {} - } - }; - - let read_fields = quote! { #(#read_fields)* }; - - Ok((read_fields, struct_init)) -} - -fn derive_transparent(item: DeriveInput, options: DeriveOptions) -> Result { - options.check_for_transparent(); - - let ident = &item.ident; - - let SplitGenerics { - mut impl_generics, - type_generics, - mut where_clause, - } = SplitGenerics::from_generics(&item.generics); - impl_generics.type_params.push(parse_quote! { __R }); - impl_generics.type_params.push(parse_quote! { __C }); - where_clause - .predicates - .push(parse_quote! { __R: ::byst::io::BufReader }); - - Ok(quote! { - #[automatically_derived] - impl #impl_generics ::byst::io::Read<__R, __C> for #ident #type_generics #where_clause { - type Error = ::std::convert::Infallible; - - #[inline] - fn read(mut __reader: &mut __R, __context: __C) -> ::std::result::Result { - ::std::result::Result::Ok(__reader.rest()) - } - } - }) -} - -fn derive_read_for_struct_bitfield( - s: &DataStruct, - bitfield: &Bitfield, - item: &DeriveInput, - _options: &DeriveOptions, -) -> Result { - let ident = &item.ident; - let SplitGenerics { - impl_generics, - type_generics, - mut where_clause, - } = SplitGenerics::from_generics(&item.generics); - let bitfield_ty = &bitfield.ty; - let mut struct_init = vec![]; - let mut bit_index = 0; - - let read_value = if let Some(endianness) = bitfield.endianness.ty() { - where_clause.predicates.push(parse_quote! { - #bitfield_ty: for<'r> ::byst::io::ReadXe::<&'r mut __R, #endianness> - }); - quote! { - ::byst::rw::ReadXe::<_, #endianness>::read(&mut reader)? - } - } - else { - where_clause.predicates.push(parse_quote! { - #bitfield_ty: for<'r> ::byst::io::Read::<&'r mut __R> - }); - quote! { - ::byst::rw::Read::<_>::read(&mut reader)? - } - }; - - for (i, field) in s.fields.iter().enumerate() { - let FieldName { - span: field_span, - member: field_name, - var: _, - } = FieldName::from_field(i, field); - let field_options = BitfieldFieldOptions::from_field(field)?; - let field_ty = &field.ty; - - let (start, bits) = match field_options { - BitfieldFieldOptions { - bits: Some(_), - end: Some(_), - .. - } => { - abort!(field_span, "Only one of `bits` and `end` can be specified") - } - - BitfieldFieldOptions { - bits: None, - end: None, - start, - .. - } => (start.unwrap_or(bit_index), 1), - - BitfieldFieldOptions { - bits: Some(bits), - start, - end: None, - .. - } => (start.unwrap_or(bit_index), bits), - - BitfieldFieldOptions { - bits: None, - start, - end: Some(end), - .. - } => { - let start = start.unwrap_or(bit_index); - ( - start, - end.checked_sub(start) - .unwrap_or_else(|| abort!(field_span, "Bit field can't have end <= start")), - ) - } - }; - - if bits == 0 { - abort!(field_span, "Bit field can't be 0 bits"); - } - - where_clause.predicates.push(parse_quote! { - #bitfield_ty: ::byst::BitFieldExtract<#field_ty> - }); - - struct_init.push(quote! { - #field_name: ::byst::BitFieldExtract::extract::<#field_ty>::(#start, #bits), - }); - - bit_index = start + bits; - } - - Ok(quote! { - #[automatically_derived] - impl<__R, #impl_generics> ::byst::rw::Read<__R> for #ident<#type_generics> #where_clause { - fn read(mut reader: __R) -> ::std::result::Result { - let _value: #bitfield_ty = #read_value; - ::std::result::Result::Ok(Self { - #(#struct_init)* - }) - } - } - }) -} diff --git a/byst-macros/src/read_write/write.rs b/byst-macros/src/read_write/write.rs deleted file mode 100644 index f9592bc..0000000 --- a/byst-macros/src/read_write/write.rs +++ /dev/null @@ -1,150 +0,0 @@ -use darling::FromField; -use proc_macro2::TokenStream; -use quote::quote; -use syn::{ - parse_quote, - Data, - DataStruct, - DeriveInput, - Fields, -}; - -use super::{ - Bitfield, - DeriveBounds, - DeriveOptions, - FieldOptions, -}; -use crate::{ - error::Error, - util::{ - Deriver, - FieldName, - SplitGenerics, - }, -}; - -pub struct DeriveWrite; - -impl Deriver for DeriveWrite { - const NAME: &'static str = "Write"; - type Options = DeriveOptions; - - fn derive_for_item(item: DeriveInput, options: Self::Options) -> Result { - if options.transparent { - derive_transparent(item, options) - } - else { - match &item.data { - Data::Struct(s) => Self::derive_for_struct(s, &item, options), - Data::Enum(e) => Self::derive_for_enum(e, &item, options), - Data::Union(u) => Self::derive_for_union(u, &item, options), - } - } - } - - fn derive_for_struct( - data: &DataStruct, - item: &DeriveInput, - options: Self::Options, - ) -> Result { - options.check_for_struct(); - - let ident = &item.ident; - let (context_name, context_ty) = options.context(); - - let SplitGenerics { - mut impl_generics, - type_generics, - where_clause, - } = SplitGenerics::from_generics(&item.generics); - impl_generics.type_params.push(parse_quote! { __W }); - let mut bounds = DeriveBounds::new(where_clause, options.error.clone()); - - let write_fields = make_struct_write_fields(&data.fields, &mut bounds)?; - - let (where_clause, error_ty) = bounds.finish(); - - Ok(quote! { - #[automatically_derived] - impl #impl_generics ::byst::io::Write<__W, #context_ty> for #ident #type_generics #where_clause { - type Error = #error_ty; - - fn write(&self, mut __writer: &mut __W, #context_name: #context_ty) -> ::std::result::Result<(), Self::Error> { - #write_fields - ::std::result::Result::Ok(()) - } - } - }) - } -} - -fn make_struct_write_fields( - fields: &Fields, - bounds: &mut DeriveBounds, -) -> Result { - let mut write_fields = Vec::with_capacity(fields.len()); - - for (i, field) in fields.iter().enumerate() { - let FieldName { - span: _, - member: field_name, - var: _, - } = FieldName::from_field(i, field); - let field_options = FieldOptions::from_field(field)?; - let field_ty = &field.ty; - - if field_options.skip.is_some() { - // nop - } - else { - let (context_ty, context_expr) = field_options.context(); - let map_err = field_options.map_err(); - - bounds.writes(field_ty, &context_ty); - - write_fields.push(quote! { - <#field_ty as ::byst::io::Write::<__W, #context_ty>>::write(&self.#field_name, &mut __writer, #context_expr).map_err(#map_err)?; - }); - } - } - - Ok(quote! { #(#write_fields)* }) -} - -fn derive_transparent(item: DeriveInput, options: DeriveOptions) -> Result { - options.check_for_transparent(); - - let ident = &item.ident; - - let SplitGenerics { - mut impl_generics, - type_generics, - mut where_clause, - } = SplitGenerics::from_generics(&item.generics); - impl_generics.type_params.push(parse_quote! { __W }); - impl_generics.type_params.push(parse_quote! { __C }); - where_clause - .predicates - .push(parse_quote! { __W: ::byst::io::Writer }); - - Ok(quote! { - #[automatically_derived] - impl #impl_generics ::byst::io::Write<__W, __C> for #ident #type_generics #where_clause { - type Error = <__W as ::byst::io::Writer>::Error; - - #[inline] - fn write(&self, writer: &mut __W, _context: __C) -> Result<(), Self::Error> { - writer.write_buf(self) - } - } - }) -} - -fn derive_write_for_struct_bitfield( - _s: &DataStruct, - _bitfield: &Bitfield, - _item: &DeriveInput, -) -> Result { - todo!(); -} diff --git a/byst-macros/src/util.rs b/byst-macros/src/util.rs deleted file mode 100644 index 8554325..0000000 --- a/byst-macros/src/util.rs +++ /dev/null @@ -1,247 +0,0 @@ -use darling::FromDeriveInput; -use proc_macro2::{ - Span, - TokenStream, -}; -use proc_macro_error::{ - abort, - abort_call_site, -}; -use quote::{ - quote, - ToTokens, -}; -use syn::{ - parse_macro_input, - punctuated::Punctuated, - spanned::Spanned, - token::Where, - ConstParam, - Data, - DataEnum, - DataStruct, - DataUnion, - DeriveInput, - Field, - Fields, - GenericParam, - Generics, - Ident, - Index, - Lifetime, - LifetimeParam, - Member, - TypeParam, - WhereClause, -}; - -use crate::error::Error; - -pub trait Deriver { - const NAME: &'static str; - type Options: FromDeriveInput; - - fn process(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let input = parse_macro_input!(input as DeriveInput); - - match Self::Options::from_derive_input(&input) { - Ok(options) => { - match Self::derive_for_item(input, options) { - Ok(output) => output.into(), - Err(e) => e.write_errors().into(), - } - } - Err(e) => e.write_errors().into(), - } - } - - fn derive_for_item(item: DeriveInput, options: Self::Options) -> Result { - match &item.data { - Data::Struct(s) => Self::derive_for_struct(s, &item, options), - Data::Enum(e) => Self::derive_for_enum(e, &item, options), - Data::Union(u) => Self::derive_for_union(u, &item, options), - } - } - - #[allow(unused_variables)] - fn derive_for_struct( - data: &DataStruct, - item: &DeriveInput, - options: Self::Options, - ) -> Result { - abort!(item.ident, "{} can't be derived on structs.", Self::NAME); - } - - #[allow(unused_variables)] - fn derive_for_enum( - data: &DataEnum, - item: &DeriveInput, - options: Self::Options, - ) -> Result { - abort!(item.ident, "{} can't be derived on enums.", Self::NAME); - } - - #[allow(unused_variables)] - fn derive_for_union( - union: &DataUnion, - item: &DeriveInput, - options: Self::Options, - ) -> Result { - abort!(item.ident, "{} can't be derived on unions.", Self::NAME); - } -} - -#[derive(Clone)] -pub struct FieldName { - pub span: Span, - pub member: Member, - pub var: Ident, -} - -impl FieldName { - pub fn from_field(index: usize, field: &Field) -> Self { - if let Some(ident) = &field.ident { - Self { - span: ident.span(), - member: Member::Named(ident.clone()), - var: ident.clone(), - } - } - else { - let span = field.ty.span(); - Self { - span, - member: Member::Unnamed(Index { - index: index as u32, - span, - }), - var: Ident::new(&format!("_{index}"), span), - } - } - } -} - -pub fn make_where_clause(where_clause: Option<&WhereClause>) -> WhereClause { - where_clause.cloned().unwrap_or_else(|| { - WhereClause { - where_token: Where { - span: Span::call_site(), - }, - predicates: Punctuated::new(), - } - }) -} - -pub fn exactly_one_field(fields: &Fields) -> &Field { - let mut it = fields.iter(); - let field = it - .next() - .unwrap_or_else(|| abort_call_site!("Expected exactly one field.")); - if let Some(field) = it.next() { - abort!(field.ident.span(), "Expected exactly one field."); - } - field -} - -pub struct SplitGenerics { - pub impl_generics: ImplGenerics, - pub type_generics: TypeGenerics, - pub where_clause: WhereClause, -} - -impl SplitGenerics { - pub fn from_generics(generics: &Generics) -> Self { - Self { - impl_generics: ImplGenerics::from_generics(generics), - type_generics: TypeGenerics(generics.clone()), - where_clause: make_where_clause(generics.where_clause.as_ref()), - } - } -} - -#[derive(Default)] -pub struct ImplGenerics { - pub lifetimes: Vec, - pub type_params: Vec, - pub const_params: Vec, -} - -impl ImplGenerics { - pub fn from_generics(generics: &Generics) -> Self { - let mut this = ImplGenerics::default(); - for lt in generics.lifetimes() { - this.lifetimes.push(lt.clone()); - } - for ty in generics.type_params() { - this.type_params.push(ty.clone()); - } - for con in generics.const_params() { - this.const_params.push(con.clone()); - } - this - } -} - -impl ToTokens for ImplGenerics { - fn to_tokens(&self, tokens: &mut TokenStream) { - let params = self - .lifetimes - .iter() - .map(|lt| GenericParam::Lifetime(lt.clone())) - .chain( - self.type_params - .iter() - .map(|ty| GenericParam::Type(ty.clone())), - ) - .chain( - self.const_params - .iter() - .map(|con| GenericParam::Const(con.clone())), - ); - - if !self.lifetimes.is_empty() - || !self.type_params.is_empty() - || !self.const_params.is_empty() - { - tokens.extend(quote! { - <#(#params),*> - }); - } - } -} - -pub struct TypeGenerics(Generics); - -impl ToTokens for TypeGenerics { - fn to_tokens(&self, tokens: &mut TokenStream) { - let params = self.0.params.iter().map(|param| { - match param { - GenericParam::Lifetime(lt) => TypeGenericParam::Lifetime(<.lifetime), - GenericParam::Type(ty) => TypeGenericParam::Type(&ty.ident), - GenericParam::Const(con) => TypeGenericParam::Const(&con.ident), - } - }); - - if !self.0.params.is_empty() { - tokens.extend(quote! { - <#(#params),*> - }); - } - } -} - -enum TypeGenericParam<'a> { - Type(&'a Ident), - Lifetime(&'a Lifetime), - Const(&'a Ident), -} - -impl<'a> ToTokens for TypeGenericParam<'a> { - fn to_tokens(&self, tokens: &mut TokenStream) { - match self { - TypeGenericParam::Type(ty) => ty.to_tokens(tokens), - TypeGenericParam::Lifetime(lt) => lt.to_tokens(tokens), - TypeGenericParam::Const(con) => con.to_tokens(tokens), - } - } -} diff --git a/byst/Cargo.toml b/byst/Cargo.toml deleted file mode 100644 index bef3e49..0000000 --- a/byst/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "byst" -version = "0.1.0" -edition = "2021" - -[features] -default = [] -bytes-impl = [] - -[dependencies.byst-macros] -#version = "0.1.0" -path = "../byst-macros" - -[dependencies] -thiserror = "1.0.60" -derive_more = "0.99.17" diff --git a/byst/src/bits.rs b/byst/src/bits.rs deleted file mode 100644 index f22082a..0000000 --- a/byst/src/bits.rs +++ /dev/null @@ -1,72 +0,0 @@ -#![allow(dead_code)] - -use std::ops::{ - BitAnd, - BitOr, - Shl, - Shr, -}; - -pub trait BitFieldExtract { - fn extract(&self, start: usize, bits: usize) -> O; -} - -// todo: I'd really like to do this at compile-time :/ -pub fn bit_mask(mut bits: usize) -> T -where - T: Shl + BitOr + From, -{ - let mut bit_mask = T::from(0u8); - while bits > 0 { - bit_mask = (bit_mask << 1) | T::from(1u8); - bits -= 1; - } - bit_mask -} - -pub fn extract_bits(value: T, start: usize, bits: usize) -> T -where - T: Shl - + BitOr - + From - + Shr - + BitAnd, -{ - (value >> start) & bit_mask::(bits) -} - -macro_rules! impl_bit_field_extract { - { - $( - $from:ty => {$($to:ty),*}; - )* - } => { - $( - $( - impl BitFieldExtract<$to> for $from { - fn extract(&self, start: usize, bits: usize) -> $to { - // ideally this check would also happen at compile-time. after all we know how many bits the int will have. - assert!(bits < <$to>::BITS as usize); - <$to>::try_from(extract_bits::(*self, start, bits)).unwrap_or_else(|_| panic!("Can't convert from {} ({}) to {}", stringify!($ty), *self, stringify!($to))) - } - } - )* - - impl BitFieldExtract for $from { - fn extract(&self, start: usize, bits: usize) -> bool { - // ideally this check would also happen at compile-time. after all we know how many bits the int will have. - assert_eq!(bits, 1); - extract_bits::(*self, start, bits) != 0 - } - } - )* - }; -} - -impl_bit_field_extract! { - u8 => {u8}; - u16 => {u8, u16}; - u32 => {u8, u16, u32}; - u64 => {u8, u16, u32, u64}; - u128 => {u8, u16, u32, u64, u128}; -} diff --git a/byst/src/buf/arc_buf.rs b/byst/src/buf/arc_buf.rs deleted file mode 100644 index 5e7e286..0000000 --- a/byst/src/buf/arc_buf.rs +++ /dev/null @@ -1,1539 +0,0 @@ -use std::{ - cell::UnsafeCell, - fmt::Debug, - mem::MaybeUninit, - ptr::NonNull, - sync::atomic::{ - AtomicUsize, - Ordering, - }, -}; - -use super::{ - BufReader, - BufWriter, - Full, - Length, - SizeLimit, -}; -use crate::{ - bytes::r#impl::{ - BytesImpl, - BytesMutImpl, - WriterImpl, - }, - impl_me, - io::{ - End, - Seek, - }, - util::{ - buf_eq, - debug_as_hexdump, - }, - Buf, - BufMut, - Bytes, - BytesMut, - IndexOutOfBounds, - Range, - RangeOutOfBounds, -}; - -#[derive(Clone, Copy)] -struct Buffer { - /// Made from a `Box<[MaybeUninit]>>` - /// - /// This pointer is valid as long as a [`Reclaim`] exists, or a - /// [`BufferRef`] exists. therefore, as long as you can acquire this - /// `BufferPtr`, it's safe to assume that `buf` points to valid - /// memory. - /// - /// This may be dangling if the buffer is zero-sized. This means that no - /// buffer was allocated for it, and thus must not be deallocated. - buf: *const [UnsafeCell>], - - /// Made from a `Box` - /// - /// Invariant: This pointer is valid as long as [`Reclaim`] exists, or - /// a [`BufferRef`] exists. - /// - /// This may be `null` if the buffer is zero-sized. This means that no - /// buffer was allocated for it, and thus must not be deallocated. - meta_data: *const MetaData, -} - -impl Buffer { - fn zero_sized() -> Self { - // special case for zero-sized buffers. they don't need to be reference counted, - // and use a dangling pointer for the `buf`. - - let buf = unsafe { - std::slice::from_raw_parts( - NonNull::>>::dangling().as_ptr(), - 0, - ) - }; - - Self { - buf, - meta_data: std::ptr::null(), - } - } - - fn new(size: usize, ref_count: usize, reclaim: bool) -> Self { - if size == 0 { - Self::zero_sized() - } - else { - // allocate ref_count - let meta_data = Box::into_raw(Box::new(MetaData { - ref_count: AtomicRefCount::new(ref_count, reclaim), - initialized: UnsafeCell::new(0), - })); - - // allocate buffer - let buf = Box::<[u8]>::new_uninit_slice(size); - - // leak it to raw pointer - let buf = Box::into_raw(buf); - - // make it `*const [UnsafeCell<_>>]`. This is roughly what - // `UnsafeCell::from_mut` does. - let buf = buf as *const [UnsafeCell>]; - - Buffer { buf, meta_data } - } - } - - fn len(&self) -> usize { - self.buf.len() - } - - #[inline] - unsafe fn deallocate(self) { - assert!( - !self.meta_data.is_null(), - "Trying to deallocate a zero-sized Buffer" - ); - let _ref_count = Box::from_raw(self.meta_data as *mut MetaData); - let _buf = Box::from_raw(self.buf as *mut [UnsafeCell>]); - } - - #[inline] - unsafe fn ref_count(&self) -> RefCount { - if self.meta_data.is_null() { - RefCount::Static - } - else { - unsafe { - // SAFETY: This `Buffer` only becomes invalid, if it's deallocated, but that - // method is unsafe. - RefCount::from_atomic(&(*self.meta_data).ref_count) - } - } - } -} - -struct MetaData { - ref_count: AtomicRefCount, - initialized: UnsafeCell, -} - -/// This manages the reference count of a [`Buffer`]: -/// -/// - [`Buffer`]s can have *one* reference from a [`Reclaim`]. This is stored as -/// the LSB. -/// - [`Buffer`]s can have any number of references through [`BufferRef`]. This -/// is stored in the remaining bits. -struct AtomicRefCount(AtomicUsize); - -impl AtomicRefCount { - #[inline] - fn new(ref_count: usize, reclaim: bool) -> Self { - Self(AtomicUsize::new( - ref_count << 1 | if reclaim { 1 } else { 0 }, - )) - } - - /// Increments reference count for [`BufferRef`]s - #[inline] - fn increment(&self) { - self.0.fetch_add(2, Ordering::Relaxed); - } - - /// Decrements reference count for [`BufferRef`]s and returns whether the - /// buffer must be deallocated. - #[inline] - fn decrement(&self) -> MustDrop { - let old_value = self.0.fetch_sub(2, Ordering::Relaxed); - assert!(old_value >= 2); - MustDrop(old_value == 2) - } - - /// Removes the [`Reclaim`] reference and returns whether the buffer must be - /// deallocated. - #[inline] - fn make_unreclaimable(&self) -> MustDrop { - MustDrop(self.0.fetch_and(!1, Ordering::Relaxed) == 1) - } - - /// Trys to reclaim the buffer. This will only be successful if the - /// reclaim-reference is the only one to the buffer. In this case it'll - /// increase the normal ref-count and return `true`. - #[inline] - fn try_reclaim(&self) -> bool { - self.0 - .compare_exchange(1, 3, Ordering::Relaxed, Ordering::Relaxed) - .is_ok() - } - - /// Checks if the buffer can be reclaimed. - #[inline] - fn can_reclaim(&self) -> bool { - self.0.load(Ordering::Relaxed) == 1 - } -} - -#[derive(Clone, Copy, Debug)] -#[must_use] -struct MustDrop(pub bool); - -impl From for bool { - fn from(value: MustDrop) -> Self { - value.0 - } -} - -#[derive(Clone, Copy, Debug)] -pub enum RefCount { - Static, - Counted { ref_count: usize, reclaim: bool }, -} - -impl RefCount { - fn from_atomic(value: &AtomicRefCount) -> Self { - let value = value.0.load(Ordering::Relaxed); - let ref_count = value >> 1; - Self::Counted { - ref_count, - reclaim: value & 1 != 0, - } - } - - #[inline] - pub fn ref_count(&self) -> Option { - match self { - Self::Static => None, - Self::Counted { ref_count, .. } => Some(*ref_count), - } - } - - #[inline] - pub fn can_be_reclaimed(&self) -> bool { - match self { - RefCount::Static => false, - RefCount::Counted { reclaim, .. } => *reclaim, - } - } - - #[inline] - pub fn is_static(&self) -> bool { - matches!(self, Self::Static) - } -} - -struct BufferRef { - buf: Buffer, - start: usize, - end: usize, - - /// `true` if this is the *tail* of the buffer. This means that this - /// [`BufferRef`] might contain an uninitialized portion of the buffer. - /// Otherwise it's fully initialized. Only the *tail* reference may access - /// [`MetaData::initialized`], iff this buffer is not zero-sized. - /// - /// If the buffer is zero-sized, this is always *false*. - /// - /// Immutable references may also set this to `false`, since they're not - /// allowed the [`MetaData::initialized`] anyway. But they must make sure - /// that the whole buffer that is referenced, is initialized (which they - /// usually do anyway). - tail: bool, -} - -impl BufferRef { - /// # Safety - /// - /// The caller must ensure that `buf` is valid. - unsafe fn from_buf(buf: Buffer) -> Self { - let end = buf.len(); - Self { - buf, - start: 0, - end, - tail: end != 0, - } - } - - /// # Safety - /// - /// The caller must ensure that there are no mutable references to this - /// portion of the buffer, and that the range is valid. - #[inline] - unsafe fn uninitialized(&self) -> &[MaybeUninit] { - // SAFETY: - // - `Buffer` is valid, since we have a `BufferRef` to it. - // - The range is valid - let ptr = self.buf.buf.get_unchecked(self.start..self.end); - std::slice::from_raw_parts(UnsafeCell::raw_get(ptr.as_ptr()), self.end - self.start) - } - - /// # Safety - /// - /// The caller must ensure that the access is unique, and that the range is - /// valid. No other active references, mutable or not may exist to this - /// portion of the buffer. Furthermore the caller must not write - /// uninitialized values into the initialized portion of the buffer. - #[inline] - unsafe fn uninitialized_mut(&mut self) -> &mut [MaybeUninit] { - // SAFETY: - // - `Buffer` is valid, since we have a `BufferRef` to it. - // - The range is valid - let ptr = self.buf.buf.get_unchecked(self.start..self.end); - std::slice::from_raw_parts_mut(UnsafeCell::raw_get(ptr.as_ptr()), self.end - self.start) - } - - /// # Safety - /// - /// The caller must ensure that there are no mutable borrows to this buffer. - #[inline] - unsafe fn initialized_end(&self) -> usize { - if self.tail { - let initialized = unsafe { - // SAFETY: - // - `Buffer` is valid, since we have a `BufferRef` to it. - // - `meta_data` is non-null: we can assume that this is not an zero-sized - // buffer, because it's a tail. there's a test for that. - // - We're the tail of the buffer, so only we're allowed to access the - // initialized `UnsafeCell`. - *(*self.buf.meta_data).initialized.get() - }; - - assert!( - initialized >= self.start && initialized <= self.end, - "BufferRef is tail, but initialized is out of its bounds." - ); - - initialized - } - else { - self.end - } - } - - /// # Safety - /// - /// The caller must ensure that the access is unique, and that all bytes - /// upto `to` have been initialized. - #[inline] - unsafe fn set_initialized_to(&self, to: usize) { - let to = self.start + to; - assert!( - to <= self.end, - "Argument to initialized_increase is out of bounds" - ); - - if self.tail { - unsafe { - // SAFETY: - // - `Buffer` is valid, since we have a `BufferRef` to it. - // - `meta_data` is non-null: we can assume that this is not an zero-sized - // buffer, because it's a tail. there's a test for that. - // - We're the tail of the buffer, so only we're allowed to access the - // initialized `UnsafeCell`. - let initialized = (*self.buf.meta_data).initialized.get(); - - assert!( - *initialized >= self.start && *initialized <= self.end, - "BufferRef is tail, but initialized is out of its bounds." - ); - - *initialized = std::cmp::max(*initialized, to); - } - } - else { - // if it's not tail, we don't care since the portion of the buffer - // is fully initialized anyway. - } - } - - /// # Safety - /// - /// The caller must ensure that there are no mutable references to this - /// portion of the buffer, and that the range is valid. - #[inline] - unsafe fn initialized(&self) -> &[u8] { - let initialized = self.initialized_end(); - - // SAFETY: - // - `Buffer` is valid, since we have a `BufferRef` to it. - // - The range is valid - // - The range is initialized - let ptr = self.buf.buf.get_unchecked(self.start..initialized); - let slice = - std::slice::from_raw_parts(UnsafeCell::raw_get(ptr.as_ptr()), initialized - self.start); - MaybeUninit::slice_assume_init_ref(slice) - } - - /// # Safety - /// - /// The caller must ensure that the access is unique, and that the range is - /// valid. No other active references, mutable or not may exist to this - /// portion of the buffer. - #[inline] - unsafe fn initialized_mut(&mut self) -> &mut [u8] { - let initialized = self.initialized_end(); - - // SAFETY: - // - `Buffer` is valid, since we have a `BufferRef` to it. - // - The range is valid - // - The range is initialized - let ptr = self.buf.buf.get_unchecked(self.start..initialized); - let slice = std::slice::from_raw_parts_mut( - UnsafeCell::raw_get(ptr.as_ptr()), - initialized - self.start, - ); - MaybeUninit::slice_assume_init_mut(slice) - } - - #[inline] - fn len(&self) -> usize { - self.end - self.start - } - - /// Splits `self` into: - /// - /// 1. `self`: `[at..]` - /// 2. returns: `[..at)` - fn split_at(&mut self, at: usize) -> BufferRef { - let split_offset = at + self.start; - - assert!(split_offset <= self.end); - - if at == self.start { - Self::default() - } - else if at == self.end { - std::mem::take(self) - } - else { - let mut new = self.clone(); - new.end = split_offset; - new.tail = false; - - self.start = split_offset; - - new - } - } - - fn shrink(&mut self, start: usize, end: usize) { - let new_start = self.start + start; - let new_end = self.start + end; - - assert!(new_start >= self.start); - assert!(new_end <= self.end); - assert!(new_start <= new_end); - - if new_start == new_end { - *self = Default::default(); - } - else { - self.start = new_start; - self.end = new_end; - } - } - - #[inline] - fn ref_count(&self) -> RefCount { - unsafe { - // SAFETY: As long as there is a [`BufferRef`], the [`Buffer`] is valid. - self.buf.ref_count() - } - } - - #[inline] - fn fully_initialize(&mut self) { - if self.tail { - unsafe { - // SAFETY: - // - `Buffer` is valid, since we have a `BufferRef` to it. - // - `meta_data` is non-null: we can assume that this is not an zero-sized - // buffer, because it's a tail. there's a test for that. - // - We're the tail of the buffer, so only we're allowed to access the - // initialized `UnsafeCell`. - - let initialized = (*self.buf.meta_data).initialized.get(); - assert!( - *initialized >= self.start && *initialized <= self.end, - "BufferRef is tail, but initialized is out of its bounds." - ); - - let ptr = self.buf.buf.get_unchecked(*initialized..self.end); - let slice = std::slice::from_raw_parts_mut( - UnsafeCell::raw_get(ptr.as_ptr()), - self.end - *initialized, - ); - MaybeUninit::fill(slice, 0); - - *initialized = self.end; - } - } - } -} - -impl Default for BufferRef { - #[inline] - fn default() -> Self { - Self { - buf: Buffer::zero_sized(), - start: 0, - end: 0, - // counter-intuitive, since zero-sized buffers kind of are always a tail. we set this to - // false, because the `MetaData::initialized` doesn't exist for a zero-sized buffer - // anyway. - tail: false, - } - } -} - -impl Clone for BufferRef { - fn clone(&self) -> Self { - if !self.buf.meta_data.is_null() { - unsafe { - // SAFETY: This `Buffer` only becomes invalid, if it's deallocated, but that - // method is unsafe. - (*self.buf.meta_data).ref_count.increment(); - } - } - - Self { - buf: self.buf, - start: self.start, - end: self.end, - tail: self.tail, - } - } -} - -impl Drop for BufferRef { - fn drop(&mut self) { - if !self.buf.meta_data.is_null() { - unsafe { - // SAFETY: This drops the inner buffer, if the ref_count reaches 0. But we're - // dropping our ref, so it's fine. - if (*self.buf.meta_data).ref_count.decrement().into() { - self.buf.deallocate(); - } - } - } - } -} - -pub struct Reclaim { - buf: Buffer, -} - -impl Reclaim { - pub fn try_reclaim(&self) -> Option { - if self.buf.meta_data.is_null() { - Some(ArcBufMut::default()) - } - else { - let reclaimed = unsafe { - // SAFETY: We have a [`Reclaim`] reference to the buffer, so it hasn't been - // deallocated. Thus it's safe to dereference the `ref_count`. - (*self.buf.meta_data).ref_count.try_reclaim() - }; - - reclaimed.then(|| { - // we reclaimed the buffer, thus we can hand out a new unique reference to it :) - ArcBufMut { - inner: BufferRef { - buf: self.buf, - start: 0, - end: self.buf.len(), - tail: true, - }, - filled: 0, - } - }) - } - } - - #[inline] - pub fn can_reclaim(&self) -> bool { - if self.buf.meta_data.is_null() { - true - } - else { - unsafe { - // SAFETY: We have a [`Reclaim`] reference to the buffer, so it hasn't been - // deallocated. Thus it's safe to dereference the `ref_count`. - (*self.buf.meta_data).ref_count.can_reclaim() - } - } - } - - #[inline] - pub fn ref_count(&self) -> RefCount { - unsafe { - // SAFETY: As long as there is a [`Reclaim`], the [`Buffer`] is valid. - self.buf.ref_count() - } - } -} - -impl Drop for Reclaim { - fn drop(&mut self) { - if !self.buf.meta_data.is_null() { - unsafe { - // SAFETY: We have a [`Reclaim`] reference to the buffer, so it hasn't been - // deallocated. Thus it's safe to dereference the `ref_count`. - if (*self.buf.meta_data).ref_count.make_unreclaimable().into() { - self.buf.deallocate(); - } - } - } - } -} - -impl Debug for Reclaim { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Reclaim").finish_non_exhaustive() - } -} - -// SAFETY: -// -// This is safe to impl `Send` and `Sync`, because all it ever does is access -// the meta data / ref count through a `*const MetaData` -unsafe impl Send for Reclaim {} -unsafe impl Sync for Reclaim {} - -#[derive(Clone, Default)] -pub struct ArcBuf { - inner: BufferRef, -} - -impl ArcBuf { - #[inline] - fn bytes(&self) -> &[u8] { - unsafe { - // SAFETY - // - // - The `inner` [`BufferRef`] points to a fully initialized portion of the - // buffer. - // - No mutable reference to this portion of the buffer exist. - MaybeUninit::slice_assume_init_ref(self.inner.uninitialized()) - } - } - - #[inline] - pub fn ref_count(&self) -> RefCount { - self.inner.ref_count() - } -} - -impl Buf for ArcBuf { - type View<'a> = Self - where - Self: 'a; - - type Reader<'a> = Self - where - Self: 'a; - - fn view(&self, range: impl Into) -> Result, RangeOutOfBounds> { - let (start, end) = range.into().indices_checked_in(0, self.len())?; - let mut cloned = Clone::clone(self); - cloned.inner.shrink(start, end); - Ok(cloned) - } - - #[inline] - fn reader(&self) -> Self::Reader<'_> { - Clone::clone(self) - } -} - -impl BufReader for ArcBuf { - type View = Self; - - #[inline] - fn peek_chunk(&self) -> Option<&[u8]> { - if self.is_empty() { - None - } - else { - Some(self.bytes()) - } - } - - #[inline] - fn view(&mut self, length: usize) -> Result { - let view = Buf::view(self, 0..length).map_err(|RangeOutOfBounds { .. }| { - End { - requested: length, - read: 0, - remaining: self.len(), - } - })?; - self.inner.shrink(length, self.len()); - Ok(view) - } - - #[inline] - fn peek_view(&self, length: usize) -> Result { - let view = Buf::view(self, 0..length).map_err(|RangeOutOfBounds { .. }| { - End { - requested: length, - read: 0, - remaining: self.len(), - } - })?; - Ok(view) - } - - #[inline] - fn rest(&mut self) -> Self::View { - std::mem::take(self) - } - - #[inline] - fn peek_rest(&self) -> Self::View { - Clone::clone(self) - } - - #[inline] - fn advance(&mut self, by: usize) -> Result<(), End> { - if by <= self.len() { - self.inner.shrink(by, self.len()); - Ok(()) - } - else { - Err(End { - requested: by, - read: 0, - remaining: self.len(), - }) - } - } - - #[inline] - fn remaining(&self) -> usize { - self.len() - } -} - -impl Seek for ArcBuf { - type Position = ArcBuf; - - #[inline] - fn tell(&self) -> Self::Position { - Clone::clone(self) - } - - #[inline] - fn seek(&mut self, position: &Self::Position) -> Self::Position { - std::mem::replace(self, Clone::clone(position)) - } -} - -impl<'b> BytesImpl<'b> for ArcBuf { - fn view(&self, range: Range) -> Result + 'b>, RangeOutOfBounds> { - Ok(Box::new(Buf::view(self, range)?)) - } - - fn clone(&self) -> Box + 'b> { - Box::new(Clone::clone(self)) - } - - fn peek_chunk(&self) -> Option<&[u8]> { - BufReader::peek_chunk(self) - } - - fn advance(&mut self, by: usize) -> Result<(), End> { - BufReader::advance(self, by) - } -} - -impl Length for ArcBuf { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } -} - -impl AsRef<[u8]> for ArcBuf { - #[inline] - fn as_ref(&self) -> &[u8] { - self.bytes() - } -} - -impl Debug for ArcBuf { - #[inline] - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - debug_as_hexdump(f, self.bytes()) - } -} - -impl PartialEq for ArcBuf { - #[inline] - fn eq(&self, other: &T) -> bool { - buf_eq(self, other) - } -} - -// SAFETY: -// -// This is safe to impl `Send` and `Sync`, because it only does immutable access -// to overlapping ranges. -unsafe impl Send for ArcBuf {} -unsafe impl Sync for ArcBuf {} - -#[derive(Default)] -pub struct ArcBufMut { - inner: BufferRef, - filled: usize, -} - -impl ArcBufMut { - /// # Safety - /// - /// The caller must ensure that `buf` is valid. - unsafe fn from_buffer(buf: Buffer) -> Self { - Self { - inner: unsafe { BufferRef::from_buf(buf) }, - filled: 0, - } - } - - /// Creates a new [`ArcBufMut`] with the specified capacity. - #[inline] - pub fn new(capacity: usize) -> Self { - let buf = Buffer::new(capacity, 1, false); - unsafe { Self::from_buffer(buf) } - } - - /// Creates a new [`ArcBufMut`], with a handle to reclaim it. - /// - /// A reclaimable buffer will not be freed when all ordinary references - /// (i.e. [`ArcBuf`]s and [`ArcBufMut`]s, but not [`Reclaim`]s) to it are - /// dropped. It can be be reclaimed using the [`Reclaim`] handle. When all - /// ordinary references *and* the [`Reclaim`] is dropped, the buffer will be - /// deallocated. - /// - /// # Example - /// - /// ``` - /// # use byst::buf::arc_buf::ArcBufMut; - /// # - /// let (mut buf, reclaim) = ArcBufMut::new_reclaimable(10); - /// - /// // Do something with `buf`... - /// # let _ = &mut buf; - /// - /// // Right now we can't reclaim it, since it's still in use. - /// assert!(!reclaim.can_reclaim()); - /// - /// // Drop it. - /// drop(buf); - /// - /// // Once all references to the underlying buffer have been dropped, we can reuse it. - /// let reclaimed_buf = reclaim.try_reclaim().unwrap(); - /// ``` - #[inline] - pub fn new_reclaimable(capacity: usize) -> (Self, Reclaim) { - let buf = Buffer::new(capacity, 1, true); - let this = unsafe { Self::from_buffer(buf) }; - let reclaim = Reclaim { buf }; - (this, reclaim) - } - - /// Returns the capacity of the buffer. - #[inline] - pub fn capacity(&self) -> usize { - self.inner.len() - } - - /// Makes the buffer immutable. - /// - /// This returns an [`ArcBuf`] that can be cheaply cloned and shared. - /// - /// This will drop the buffer if the buffer hasn't been filled and return an - /// [`ArcBuf`] that has no heap-allocation. - #[inline] - pub fn freeze(mut self) -> ArcBuf { - self.inner.shrink(0, self.filled); - ArcBuf { inner: self.inner } - } - - /// Returns the reference count for this buffer. - /// - /// This includes all references to the underlying buffer, even if it was - /// split. - #[inline] - pub fn ref_count(&self) -> RefCount { - self.inner.ref_count() - } - - /// Splits `self` into: - /// - /// 1. `self`: Right half starting with `at`. (`[at..]`) - /// 2. returns: Left half up to `at`, but not including it. (`[..at)`) - pub fn split_at(&mut self, at: usize) -> Result { - let filled = self.filled; - if at == 0 { - Ok(Self::default()) - } - else if at == filled { - Ok(std::mem::take(self)) - } - else if at < filled { - let inner = self.inner.split_at(at); - self.filled = filled - at; - Ok(Self { inner, filled: at }) - } - else { - Err(IndexOutOfBounds { - required: at, - bounds: (0, filled), - }) - } - } - - /// Returns an immutable reference to the filled portion of the buffer. - #[inline] - fn filled(&self) -> &[u8] { - unsafe { - // SAFETY: - // - // - `..self.filled` is initialized - // - We have the only reference to that portion of the buffer. - MaybeUninit::slice_assume_init_ref(&self.inner.uninitialized()[..self.filled]) - } - } - - /// Returns a mutable reference to the filled portion of the buffer. - #[inline] - fn filled_mut(&mut self) -> &mut [u8] { - unsafe { - // SAFETY: - // - // - `..self.filled` is initialized - // - We have the only reference to that portion of the buffer. - MaybeUninit::slice_assume_init_mut(&mut self.inner.uninitialized_mut()[..self.filled]) - } - } - - /// Returns an immutable reference to the initialized portion of the buffer. - #[inline] - pub fn initialized(&self) -> &[u8] { - unsafe { - // SAFETY: - // - // - We have the only reference to that portion of the buffer. - self.inner.initialized() - } - } - - /// Returns a mutable reference to the initialized portion of the buffer. - /// - /// This is useful if you want to write to the buffer, without having to - /// fill it first. You can resize the [`ArcBufMut`] to include the written - /// data with [`set_filled_to`]. To fully initialize a buffer, you can use - /// [`fully_initialize`]. - /// - /// # Example - /// - /// This example shows how an [`ArcBufMut`] can be used to read data from - /// the OS, which usually requires a contiguous initialized buffer, and - /// returns the number of bytes read. - /// - /// ``` - /// # use byst::buf::arc_buf::ArcBufMut; - /// # - /// # struct Socket; - /// # - /// # impl Socket { - /// # fn recv(&mut self, buf: &mut [u8]) -> usize { - /// # buf[0] = 0xac; - /// # buf[1] = 0xab; - /// # 2 - /// # } - /// # } - /// # - /// # let mut socket = Socket; - /// # - /// let mut buf = ArcBufMut::new(1522); - /// buf.fully_initialize(); - /// - /// // Some OS function that writes to a contiguous buffer, and returns the number of bytes read. - /// // In this example this call will write b"\xac\xab" to the buffer, and return 2. - /// let n_read = socket.recv(buf.initialized_mut()); - /// - /// buf.set_filled_to(n_read); - /// - /// assert_eq!(buf, b"\xac\xab"); - /// ``` - /// - /// [`set_filled_to`]: Self::set_filled_to - /// [`fully_initialize`]: Self::fully_initialize - #[inline] - pub fn initialized_mut(&mut self) -> &mut [u8] { - unsafe { - // SAFETY: - // - // - We have the only mutable reference to that portion of the buffer. - self.inner.initialized_mut() - } - } - - /// Returns an immutable reference to the full buffer. - #[inline] - pub fn uninitialized(&self) -> &[MaybeUninit] { - unsafe { - // SAFETY: - // - // - We have the only reference to that portion of the buffer. - self.inner.uninitialized() - } - } - - /// Returns a mutable reference to the full buffer. - /// - /// # Safety - /// - /// The caller must not write uninitialized values into the initialized - /// portion of the buffer. - #[inline] - pub unsafe fn uninitialized_mut(&mut self) -> &mut [MaybeUninit] { - // SAFETY: - // - // - We have the only reference to that portion of the buffer. - self.inner.uninitialized_mut() - } - - /// Resizes the buffer to include all bytes upto `to`. - /// - /// This is useful if the buffer was previously written to using - /// [`initialized_mut`]. You can fully initialize a buffer using - /// [`fully_initialize`] - /// - /// # Panics - /// - /// Panics if the buffer hasn't been initialized upto `to`. - /// - /// [`initialized_mut`]: Self::initialized_mut - /// [`fully_initialize`]: Self::fully_initialize - #[inline] - pub fn set_filled_to(&mut self, to: usize) { - let end = unsafe { - // SAFETY: we have a `&mut self`, so there are no other mutable references to - // this buffer. - self.inner.initialized_end() - }; - assert!( - to <= end - self.inner.start, - "`ArcBufMut::set_filled_to`: Argument `to` is out of bounds: {to}" - ); - self.filled = to; - } - - /// Sets the buffer as initialized upto `to`. - /// - /// # Safety - /// - /// The caller must ensure that the buffer was initialized upto `to`. To do - /// this a `&mut [MaybeUninit]` can be obtained through - /// [`uninitialized_mut`] - /// - /// # Panics - /// - /// Panics if `to` is out of bounds. - /// - /// [`uninitialized_mut`]: Self::uninitialized_mut - pub unsafe fn set_initialized_to(&mut self, to: usize) { - self.inner.set_initialized_to(to); - } - - /// Fully initializes the underlying buffer. - /// - /// This does nothing if this [`ArcBufMut`] is not at the end of the buffer, - /// e.g. if it was the left half obtained from a [`ArcBufMut::split_at`]. - #[inline] - pub fn fully_initialize(&mut self) { - self.inner.fully_initialize(); - } - - /// Clears the buffer. - /// - /// Internally this sets the filled counter to 0. Any portion of the buffer - /// already initialized, stays initialized. - pub fn clear(&mut self) { - self.filled = 0; - } -} - -impl AsRef<[u8]> for ArcBufMut { - #[inline] - fn as_ref(&self) -> &[u8] { - self.filled() - } -} - -impl AsMut<[u8]> for ArcBufMut { - #[inline] - fn as_mut(&mut self) -> &mut [u8] { - self.filled_mut() - } -} - -impl Debug for ArcBufMut { - #[inline] - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - debug_as_hexdump(f, self.filled()) - } -} - -impl PartialEq for ArcBufMut { - #[inline] - fn eq(&self, other: &T) -> bool { - buf_eq(self, other) - } -} - -impl Buf for ArcBufMut { - type View<'a> = &'a [u8] - where - Self: 'a; - - type Reader<'a> = &'a [u8] - where - Self: 'a; - - #[inline] - fn view(&self, range: impl Into) -> Result, RangeOutOfBounds> { - range.into().slice_get(self.filled()) - } - - #[inline] - fn reader(&self) -> Self::Reader<'_> { - self.filled() - } -} - -impl Length for ArcBufMut { - #[inline] - fn len(&self) -> usize { - self.filled - } -} - -impl BufMut for ArcBufMut { - type ViewMut<'a> = &'a mut [u8] - where - Self: 'a; - - type Writer<'a> = Writer<'a> - where - Self: 'a; - - #[inline] - fn view_mut(&mut self, range: impl Into) -> Result, RangeOutOfBounds> { - range.into().slice_get_mut(self.filled_mut()) - } - - #[inline] - fn writer(&mut self) -> Self::Writer<'_> { - Writer::new(self) - } - - #[inline] - fn reserve(&mut self, size: usize) -> Result<(), Full> { - if size <= self.capacity() { - Ok(()) - } - else { - Err(Full { - required: size, - capacity: self.capacity(), - }) - } - } - - #[inline] - fn size_limit(&self) -> SizeLimit { - SizeLimit::Exact(self.capacity()) - } -} - -impl BytesMutImpl for ArcBufMut { - fn view(&self, range: Range) -> Result, RangeOutOfBounds> { - Ok(Box::new(range.slice_get(self.filled())?)) - } - - fn view_mut(&mut self, range: Range) -> Result, RangeOutOfBounds> { - Ok(Box::new(BufMut::view_mut(self, range)?)) - } - - fn reader(&self) -> Box + '_> { - Box::new(self.filled()) - } - - fn writer(&mut self) -> Box { - Box::new(Writer::new(self)) - } - - fn reserve(&mut self, size: usize) -> Result<(), Full> { - BufMut::reserve(self, size) - } - - fn size_limit(&self) -> SizeLimit { - BufMut::size_limit(self) - } - - fn split_at(&mut self, at: usize) -> Result, IndexOutOfBounds> { - Ok(Box::new(ArcBufMut::split_at(self, at)?)) - } -} - -impl From for Bytes { - #[inline] - fn from(value: ArcBuf) -> Self { - Bytes::from_impl(Box::new(value)) - } -} - -impl From for BytesMut { - #[inline] - fn from(value: ArcBufMut) -> Self { - BytesMut::from_impl(Box::new(value)) - } -} - -impl From for Bytes { - #[inline] - fn from(value: ArcBufMut) -> Self { - value.freeze().into() - } -} - -pub struct Writer<'a> { - buf: &'a mut ArcBufMut, - position: usize, -} - -impl<'a> Writer<'a> { - pub fn new(buf: &'a mut ArcBufMut) -> Self { - Self { buf, position: 0 } - } - - /// Fills the next `length` bytes by applying the closure `f` to it. - /// - /// # Safety - /// - /// `f` must initialize make sure the whole slice it is passed is - /// initialized after its call. - unsafe fn fill_with( - &mut self, - length: usize, - f: impl FnOnce(&mut [MaybeUninit]), - ) -> Result<(), Full> { - let end = self.position + length; - - if end <= self.buf.capacity() { - f(&mut self.buf.uninitialized_mut()[self.position..end]); - - unsafe { - // SAFETY: - // - access is unqiue, because we have a `&mut self` - // - the bytes upto `end` have just been initialized - self.buf.set_initialized_to(end); - } - - self.buf.filled = std::cmp::max(self.buf.filled, end); - self.position = end; - - Ok(()) - } - else { - Err(Full { - required: length, - capacity: self.buf.capacity(), - }) - } - } -} - -impl<'b> BufWriter for Writer<'b> { - type ViewMut<'a> = &'a mut [u8] where Self: 'a; - - #[inline] - fn peek_chunk_mut(&mut self) -> Option<&mut [u8]> { - if self.position < self.buf.filled { - Some(&mut self.buf.filled_mut()[self.position..]) - } - else { - None - } - } - - fn view_mut(&mut self, length: usize) -> Result, crate::io::Full> { - if self.position + length <= self.buf.filled { - let view = &mut self.buf.filled_mut()[self.position..][..length]; - self.position += length; - Ok(view) - } - else { - Err(crate::io::Full { - written: 0, - requested: length, - remaining: self.buf.filled - self.position, - }) - } - } - - #[inline] - fn peek_view_mut(&mut self, length: usize) -> Result, crate::io::Full> { - if self.position + length <= self.buf.filled { - Ok(&mut self.buf.filled_mut()[self.position..][..length]) - } - else { - Err(crate::io::Full { - written: 0, - requested: length, - remaining: self.buf.filled - self.position, - }) - } - } - - #[inline] - fn rest_mut(&mut self) -> Self::ViewMut<'_> { - let rest = &mut self.buf.filled_mut()[self.position..]; - self.position += rest.len(); - rest - } - - #[inline] - fn peek_rest_mut(&mut self) -> Self::ViewMut<'_> { - &mut self.buf.filled_mut()[self.position..] - } - - #[inline] - fn advance(&mut self, by: usize) -> Result<(), crate::io::Full> { - // note: The cursor position can't be greater than `self.filled`, and both point - // into the initialized portion, so it's safe to assume that the buffer has been - // initialized upto `already_filled`. - let already_filled = self.buf.filled - self.position; - - if by > already_filled { - unsafe { - // SAFETY: The closure initializes `already_filled..`. `..already_filled` is - // already filled, and thus initialized. - self.fill_with(by, |buf| { - MaybeUninit::fill(&mut buf[already_filled..], 0); - }) - } - .map_err(Into::into) - } - else { - self.position += by; - Ok(()) - } - } - - #[inline] - fn remaining(&self) -> usize { - self.buf.filled - self.position - } - - #[inline] - fn extend(&mut self, with: &[u8]) -> Result<(), crate::io::Full> { - unsafe { - // SAFETY: The closure initializes the whole slice. - self.fill_with(with.len(), |buf| { - MaybeUninit::copy_from_slice(buf, with); - }) - .map_err(Into::into) - } - } -} - -impl<'b> WriterImpl for Writer<'b> { - #[inline] - fn peek_chunk_mut(&mut self) -> Option<&mut [u8]> { - BufWriter::peek_chunk_mut(self) - } - - #[inline] - fn advance(&mut self, by: usize) -> Result<(), crate::io::Full> { - BufWriter::advance(self, by) - } - - #[inline] - fn remaining(&self) -> usize { - BufWriter::remaining(self) - } - - #[inline] - fn extend(&mut self, with: &[u8]) -> Result<(), crate::io::Full> { - BufWriter::extend(self, with) - } -} - -// SAFETY: -// -// This is safe to impl `Send` and `Sync`, because it only does mutable access -// to non-overlapping ranges and ensures only unique references to these exist. -unsafe impl Send for ArcBufMut {} -unsafe impl Sync for ArcBufMut {} - -impl_me! { - impl[] Reader for ArcBuf as BufReader; - impl['a] Writer for Writer<'a> as BufWriter; -} - -#[cfg(test)] -mod tests { - use super::ArcBufMut; - use crate::{ - buf::{ - tests::buf_mut_tests, - Full, - Length, - }, - copy, - hexdump::Hexdump, - }; - - buf_mut_tests!(ArcBufMut::new(20)); - - #[test] - fn it_reclaims_empty_buffers_correctly() { - // don't ask me why we have specifically this test lol - let (buf, reclaim) = ArcBufMut::new_reclaimable(0); - assert!(buf.inner.buf.meta_data.is_null()); - assert!(buf.ref_count().is_static()); - drop(buf); - assert!(reclaim.can_reclaim()); - let reclaimed = reclaim.try_reclaim().unwrap(); - assert!(reclaimed.ref_count().is_static()); - } - - #[test] - fn empty_bufs_dont_ref_count() { - let buf = ArcBufMut::new(10); - let frozen = buf.freeze(); - assert!(frozen.ref_count().is_static()); - - let buf = ArcBufMut::new(0); - assert!(buf.ref_count().is_static()); - } - - #[test] - fn empty_bufs_dont_allocate() { - let buf = ArcBufMut::new(0); - assert!(buf.inner.buf.buf.is_empty()); - assert!(buf.inner.buf.meta_data.is_null()); - - let mut buf = ArcBufMut::new(10); - let _buf_ref = buf.inner.split_at(10); - assert!(buf.inner.buf.meta_data.is_null()); - } - - #[test] - fn bufs_split_correctly() { - let mut buf = ArcBufMut::new(20); - copy(&mut buf, b"Hello World. This is").unwrap(); - - let new = buf.split_at(5).unwrap(); - - assert_eq!(new.len(), 5); - assert_eq!(buf.len(), 15); - - println!("{}", Hexdump::new(&new)); - println!("{}", Hexdump::new(&buf)); - - assert_eq!(new, b"Hello"); - assert_eq!(buf, b" World. This is"); - } - - #[test] - fn split_off_buf_doesnt_spill_into_other_half() { - let mut buf = ArcBufMut::new(20); - copy(&mut buf, b"Hello World. This is").unwrap(); - - let mut new = buf.split_at(5).unwrap(); - - let e = copy(&mut new, b"Spill much?").unwrap_err(); - - assert_eq!( - e, - Full { - required: 11, - capacity: 5 - } - ); - assert_eq!(new, b"Hello"); - assert_eq!(buf, b" World. This is"); - } - - #[test] - fn left_half_of_split_is_not_tail() { - let mut buf = ArcBufMut::new(20); - copy(&mut buf, b"Hello World. This is").unwrap(); - let left = buf.split_at(5).unwrap(); - assert!(!left.inner.tail); - } - - #[test] - fn buf_shrunk_to_zero_size_is_static() { - let mut buf = ArcBufMut::new(20); - copy(&mut buf, b"Hello World. This is").unwrap(); - - buf.inner.shrink(5, 5); - assert!(buf.ref_count().is_static()); - assert!(buf.inner.buf.meta_data.is_null()); - assert!(!buf.inner.tail); - } - - #[test] - fn it_splits_with_left_empty_correctly() { - let mut buf = ArcBufMut::new(20); - copy(&mut buf, b"Hello World. This is").unwrap(); - - let left = buf.split_at(0).unwrap(); - assert!(left.is_empty()); - assert_eq!(buf.len(), 20); - assert!(left.ref_count().is_static()); - assert!(left.inner.buf.meta_data.is_null()); - assert!(!left.inner.tail); - } - - #[test] - fn it_splits_with_right_empty_correctly() { - let mut buf = ArcBufMut::new(20); - copy(&mut buf, b"Hello World. This is").unwrap(); - - let left = buf.split_at(20).unwrap(); - assert!(buf.is_empty()); - assert_eq!(left.len(), 20); - assert!(buf.ref_count().is_static()); - assert!(buf.inner.buf.meta_data.is_null()); - assert!(!buf.inner.tail); - } -} diff --git a/byst/src/buf/array_buf.rs b/byst/src/buf/array_buf.rs deleted file mode 100644 index 0e302ee..0000000 --- a/byst/src/buf/array_buf.rs +++ /dev/null @@ -1,295 +0,0 @@ -use std::{ - fmt::Debug, - mem::MaybeUninit, -}; - -use super::{ - partially_initialized::{ - PartiallyInitialized, - PartiallyInitializedWriter, - }, - BufWriter, - Full, - Length, -}; -use crate::{ - buf::{ - Buf, - BufMut, - SizeLimit, - }, - io::Writer, - range::{ - Range, - RangeOutOfBounds, - }, - util::buf_eq, -}; - -/// A buffer backed by an array. The array is initially empty, but can grow -/// until it reaches its capacity `N`. -pub struct ArrayBuf { - inner: PartiallyInitialized<[MaybeUninit; N]>, -} - -impl ArrayBuf { - #[inline] - pub fn new() -> Self { - Self { - inner: PartiallyInitialized::new([MaybeUninit::uninit(); N]), - } - } - - #[inline] - pub fn is_full(&self) -> bool { - self.inner.is_full() - } - - pub fn resize(&mut self, new_len: usize, value: u8) { - self.inner.resize(new_len, value) - } - - #[inline] - pub fn clear(&mut self) { - self.inner.clear(); - } - - #[inline] - pub fn inner_ref(&self) -> &[MaybeUninit; N] { - self.inner.inner_ref() - } - - #[inline] - pub fn inner_mut(&mut self) -> &mut [MaybeUninit; N] { - self.inner.inner_mut() - } -} - -impl Default for ArrayBuf { - #[inline] - fn default() -> Self { - Self::new() - } -} - -impl AsRef<[u8]> for ArrayBuf { - #[inline] - fn as_ref(&self) -> &[u8] { - self.inner.as_ref() - } -} - -impl AsMut<[u8]> for ArrayBuf { - #[inline] - fn as_mut(&mut self) -> &mut [u8] { - self.inner.as_mut() - } -} - -impl Clone for ArrayBuf { - #[inline] - fn clone(&self) -> Self { - // note: we could auto-derive this, since `MaybeUninit` implements `Clone` if - // `T` (i.e. `u8`) is `Copy`. But it would copy the whole buffer, and we only - // copy the portion that has been initialized. - - let mut cloned = Self::new(); - let source = self.inner.as_ref(); - - MaybeUninit::copy_from_slice(&mut cloned.inner.inner_mut()[..source.len()], source); - unsafe { - // SAFETY: We just initialized the first `source.len()` bytes - cloned.inner.assume_initialized(source.len()); - } - - cloned - } -} - -impl Debug for ArrayBuf { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - Debug::fmt(&self.inner, f) - } -} - -impl PartialEq for ArrayBuf { - #[inline] - fn eq(&self, other: &T) -> bool { - buf_eq(self, other) - } -} - -impl Eq for ArrayBuf {} - -#[derive(Clone, Copy, Debug, thiserror::Error)] -#[error("Buffer only partially initialized: {initialized} < {buf_size}")] -pub struct NotFullyInitialized { - pub initialized: usize, - pub buf_size: usize, -} - -impl TryFrom> for [u8; N] { - type Error = NotFullyInitialized; - - fn try_from(value: ArrayBuf) -> Result { - let (buf, initialized) = value.inner.into_parts(); - if initialized == N { - unsafe { - // SAFETY: we just checked that it's fully initialized. - Ok(MaybeUninit::array_assume_init(buf)) - } - } - else { - Err(NotFullyInitialized { - initialized, - buf_size: N, - }) - } - } -} - -impl Buf for ArrayBuf { - type View<'a> = &'a [u8] - where - Self: 'a; - - type Reader<'a> = &'a [u8] - where - Self: 'a; - - #[inline] - fn view(&self, range: impl Into) -> Result, RangeOutOfBounds> { - self.inner.view(range) - } - - #[inline] - fn reader(&self) -> Self::Reader<'_> { - self.inner.reader() - } -} - -impl Length for ArrayBuf { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } -} - -impl BufMut for ArrayBuf { - type ViewMut<'a> = &'a mut [u8] - where - Self: 'a; - - type Writer<'a> = ArrayBufWriter<'a, N> - where - Self: 'a; - - #[inline] - fn view_mut(&mut self, range: impl Into) -> Result, RangeOutOfBounds> { - self.inner.view_mut(range) - } - - #[inline] - fn writer(&mut self) -> Self::Writer<'_> { - ArrayBufWriter { - inner: self.inner.writer(), - } - } - - #[inline] - fn reserve(&mut self, size: usize) -> Result<(), Full> { - self.inner.reserve(size) - } - - #[inline] - fn size_limit(&self) -> SizeLimit { - N.into() - } -} - -pub struct ArrayBufWriter<'a, const N: usize> { - inner: PartiallyInitializedWriter<'a, [MaybeUninit; N]>, -} - -impl<'b, const N: usize> BufWriter for ArrayBufWriter<'b, N> { - type ViewMut<'a> = &'a mut [u8] where Self: 'a; - - #[inline] - fn peek_chunk_mut(&mut self) -> Option<&mut [u8]> { - self.inner.peek_chunk_mut() - } - - fn view_mut(&mut self, length: usize) -> Result, crate::io::Full> { - self.inner.view_mut(length) - } - - #[inline] - fn peek_view_mut(&mut self, length: usize) -> Result, crate::io::Full> { - self.inner.peek_view_mut(length) - } - - #[inline] - fn rest_mut(&mut self) -> Self::ViewMut<'_> { - self.inner.rest_mut() - } - - #[inline] - fn peek_rest_mut(&mut self) -> Self::ViewMut<'_> { - self.inner.peek_rest_mut() - } - - #[inline] - fn advance(&mut self, by: usize) -> Result<(), crate::io::Full> { - self.inner.advance(by) - } - - #[inline] - fn remaining(&self) -> usize { - self.inner.remaining() - } - - #[inline] - fn extend(&mut self, with: &[u8]) -> Result<(), crate::io::Full> { - self.inner.extend(with) - } -} - -impl<'a, const N: usize> Writer for ArrayBufWriter<'a, N> { - type Error = ; N]> as Writer>::Error; - - #[inline] - fn write_buf(&mut self, buf: B) -> Result<(), crate::io::Full> { - self.inner.write_buf(buf) - } - - #[inline] - fn skip(&mut self, amount: usize) -> Result<(), crate::io::Full> { - self.inner.skip(amount) - } -} - -#[cfg(test)] -mod tests { - use super::ArrayBuf; - use crate::{ - buf::{ - tests::buf_mut_tests, - Full, - }, - copy, - }; - - buf_mut_tests!(ArrayBuf::<20>::new()); - - #[test] - fn cant_write_more_than_buf_size() { - let mut bytes_mut = ArrayBuf::<4>::new(); - assert_eq!( - copy(&mut bytes_mut, b"abcdefgh").unwrap_err(), - Full { - required: 8, - capacity: 4 - } - ); - } -} diff --git a/byst/src/buf/chunks.rs b/byst/src/buf/chunks.rs deleted file mode 100644 index 88d11de..0000000 --- a/byst/src/buf/chunks.rs +++ /dev/null @@ -1,136 +0,0 @@ -use std::iter::FusedIterator; - -use super::{ - Buf, - BufReader, - Length, -}; - -/// Iterator over the bytes in a buffer. -pub struct BufIter<'b, B: Buf + ?Sized + 'b> { - reader: B::Reader<'b>, -} - -impl<'b, B: Buf + ?Sized> BufIter<'b, B> { - #[inline] - pub fn new(buf: &'b B) -> Self { - let reader = buf.reader(); - Self { reader } - } -} - -impl<'b, B: Buf + ?Sized> Iterator for BufIter<'b, B> { - type Item = u8; - - #[inline] - fn next(&mut self) -> Option { - let chunk = self.reader.peek_chunk()?; - let byte = *chunk.first().expect("BufReader returned empty chunk.;"); - self.reader - .advance(1) - .expect("BufReader failed to advance by 1"); - Some(byte) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let remaining = self.reader.remaining(); - (remaining, Some(remaining)) - } -} - -impl<'b, B: Buf + ?Sized> FusedIterator for BufIter<'b, B> {} - -impl<'b, B: Buf + ?Sized> ExactSizeIterator for BufIter<'b, B> {} - -/// Iterator wrapper to skip empty chunks. -#[derive(Debug)] -pub struct NonEmpty { - inner: I, -} - -impl NonEmpty { - #[inline] - pub fn new(inner: I) -> Self { - Self { inner } - } - - #[inline] - pub fn into_inner(self) -> I { - self.inner - } -} - -impl> Iterator for NonEmpty { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - let item = self.inner.next()?; - (!item.is_empty()).then_some(item) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - (0, self.inner.size_hint().1) - } -} - -impl + DoubleEndedIterator> DoubleEndedIterator for NonEmpty { - #[inline] - fn next_back(&mut self) -> Option { - self.inner.next_back() - } -} - -impl + FusedIterator> FusedIterator for NonEmpty {} - -/// Wrapper for chunk iterators that also tracks the current offset. -pub struct WithOffset { - inner: I, - offset: usize, -} - -impl WithOffset { - #[inline] - pub fn new(inner: I) -> Self { - Self::with_initial_offset(inner, 0) - } - - #[inline] - pub fn with_initial_offset(inner: I, initial_offset: usize) -> Self { - Self { - inner, - offset: initial_offset, - } - } - - #[inline] - pub fn offset(&self) -> usize { - self.offset - } - - #[inline] - pub fn into_inner(self) -> I { - self.inner - } -} - -impl> Iterator for WithOffset { - type Item = (usize, T); - - #[inline] - fn next(&mut self) -> Option { - let chunk = self.inner.next()?; - let offset = self.offset; - self.offset += chunk.len(); - Some((offset, chunk)) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -impl + FusedIterator> FusedIterator for WithOffset {} diff --git a/byst/src/buf/empty.rs b/byst/src/buf/empty.rs deleted file mode 100644 index 24b622e..0000000 --- a/byst/src/buf/empty.rs +++ /dev/null @@ -1,394 +0,0 @@ -use std::ops::{ - Deref, - DerefMut, -}; - -use super::{ - Buf, - BufReader, - BufWriter, - Full, - Length, - SizeLimit, -}; -use crate::{ - bytes::r#impl::{ - BytesImpl, - BytesMutImpl, - WriterImpl, - }, - impl_me, - io::{ - End, - Reader, - Seek, - }, - BufMut, - Bytes, - IndexOutOfBounds, - Range, - RangeOutOfBounds, -}; - -/// An empty buffer. -#[derive(Debug, Clone, Copy, Default)] -pub struct Empty; - -impl From for Bytes { - #[inline] - fn from(value: Empty) -> Self { - Self::from_impl(Box::new(value)) - } -} - -impl Buf for Empty { - type View<'a> = Self - where - Self: 'a; - - type Reader<'a> = Self - where - Self: 'a; - - #[inline] - fn view(&self, range: impl Into) -> Result { - check_range(range.into())?; - Ok(Self) - } - - #[inline] - fn reader(&self) -> Self { - Self - } -} - -impl BufMut for Empty { - type ViewMut<'a> = Self - where - Self: 'a; - - type Writer<'a> = Self - where - Self: 'a; - - #[inline] - fn view_mut(&mut self, range: impl Into) -> Result { - check_range(range.into())?; - Ok(Self) - } - - #[inline] - fn writer(&mut self) -> Self { - Self - } - - #[inline] - fn reserve(&mut self, size: usize) -> Result<(), Full> { - if size == 0 { - Ok(()) - } - else { - Err(Full { - required: size, - capacity: 0, - }) - } - } - - #[inline] - fn size_limit(&self) -> SizeLimit { - SizeLimit::Exact(0) - } -} - -impl Length for Empty { - #[inline] - fn len(&self) -> usize { - 0 - } - - #[inline] - fn is_empty(&self) -> bool { - true - } -} - -impl BufReader for Empty { - type View = Self; - - #[inline] - fn peek_chunk(&self) -> Option<&'static [u8]> { - None - } - - #[inline] - fn view(&mut self, length: usize) -> Result { - check_length_read(length)?; - Ok(Self) - } - - #[inline] - fn peek_view(&self, length: usize) -> Result { - check_length_read(length)?; - Ok(Self) - } - - #[inline] - fn rest(&mut self) -> Self::View { - Self - } - - #[inline] - fn peek_rest(&self) -> Self::View { - Self - } - - #[inline] - fn advance(&mut self, by: usize) -> Result<(), End> { - check_length_read(by) - } - - #[inline] - fn remaining(&self) -> usize { - 0 - } -} - -impl Seek for Empty { - type Position = Self; - - #[inline] - fn tell(&self) -> Self::Position { - Self - } - - #[inline] - fn seek(&mut self, _position: &Self::Position) -> Self::Position { - Self - } -} - -impl BufWriter for Empty { - type ViewMut<'a> = Empty where Self: 'a; - - #[inline] - fn peek_chunk_mut(&mut self) -> Option<&mut [u8]> { - None - } - - fn view_mut(&mut self, length: usize) -> Result, crate::io::Full> { - check_length_write(length)?; - Ok(Self) - } - - #[inline] - fn peek_view_mut(&mut self, length: usize) -> Result, crate::io::Full> { - check_length_write(length)?; - Ok(Self) - } - - #[inline] - fn rest_mut(&mut self) -> Self::ViewMut<'_> { - Self - } - - #[inline] - fn peek_rest_mut(&mut self) -> Self::ViewMut<'_> { - Self - } - - #[inline] - fn advance(&mut self, by: usize) -> Result<(), crate::io::Full> { - check_length_write(by) - } - - #[inline] - fn remaining(&self) -> usize { - 0 - } - - #[inline] - fn extend(&mut self, with: &[u8]) -> Result<(), crate::io::Full> { - check_length_write(with.len()) - } -} - -impl Reader for Empty { - type Error = End; - - #[inline] - fn read_into( - &mut self, - _dest: D, - _limit: impl Into>, - ) -> Result { - Ok(0) - } - - fn read_into_exact(&mut self, _dest: D, length: usize) -> Result<(), Self::Error> { - check_length_read(length) - } - - #[inline] - fn skip(&mut self, amount: usize) -> Result<(), Self::Error> { - check_length_read(amount) - } -} - -impl PartialEq for Empty { - #[inline] - fn eq(&self, other: &T) -> bool { - other.is_empty() - } -} - -impl Deref for Empty { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - Default::default() - } -} - -impl DerefMut for Empty { - fn deref_mut(&mut self) -> &mut Self::Target { - Default::default() - } -} - -impl AsRef<[u8]> for Empty { - fn as_ref(&self) -> &[u8] { - Default::default() - } -} - -impl AsMut<[u8]> for Empty { - fn as_mut(&mut self) -> &mut [u8] { - Default::default() - } -} - -impl<'b> BytesImpl<'b> for Empty { - fn view(&self, range: Range) -> Result + 'b>, RangeOutOfBounds> { - check_range(range)?; - Ok(Box::new(Self)) - } - - fn clone(&self) -> Box + 'b> { - Box::new(Self) - } - - fn peek_chunk(&self) -> Option<&'_ [u8]> { - None - } - - fn advance(&mut self, by: usize) -> Result<(), End> { - BufReader::advance(self, by) - } -} - -impl BytesMutImpl for Empty { - fn view(&self, range: Range) -> Result + '_>, RangeOutOfBounds> { - check_range(range)?; - Ok(Box::new(Self)) - } - - fn view_mut( - &mut self, - range: Range, - ) -> Result, RangeOutOfBounds> { - check_range(range)?; - Ok(Box::new(Self)) - } - - fn reader(&self) -> Box + '_> { - Box::new(Self) - } - - fn writer(&mut self) -> Box { - Box::new(Self) - } - - fn reserve(&mut self, size: usize) -> Result<(), Full> { - BufMut::reserve(self, size) - } - - fn size_limit(&self) -> SizeLimit { - BufMut::size_limit(self) - } - - fn split_at(&mut self, at: usize) -> Result, IndexOutOfBounds> { - if at == 0 { - Ok(Box::new(Self)) - } - else { - Err(IndexOutOfBounds { - required: at, - bounds: (0, 0), - }) - } - } -} - -impl WriterImpl for Empty { - fn peek_chunk_mut(&mut self) -> Option<&mut [u8]> { - None - } - - fn advance(&mut self, by: usize) -> Result<(), crate::io::Full> { - BufWriter::advance(self, by) - } - - fn remaining(&self) -> usize { - 0 - } - - fn extend(&mut self, with: &[u8]) -> Result<(), crate::io::Full> { - BufWriter::extend(self, with) - } -} - -impl_me! { - impl Writer for Empty as BufWriter; -} - -#[inline] -fn check_range(range: Range) -> Result<(), RangeOutOfBounds> { - if range.start.unwrap_or_default() == 0 && range.end.unwrap_or_default() == 0 { - Ok(()) - } - else { - Err(RangeOutOfBounds { - required: range, - bounds: (0, 0), - }) - } -} - -#[inline] -fn check_length_write(length: usize) -> Result<(), crate::io::Full> { - if length == 0 { - Ok(()) - } - else { - Err(crate::io::Full { - written: 0, - requested: length, - remaining: 0, - }) - } -} - -#[inline] -fn check_length_read(length: usize) -> Result<(), End> { - if length == 0 { - Ok(()) - } - else { - Err(End { - read: 0, - requested: length, - remaining: 0, - }) - } -} diff --git a/byst/src/buf/mod.rs b/byst/src/buf/mod.rs deleted file mode 100644 index dec5d72..0000000 --- a/byst/src/buf/mod.rs +++ /dev/null @@ -1,620 +0,0 @@ -pub mod arc_buf; -pub mod array_buf; -pub mod chunks; -mod empty; -mod partially_initialized; -pub mod rope; -mod slab; - -use std::{ - borrow::Cow, - fmt::Debug, - ops::{ - Deref, - DerefMut, - }, - rc::Rc, - sync::Arc, -}; - -use chunks::BufIter; - -pub use self::{ - empty::Empty, - slab::Slab, -}; -use super::range::{ - Range, - RangeOutOfBounds, -}; -use crate::{ - impl_me, - io::{ - BufReader, - BufWriter, - }, -}; - -pub trait Length { - /// Returns the length of this buffer in bytes. - fn len(&self) -> usize; - - /// Returns whether this buffer is empty (i.e. has length 0). - #[inline] - fn is_empty(&self) -> bool { - self.len() == 0 - } -} - -/// Read access to a buffer of bytes. -pub trait Buf: Length { - /// A view of a portion of the buffer. - type View<'a>: Buf + Sized + 'a - where - Self: 'a; - - type Reader<'a>: BufReader> - where - Self: 'a; - - /// Returns a view of a portion of the buffer. - fn view(&self, range: impl Into) -> Result, RangeOutOfBounds>; - - /// Returns a [`BufReader`] for this buffer. - fn reader(&self) -> Self::Reader<'_>; - - /// Returns whether this buffer contains bytes for the given range. - /// - /// # Default implementation - /// - /// The default implementation will check if the range is contained by - /// `..self.len()`. - #[inline] - fn contains(&self, range: impl Into) -> bool { - range.into().contained_by(..self.len()) - } -} - -pub trait BufExt: Buf { - #[inline] - fn bytes_iter(&self) -> BufIter<'_, Self> { - BufIter::new(self) - } - - fn as_vec(&self) -> Vec { - let mut reader = self.reader(); - let mut buf = Vec::with_capacity(reader.remaining()); - while let Some(chunk) = reader.peek_chunk() { - buf.extend(chunk.iter().copied()); - reader.advance(chunk.len()).unwrap(); - } - buf - } -} - -impl BufExt for B {} - -/// Write access to a buffer of bytes. -pub trait BufMut: Buf { - /// Mutable view of a portion of the buffer. - type ViewMut<'a>: BufMut + Sized - where - Self: 'a; - - type Writer<'a>: BufWriter - where - Self: 'a; - - /// Returns a mutable view of a portion of the buffer. - fn view_mut(&mut self, range: impl Into) -> Result, RangeOutOfBounds>; - - fn writer(&mut self) -> Self::Writer<'_>; - - fn reserve(&mut self, size: usize) -> Result<(), Full>; - - fn size_limit(&self) -> SizeLimit; -} - -#[derive(Clone, Copy, Debug, Default)] -pub enum SizeLimit { - /// The [`BufMut`] can grow, but might get full. - #[default] - Unknown, - - /// The [`BufMut`] can grow limitless. - Unlimited, - - /// The [`BufMut`] can grow to this exact length. - Exact(usize), -} - -impl From for SizeLimit { - #[inline] - fn from(value: usize) -> Self { - Self::Exact(value) - } -} - -#[derive(Debug, PartialEq, Eq, thiserror::Error)] -#[error( - "Buffer is full: data with length ({required}) can't fit into buffer with length {capacity}." -)] -pub struct Full { - pub required: usize, - pub capacity: usize, -} - -impl From for Full { - fn from(value: crate::io::Full) -> Self { - Self { - required: value.requested, - capacity: value.remaining + value.written, - } - } -} - -impl Length for [u8] { - #[inline] - fn len(&self) -> usize { - <[u8]>::len(self) - } -} - -impl Length for [u8; N] { - #[inline] - fn len(&self) -> usize { - N - } -} - -impl<'a, T: Length + ?Sized> Length for &'a T { - #[inline] - fn len(&self) -> usize { - T::len(self) - } -} - -impl<'a, T: Length + ?Sized> Length for &'a mut T { - #[inline] - fn len(&self) -> usize { - T::len(self) - } -} - -impl Length for Box { - #[inline] - fn len(&self) -> usize { - T::len(self) - } -} - -impl Length for Arc { - #[inline] - fn len(&self) -> usize { - T::len(self) - } -} - -impl Length for Rc { - #[inline] - fn len(&self) -> usize { - T::len(self) - } -} - -impl<'a, T: Length + ToOwned + ?Sized> Length for Cow<'a, T> { - #[inline] - fn len(&self) -> usize { - T::len(self) - } -} - -impl Length for Vec { - #[inline] - fn len(&self) -> usize { - Vec::len(self) - } -} - -macro_rules! impl_buf_with_deref { - { - $( - ($($generics:tt)*), $ty:ty; - )* - } => { - $( - impl<$($generics)*> Buf for $ty { - type View<'a> = ::View<'a> where Self: 'a; - type Reader<'a> = ::Reader<'a> where Self: 'a; - - #[inline] - fn view(&self, range: impl Into) -> Result, RangeOutOfBounds> { - ::view(self.deref(), range) - } - - #[inline] - fn reader(&self) -> Self::Reader<'_> { - ::reader(self.deref()) - } - } - )* - }; -} - -impl_buf_with_deref! { - ('b, B: Buf + ?Sized), &'b B; - ('b, B: Buf + ?Sized), &'b mut B; - (B: Buf + ?Sized), Box; - (B: Buf + ?Sized), Arc; - (B: Buf + ?Sized), Rc; -} - -macro_rules! impl_buf_for_slice_like { - { - $( - ($($generics:tt)*), $ty:ty, $view_lt:lifetime; - )* - } => { - $( - impl<$($generics)*> Buf for $ty { - type View<'a> = & $view_lt [u8] where Self: 'a; - type Reader<'a> = & $view_lt [u8] where Self: 'a; - - #[inline] - fn view<'a>(&'a self, range: impl Into) -> Result<& $view_lt [u8], RangeOutOfBounds> { - range.into().slice_get(self) - } - - #[inline] - fn reader(&self) -> Self::Reader<'_> { - self - } - } - )* - }; -} - -// note: it would be better to impl `Buf` for `[u8]` and let the blanket impls -// above impl for `&[u8]` etc., but an implementation for `[u8]` would have -// `Buf::View = &[u8]`, which at that point doesn't implement `Buf` yet. it's -// the classic chicken-egg problem. -impl_buf_for_slice_like! { - ('b), &'b [u8], 'b; - (const N: usize), [u8; N], 'a; - ('b), &'b mut [u8], 'a; - (), Vec, 'a; - (), Box<[u8]>, 'a; - (), Arc<[u8]>, 'a; - ('b), Cow<'b, [u8]>, 'a; -} - -impl<'b, B: BufMut + ?Sized> BufMut for &'b mut B { - type ViewMut<'a> = ::ViewMut<'a> where Self: 'a; - type Writer<'a> = ::Writer<'a> where Self: 'a; - - #[inline] - fn view_mut(&mut self, range: impl Into) -> Result, RangeOutOfBounds> { - ::view_mut(self.deref_mut(), range) - } - - #[inline] - fn writer(&mut self) -> Self::Writer<'_> { - ::writer(self.deref_mut()) - } - - #[inline] - fn reserve(&mut self, size: usize) -> Result<(), Full> { - ::reserve(self.deref_mut(), size) - } - - #[inline] - fn size_limit(&self) -> SizeLimit { - ::size_limit(self) - } -} - -impl BufMut for Box { - type ViewMut<'a> = ::ViewMut<'a> where Self: 'a; - type Writer<'a> = ::Writer<'a> where Self: 'a; - - #[inline] - fn view_mut(&mut self, range: impl Into) -> Result, RangeOutOfBounds> { - ::view_mut(self.deref_mut(), range) - } - - #[inline] - fn writer(&mut self) -> Self::Writer<'_> { - ::writer(self.deref_mut()) - } - - #[inline] - fn reserve(&mut self, size: usize) -> Result<(), Full> { - ::reserve(self.deref_mut(), size) - } - - #[inline] - fn size_limit(&self) -> SizeLimit { - ::size_limit(self) - } -} - -impl<'b> BufMut for &'b mut [u8] { - type ViewMut<'a> = &'a mut [u8] where Self: 'a; - type Writer<'a> = &'a mut [u8] where Self: 'a; - - #[inline] - fn view_mut(&mut self, range: impl Into) -> Result, RangeOutOfBounds> { - range.into().slice_get_mut(self) - } - - #[inline] - fn writer(&mut self) -> Self::Writer<'_> { - self - } - - #[inline] - fn reserve(&mut self, size: usize) -> Result<(), Full> { - if size > self.len() { - Err(Full { - required: size, - capacity: self.len(), - }) - } - else { - Ok(()) - } - } - - #[inline] - fn size_limit(&self) -> SizeLimit { - self.len().into() - } -} - -impl BufMut for [u8; N] { - type ViewMut<'a> = &'a mut [u8] where Self: 'a; - type Writer<'a> = &'a mut [u8] where Self: 'a; - - #[inline] - fn view_mut(&mut self, range: impl Into) -> Result, RangeOutOfBounds> { - range.into().slice_get_mut(self) - } - - #[inline] - fn writer(&mut self) -> Self::Writer<'_> { - self - } - - #[inline] - fn reserve(&mut self, size: usize) -> Result<(), Full> { - if size > N { - Err(Full { - required: size, - capacity: self.len(), - }) - } - else { - Ok(()) - } - } - - #[inline] - fn size_limit(&self) -> SizeLimit { - self.len().into() - } -} - -impl BufMut for Box<[u8]> { - type ViewMut<'a> = &'a mut [u8] where Self: 'a; - type Writer<'a> = &'a mut [u8] where Self: 'a; - - #[inline] - fn view_mut(&mut self, range: impl Into) -> Result, RangeOutOfBounds> { - range.into().slice_get_mut(self) - } - - #[inline] - fn writer(&mut self) -> Self::Writer<'_> { - self - } - - #[inline] - fn reserve(&mut self, size: usize) -> Result<(), Full> { - if size > self.len() { - Err(Full { - required: size, - capacity: self.len(), - }) - } - else { - Ok(()) - } - } - - #[inline] - fn size_limit(&self) -> SizeLimit { - self.len().into() - } -} - -impl BufMut for Vec { - type ViewMut<'a> = &'a mut [u8] where Self: 'a; - type Writer<'a> = VecWriter<'a> where Self: 'a; - - #[inline] - fn view_mut(&mut self, range: impl Into) -> Result, RangeOutOfBounds> { - range.into().slice_get_mut(self) - } - - #[inline] - fn writer(&mut self) -> Self::Writer<'_> { - VecWriter::new(self) - } - - #[inline] - fn reserve(&mut self, size: usize) -> Result<(), Full> { - if size > self.len() { - self.reserve_exact(size - self.len()); - } - Ok(()) - } - - #[inline] - fn size_limit(&self) -> SizeLimit { - SizeLimit::Unlimited - } -} - -#[derive(Debug)] -pub struct VecWriter<'a> { - vec: &'a mut Vec, - position: usize, -} - -impl<'a> VecWriter<'a> { - #[inline] - fn new(vec: &'a mut Vec) -> Self { - Self { vec, position: 0 } - } -} - -impl<'v> BufWriter for VecWriter<'v> { - type ViewMut<'a> = &'a mut [u8] where Self: 'a; - - #[inline] - fn peek_chunk_mut(&mut self) -> Option<&mut [u8]> { - if self.position < self.vec.len() { - Some(&mut self.vec[self.position..]) - } - else { - None - } - } - - fn view_mut(&mut self, length: usize) -> Result, crate::io::Full> { - if self.position + length <= self.vec.len() { - let view = &mut self.vec[self.position..][..length]; - self.position += length; - Ok(view) - } - else { - Err(crate::io::Full { - written: 0, - requested: length, - remaining: self.vec.len() - self.position, - }) - } - } - - #[inline] - fn peek_view_mut(&mut self, length: usize) -> Result, crate::io::Full> { - if self.position + length <= self.vec.len() { - Ok(&mut self.vec[self.position..][..length]) - } - else { - Err(crate::io::Full { - written: 0, - requested: length, - remaining: self.vec.len() - self.position, - }) - } - } - - #[inline] - fn rest_mut(&mut self) -> Self::ViewMut<'_> { - let new_position = self.vec.len(); - let rest = &mut self.vec[self.position..]; - self.position = new_position; - rest - } - - #[inline] - fn peek_rest_mut(&mut self) -> Self::ViewMut<'_> { - &mut self.vec[self.position..] - } - - #[inline] - fn advance(&mut self, by: usize) -> Result<(), crate::io::Full> { - let n = (self.position + by).saturating_sub(self.vec.len()); - self.vec.extend((0..n).map(|_| 0)); - self.position += by; - Ok(()) - } - - #[inline] - fn remaining(&self) -> usize { - self.vec.len() - } - - #[inline] - fn extend(&mut self, with: &[u8]) -> Result<(), crate::io::Full> { - let n_overwrite = std::cmp::min(self.vec.len() - self.position, with.len()); - self.vec[self.position..][..n_overwrite].copy_from_slice(&with[..n_overwrite]); - self.vec.extend(with[n_overwrite..].iter().copied()); - self.position += with.len(); - Ok(()) - } -} - -impl_me! { - impl['a] Writer for VecWriter<'a> as BufWriter; -} - -#[cfg(test)] -pub(crate) mod tests { - macro_rules! buf_mut_tests { - ($new:expr) => { - #[test] - fn copy_with_fill() { - use ::byst::{ - buf::{ - Buf as _, - BufReader as _, - }, - copy_range, - }; - let mut bytes_mut = $new; - copy_range(&mut bytes_mut, 4..8, b"abcd", ..).unwrap(); - assert_eq!( - bytes_mut.reader().peek_chunk().unwrap(), - b"\x00\x00\x00\x00abcd" - ); - } - - #[test] - fn copy_over_buf_end() { - use ::byst::{ - buf::{ - Buf as _, - BufReader as _, - }, - copy_range, - }; - let mut bytes_mut = $new; - copy_range(&mut bytes_mut, 0..4, b"abcd", ..).unwrap(); - copy_range(&mut bytes_mut, 2..6, b"efgh", ..).unwrap(); - assert_eq!(bytes_mut.reader().peek_chunk().unwrap(), b"abefgh"); - } - - #[test] - fn copy_extend_with_unbounded_destination_slice() { - use ::byst::{ - buf::{ - Buf as _, - BufReader as _, - }, - copy_range, - }; - let mut bytes_mut = $new; - copy_range(&mut bytes_mut, 0..4, b"abcd", ..).unwrap(); - copy_range(&mut bytes_mut, 2.., b"efgh", ..).unwrap(); - assert_eq!(bytes_mut.reader().peek_chunk().unwrap(), b"abefgh"); - } - }; - } - pub(crate) use buf_mut_tests; - - mod vec { - buf_mut_tests!(Vec::::new()); - } -} diff --git a/byst/src/buf/partially_initialized.rs b/byst/src/buf/partially_initialized.rs deleted file mode 100644 index fc512bb..0000000 --- a/byst/src/buf/partially_initialized.rs +++ /dev/null @@ -1,358 +0,0 @@ -//! # Note -//! -//! This is intentionally not public. If used with a type `B`, which doesn't -//! uphold some invariants, can cause UB. We could make the `new` method unsafe, -//! or use an unsafe-marked trait. - -use std::{ - fmt::Debug, - mem::MaybeUninit, -}; - -use super::{ - Full, - Length, -}; -use crate::{ - buf::{ - Buf, - BufMut, - SizeLimit, - }, - impl_me, - io::BufWriter, - range::{ - Range, - RangeOutOfBounds, - }, - util::debug_as_hexdump, -}; - -/// A contiguous chunk of memory that is partially initialized. -#[derive(Copy, Clone)] -pub struct PartiallyInitialized { - // invariant: `buf[..initialized]` is initialized. - buf: B, - initialized: usize, -} - -impl PartiallyInitialized { - #[inline] - pub fn new(buf: B) -> Self { - Self { - buf, - initialized: 0, - } - } - - #[inline] - pub unsafe fn assume_initialized(&mut self, initialized: usize) { - self.initialized = self.initialized.max(initialized); - } - - #[inline] - pub fn clear(&mut self) { - self.initialized = 0; - } - - #[inline] - pub fn inner_ref(&self) -> &B { - &self.buf - } - - #[inline] - pub fn inner_mut(&mut self) -> &mut B { - &mut self.buf - } - - #[inline] - pub fn into_parts(self) -> (B, usize) { - (self.buf, self.initialized) - } -} - -impl]>> PartiallyInitialized { - #[inline] - fn bytes(&self) -> &[u8] { - // invariant: this will always return a slice of length `self.initialized`. - - // SAFETY: see invariant in struct - unsafe { MaybeUninit::slice_assume_init_ref(&self.buf.as_ref()[..self.initialized]) } - } - - #[inline] - pub fn capacity(&self) -> usize { - self.buf.as_ref().len() - } - - #[inline] - pub fn is_full(&self) -> bool { - self.initialized == self.buf.as_ref().len() - } -} - -impl]> + AsMut<[MaybeUninit]>> PartiallyInitialized { - #[inline] - fn bytes_mut(&mut self) -> &mut [u8] { - // invariant: this will always return a slice of length `self.initialized`. - - // SAFETY: see invariant in struct - unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf.as_mut()[..self.initialized]) } - } - - pub fn resize(&mut self, new_len: usize, value: u8) { - let n = self.buf.as_ref().len(); - if new_len > n { - panic!("Can't resize ArrayBuf<{n}> to length {new_len}"); - } - - // after this the struct invariant still holds - if new_len > self.initialized { - MaybeUninit::fill(&mut self.buf.as_mut()[self.initialized..new_len], value); - } - self.initialized = new_len; - } -} - -impl]>> AsRef<[u8]> for PartiallyInitialized { - #[inline] - fn as_ref(&self) -> &[u8] { - self.bytes() - } -} - -impl]> + AsMut<[MaybeUninit]>> AsMut<[u8]> - for PartiallyInitialized -{ - #[inline] - fn as_mut(&mut self) -> &mut [u8] { - self.bytes_mut() - } -} - -impl]>> Debug for PartiallyInitialized { - #[inline] - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - debug_as_hexdump(f, self) - } -} - -impl]>> PartialEq for PartiallyInitialized { - #[inline] - fn eq(&self, other: &Self) -> bool { - self.bytes() == other.bytes() - } -} - -impl]>> Eq for PartiallyInitialized {} - -impl]>> Buf for PartiallyInitialized { - type View<'a> = &'a [u8] - where - Self: 'a; - - type Reader<'a> = &'a [u8] - where - Self: 'a; - - #[inline] - fn view(&self, range: impl Into) -> Result, RangeOutOfBounds> { - range.into().slice_get(self.bytes()) - } - - #[inline] - fn reader(&self) -> Self::Reader<'_> { - self.bytes() - } -} - -impl]>> Length for PartiallyInitialized { - #[inline] - fn len(&self) -> usize { - self.initialized - } -} - -impl]> + AsMut<[MaybeUninit]>> BufMut for PartiallyInitialized { - type ViewMut<'a> = &'a mut [u8] - where - Self: 'a; - - type Writer<'a> = PartiallyInitializedWriter<'a, B> - where - Self: 'a; - - #[inline] - fn view_mut(&mut self, range: impl Into) -> Result, RangeOutOfBounds> { - range.into().slice_get_mut(self.bytes_mut()) - } - - #[inline] - fn writer(&mut self) -> Self::Writer<'_> { - PartiallyInitializedWriter { - partially_initialized: self, - position: 0, - } - } - - fn reserve(&mut self, size: usize) -> Result<(), Full> { - let n = self.buf.as_ref().len(); - if size <= n { - Ok(()) - } - else { - Err(Full { - required: size, - capacity: n, - }) - } - } - - #[inline] - fn size_limit(&self) -> SizeLimit { - self.buf.as_ref().len().into() - } -} - -pub struct PartiallyInitializedWriter<'a, B> { - partially_initialized: &'a mut PartiallyInitialized, - position: usize, -} - -impl<'a, B: AsRef<[MaybeUninit]> + AsMut<[MaybeUninit]>> PartiallyInitializedWriter<'a, B> { - /// Fills the next `length` bytes by applying the closure `f` to it. - /// - /// # Safety - /// - /// `f` must initialize make sure the whole slice it is passed is - /// initialized after its call. - unsafe fn fill_with( - &mut self, - length: usize, - f: impl FnOnce(&mut [MaybeUninit]), - ) -> Result<(), Full> { - let end = self.position + length; - - if end <= self.partially_initialized.capacity() { - f(&mut self.partially_initialized.buf.as_mut()[self.position..end]); - - unsafe { - // SAFETY: - // - access is unqiue, because we have a `&mut self` - // - the bytes upto `end` have just been initialized - self.partially_initialized.assume_initialized(end); - } - - self.position = end; - - Ok(()) - } - else { - Err(Full { - required: length, - capacity: self.partially_initialized.capacity(), - }) - } - } -} - -impl<'b, B: AsRef<[MaybeUninit]> + AsMut<[MaybeUninit]>> BufWriter - for PartiallyInitializedWriter<'b, B> -{ - type ViewMut<'a> = &'a mut [u8] where Self: 'a; - - #[inline] - fn peek_chunk_mut(&mut self) -> Option<&mut [u8]> { - if self.position < self.partially_initialized.initialized { - Some(&mut self.partially_initialized.bytes_mut()[self.position..]) - } - else { - None - } - } - - fn view_mut(&mut self, length: usize) -> Result, crate::io::Full> { - if self.position + length <= self.partially_initialized.initialized { - let view = &mut self.partially_initialized.bytes_mut()[self.position..][..length]; - self.position += length; - Ok(view) - } - else { - Err(crate::io::Full { - written: 0, - requested: length, - remaining: self.partially_initialized.initialized - self.position, - }) - } - } - - #[inline] - fn peek_view_mut(&mut self, length: usize) -> Result, crate::io::Full> { - if self.position + length <= self.partially_initialized.initialized { - Ok(&mut self.partially_initialized.bytes_mut()[self.position..][..length]) - } - else { - Err(crate::io::Full { - written: 0, - requested: length, - remaining: self.partially_initialized.initialized - self.position, - }) - } - } - - #[inline] - fn rest_mut(&mut self) -> Self::ViewMut<'_> { - let new_position = self.partially_initialized.initialized; - let rest = &mut self.partially_initialized.bytes_mut()[self.position..]; - self.position = new_position; - rest - } - - #[inline] - fn peek_rest_mut(&mut self) -> Self::ViewMut<'_> { - &mut self.partially_initialized.bytes_mut()[self.position..] - } - - #[inline] - fn advance(&mut self, by: usize) -> Result<(), crate::io::Full> { - // note: The cursor position can't be greater than `self.filled`, and both point - // into the initialized portion, so it's safe to assume that the buffer has been - // initialized upto `already_filled`. - let already_filled = self.partially_initialized.initialized - self.position; - - if by > already_filled { - unsafe { - // SAFETY: The closure initializes `already_filled..`. `..already_filled` is - // already filled, and thus initialized. - self.fill_with(by, |buf| { - MaybeUninit::fill(&mut buf[already_filled..], 0); - }) - } - .map_err(Into::into) - } - else { - self.position += by; - Ok(()) - } - } - - #[inline] - fn remaining(&self) -> usize { - self.partially_initialized.initialized - self.position - } - - #[inline] - fn extend(&mut self, with: &[u8]) -> Result<(), crate::io::Full> { - unsafe { - // SAFETY: The closure initializes the whole slice. - self.fill_with(with.len(), |buf| { - MaybeUninit::copy_from_slice(buf, with); - }) - } - .map_err(Into::into) - } -} - -impl_me! { - impl['a, B: AsRef<[MaybeUninit]> + AsMut<[MaybeUninit]>] Writer for PartiallyInitializedWriter<'a, B> as BufWriter; -} diff --git a/byst/src/buf/rope.rs b/byst/src/buf/rope.rs deleted file mode 100644 index 3fd084c..0000000 --- a/byst/src/buf/rope.rs +++ /dev/null @@ -1,453 +0,0 @@ -use std::{ - cmp::Ordering, - fmt::Debug, -}; - -use super::{ - chunks::WithOffset, - BufReader, - Length, -}; -use crate::{ - impl_me, - io::{ - End, - Seek, - }, - Buf, - Range, - RangeOutOfBounds, -}; - -#[derive(Clone, Copy, Debug)] -pub(crate) struct Segment { - pub(crate) offset: usize, - pub(crate) buf: B, -} - -#[derive(Clone, Debug)] -pub struct Rope { - segments: Vec>, -} - -impl Rope { - #[inline] - pub fn new() -> Self { - Self::with_capacity(0) - } - - #[inline] - pub fn with_capacity(capacity: usize) -> Self { - Self { - segments: Vec::with_capacity(capacity), - } - } - - #[inline] - pub fn num_segments(&self) -> usize { - self.segments.len() - } -} - -impl Rope { - pub fn push(&mut self, segment: B) { - if !segment.is_empty() { - self.segments.push(Segment { - offset: self.len(), - buf: segment, - }); - } - } - - fn view_checked(&self, range: Range) -> Result, RangeOutOfBounds> { - let (start, end) = range.indices_checked_in(0, self.len())?; - Ok(view_unchecked(&self.segments, start, end)) - } -} - -impl Buf for Rope { - type View<'a> = View<'a, B> - where - Self: 'a; - - type Reader<'a> = Reader<'a, B> - where - Self: 'a; - - #[inline] - fn view(&self, range: impl Into) -> Result, RangeOutOfBounds> { - self.view_checked(range.into()) - } - - #[inline] - fn reader(&self) -> Self::Reader<'_> { - todo!(); - } -} - -impl Length for Rope { - #[inline] - fn len(&self) -> usize { - self.segments - .last() - .map(|segment| segment.offset + segment.buf.len()) - .unwrap_or_default() - } -} - -impl FromIterator for Rope { - fn from_iter>(iter: T) -> Self { - Self { - segments: WithOffset::new(iter.into_iter()) - .map(|(offset, buf)| Segment { offset, buf }) - .collect(), - } - } -} - -impl Default for Rope { - #[inline] - fn default() -> Self { - Self::new() - } -} - -#[derive(Clone, Copy, Debug)] -pub struct View<'b, B> { - segments: &'b [Segment], - start_offset: usize, - end_offset: usize, -} - -impl<'b, B: Buf> View<'b, B> { - fn view_checked(&self, range: Range) -> Result, RangeOutOfBounds> { - let (start, end) = range.indices_checked_in(0, self.len())?; - let first_offset = self - .segments - .first() - .map(|segment| segment.offset) - .unwrap_or_default(); - Ok(view_unchecked( - self.segments, - start + first_offset + self.start_offset, - end + first_offset + self.start_offset, - )) - } -} - -impl<'b, B: Buf> Buf for View<'b, B> { - type View<'a> = View<'a, B> - where - Self: 'a; - - type Reader<'a> = Reader<'a, B> - where - Self: 'a; - - #[inline] - fn view(&self, range: impl Into) -> Result, RangeOutOfBounds> { - self.view_checked(range.into()) - } - - #[inline] - fn reader(&self) -> Self::Reader<'_> { - todo!(); - } -} - -impl<'b, B: Length> Length for View<'b, B> { - fn len(&self) -> usize { - self.segments - .first() - .zip(self.segments.last()) - .map(|(first, last)| last.offset - first.offset + self.end_offset - self.start_offset) - .unwrap_or_default() - } -} - -pub struct Reader<'a, B> { - _segments: std::slice::Iter<'a, Segment>, -} - -impl<'a, B> Default for Reader<'a, B> { - fn default() -> Self { - Self { - _segments: [].iter(), - } - } -} - -impl<'a, B: Buf> BufReader for Reader<'a, B> { - type View = View<'a, B>; - - fn peek_chunk(&self) -> Option<&[u8]> { - todo!() - } - - #[inline] - fn view(&mut self, _length: usize) -> Result { - todo!() - } - - fn peek_view(&self, _length: usize) -> Result { - todo!() - } - - fn rest(&mut self) -> Self::View { - todo!() - } - - fn peek_rest(&self) -> Self::View { - todo!() - } - - fn advance(&mut self, _by: usize) -> Result<(), End> { - todo!() - } - - fn remaining(&self) -> usize { - todo!() - } -} - -impl<'a, B: Buf> Seek for Reader<'a, B> { - type Position = (); - - fn tell(&self) -> Self::Position { - todo!(); - } - - fn seek(&mut self, _position: &Self::Position) -> Self::Position { - todo!(); - } -} - -impl_me! { - impl['a, B: Buf] Reader for Reader<'a, B> as BufReader; -} - -pub(crate) fn find_segment( - segments: &[S], - offset: usize, - end_spill_over: bool, - bounds: impl Fn(&S) -> (usize, usize), -) -> Option { - segments - .binary_search_by(|segment| { - let (start, end) = bounds(segment); - match (offset.cmp(&start), offset.cmp(&end)) { - // target is left of current - (Ordering::Less, _) => Ordering::Greater, - // target is definitely right of current - (_, Ordering::Greater) => Ordering::Less, - // offset falls on end of this segment. What we do here depends no - // `end_spill_over`. This is used to go to the next segment, - // if we're looking for the start of a range, or return this segment, if we're - // looking for the end of a range. - (_, Ordering::Equal) if end_spill_over => Ordering::Less, - // remaining cases are if this is the segment - _ => Ordering::Equal, - } - }) - .ok() -} - -pub(crate) struct SegmentBounds { - pub start_segment: usize, - pub start_offset: usize, - pub end_segment: usize, - pub end_offset: usize, -} - -pub(crate) fn segment_bounds_unchecked( - segments: &[S], - start: usize, - end: usize, - bounds: impl Fn(&S) -> (usize, usize), -) -> Option { - if start == end { - None - } - else { - let start_segment = - find_segment(segments, start, true, &bounds).expect("Bug: Didn't find start segment"); - let start_offset = start - bounds(&segments[start_segment]).0; - - let end_segment = find_segment(&segments[start_segment..], end, false, &bounds) - .expect("Bug: Didn't find end segment") - + start_segment; - let end_offset = end - bounds(&segments[end_segment]).0; - - Some(SegmentBounds { - start_segment, - start_offset, - end_segment, - end_offset, - }) - } -} - -fn view_unchecked(segments: &[Segment], start: usize, end: usize) -> View<'_, B> { - let bounds = |segment: &Segment| (segment.offset, segment.offset + segment.buf.len()); - - if let Some(SegmentBounds { - start_segment, - start_offset, - end_segment, - end_offset, - }) = segment_bounds_unchecked(segments, start, end, bounds) - { - View { - segments: &segments[start_segment..=end_segment], - start_offset, - end_offset, - } - } - else { - View { - segments: &[], - start_offset: 0, - end_offset: 0, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::buf::BufExt; - - fn collect_chunks(buf: B) -> Vec> { - // uggh... fix this when we solved the BufReader lifetime issue. - let mut reader = buf.reader(); - let mut chunks = vec![]; - while let Some(chunk) = reader.peek_chunk() { - chunks.push(chunk.to_owned()); - reader.advance(chunk.len()).unwrap(); - } - chunks - } - - #[test] - #[ignore = "Not yet implemented"] - fn it_chunks_correctly() { - let input = vec![ - b"Hello" as &[u8], - b" " as &[u8], - b"World" as &[u8], - b"!" as &[u8], - ]; - - let rope = input.iter().collect::>(); - - assert_eq!(rope.segments[0].offset, 0); - assert_eq!(rope.segments[1].offset, 5); - assert_eq!(rope.segments[2].offset, 6); - assert_eq!(rope.segments[3].offset, 11); - - assert_eq!(input, collect_chunks(&rope)); - } - - #[test] - #[ignore = "Not yet implemented"] - fn it_views_correctly() { - let rope = [ - b"Hello" as &[u8], - b" " as &[u8], - b"World" as &[u8], - b"!" as &[u8], - ] - .iter() - .collect::>(); - - let view = rope.view(2..9).unwrap(); - assert_eq!(view.as_vec(), b"llo Wor"); - - let view = rope.view(5..9).unwrap(); - assert_eq!(view.as_vec(), b" Wor"); - - let view = rope.view(6..).unwrap(); - assert_eq!(view.as_vec(), b"World!"); - } - - #[test] - #[ignore = "Not yet implemented"] - fn it_chunks_corner_cases_correctly() { - let rope = [ - b"Hello" as &[u8], - b" " as &[u8], - b"World" as &[u8], - b"!" as &[u8], - ] - .iter() - .collect::>(); - - let view = rope.view(5..6).unwrap(); - let chunks = collect_chunks(view); - assert_eq!(chunks.len(), 1); - assert_eq!(chunks[0], b" "); - - let view = rope.view(5..11).unwrap(); - let chunks = collect_chunks(view); - assert_eq!(chunks.len(), 2); - assert_eq!(chunks[0], b" "); - assert_eq!(chunks[1], b"World"); - } - - #[test] - #[ignore = "Not yet implemented"] - fn it_views_views_correctly() { - let rope = [ - b"Hello" as &[u8], - b" " as &[u8], - b"World" as &[u8], - b"!" as &[u8], - ] - .iter() - .collect::>(); - - let view = rope.view(2..9).unwrap(); - let view2 = view.view(2..4).unwrap(); - assert_eq!(view2.as_vec(), b"o "); - - let view = rope.view(5..9).unwrap(); - let view2 = view.view(1..).unwrap(); - assert_eq!(view2.as_vec(), b"Wor"); - - let view = rope.view(6..).unwrap(); - let view2 = view.view(..5).unwrap(); - assert_eq!(view2.as_vec(), b"World"); - } - - #[test] - #[ignore = "Not yet implemented"] - fn len_is_correct() { - let rope = [ - b"Hello" as &[u8], - b" " as &[u8], - b"World" as &[u8], - b"!" as &[u8], - ] - .iter() - .collect::>(); - assert_eq!(rope.len(), 12); - - let rope = [b"" as &[u8], b"" as &[u8]].iter().collect::>(); - assert_eq!(rope.len(), 0); - assert!(rope.is_empty()); - } - - #[test] - #[ignore = "Not yet implemented"] - fn it_views_empty_ropes_correctly() { - let rope = Rope::<&'static [u8]>::new(); - assert!(rope.view(..).unwrap().is_empty()); - assert_eq!( - rope.view(..1).unwrap_err(), - RangeOutOfBounds { - required: Range::from(..1), - bounds: (0, 0) - } - ); - } -} diff --git a/byst/src/buf/slab.rs b/byst/src/buf/slab.rs deleted file mode 100644 index 0cac3ae..0000000 --- a/byst/src/buf/slab.rs +++ /dev/null @@ -1,236 +0,0 @@ -use crate::buf::arc_buf::{ - ArcBufMut, - Reclaim, -}; - -/// Efficient allocation of equally-sized buffers. -#[derive(Debug)] -pub struct Slab { - buf_size: usize, - reuse_count: usize, - in_use: Vec, - available: Vec<(Reclaim, ArcBufMut)>, -} - -impl Slab { - /// Creates a new slab allocator for buffers of size `buf_size`. - /// - /// The argument `reuse_count` controls how many buffers should be kept - /// around for reuse. If a buffer becomes available again, but the [`Slab`] - /// already has `reuse_count` available buffers, it will free the - /// newly-available buffer. - #[inline] - pub fn new(buf_size: usize, reuse_count: usize) -> Self { - Self { - buf_size, - reuse_count, - in_use: Vec::with_capacity(reuse_count * 2), - available: Vec::with_capacity(reuse_count), - } - } - - /// Returns a (mutable) buffer. - /// - /// This will either reuse a buffer, or allocate a new one. - /// - /// Once the returned [`BytesMut`] or all [`Bytes`] created from it are - /// dropped, the buffer will be reused by the [`Slab`]. - pub fn get(&mut self) -> ArcBufMut { - if self.buf_size == 0 { - return ArcBufMut::default(); - } - - if let Some((reclaim, buf)) = self.available.pop() { - // there's a buffer in `available` that we can use. - self.in_use.push(reclaim); - buf - } - else { - // try to find a buffer that is unused, but not yet in `available`. - - let mut i = 0; - let mut reclaimed = None; - - while i < self.in_use.len() { - let reclaim = &self.in_use[i]; - - if reclaimed.is_none() { - // try to reclaim unused buffer - - if let Some(buf) = reclaim.try_reclaim() { - reclaimed = Some(buf); - } - else { - i += 1; - } - } - else { - // get all other buffers that are reclaimable from `in_use` and put them into - // `available`, or drop them. - - if let Some(mut buf) = reclaim.try_reclaim() { - let reclaim = self.in_use.swap_remove(i); - if self.available.len() < self.reuse_count { - // put buffer into available list - buf.clear(); - self.available.push((reclaim, buf)); - } - } - else { - i += 1; - } - } - } - - if let Some(reclaimed) = reclaimed { - reclaimed - } - else { - // allocate new buffer - let (buf, reclaim) = ArcBufMut::new_reclaimable(self.buf_size); - self.in_use.push(reclaim); - buf - } - } - } - - /// Number of in-use buffers. - /// - /// This value might not be accurate, because the [`Slab`] only checks if - /// buffers became available again, if none are available during - /// [`Slab::get`]. Thus the actual number of in-use buffers might be lower. - #[inline] - pub fn num_in_use(&self) -> usize { - self.in_use.len() - } - - /// Number of available buffers. - /// - /// This value might not be accurate, because the [`Slab`] only checks if - /// buffers became available again, if none are available during - /// [`Slab::get`]. Thus the actual number of available buffers might be - /// higher. - #[inline] - pub fn num_available(&self) -> usize { - self.available.len() - } - - /// Total number of buffers managed by this [`Slab`] - #[inline] - pub fn num_total(&self) -> usize { - self.num_in_use() + self.num_available() - } - - /// Size of buffer this [`Slab`] allocates - #[inline] - pub fn buf_size(&self) -> usize { - self.buf_size - } - - /// The `reuse_count` with which this [`Slab`] was configured. See - /// [`Slab::new`]. - #[inline] - pub fn reuse_count(&self) -> usize { - self.reuse_count - } - - /// Change the `reuse_cunt`. See [`Slab::new`]. - #[inline] - pub fn set_reuse_count(&mut self, reuse_count: usize) { - self.reuse_count = reuse_count; - } -} - -#[cfg(test)] -mod tests { - use super::Slab; - use crate::{ - buf::{ - tests::buf_mut_tests, - BufExt, - Full, - }, - copy, - Buf, - RangeOutOfBounds, - }; - - buf_mut_tests!({ - let mut slab = Slab::new(128, 32); - slab.get() - }); - - #[test] - fn cant_read_more_than_written() { - let mut slab = Slab::new(128, 32); - - let mut bytes_mut = slab.get(); - copy(&mut bytes_mut, b"abcd").unwrap(); - - assert_eq!( - bytes_mut.view(0..8).unwrap_err(), - RangeOutOfBounds { - required: (0..8).into(), - bounds: (0, 4) - }, - ); - } - - #[test] - fn cant_write_more_than_buf_size() { - let mut slab = Slab::new(4, 32); - - let mut bytes_mut = slab.get(); - assert_eq!( - copy(&mut bytes_mut, b"abcdefgh").unwrap_err(), - Full { - required: 8, - capacity: 4 - } - ); - } - - #[test] - fn write_freeze_read() { - let mut slab = Slab::new(128, 32); - - let mut bytes_mut = slab.get(); - copy(&mut bytes_mut, b"abcd").unwrap(); - - let bytes = bytes_mut.freeze(); - assert_eq!(bytes.as_vec(), b"abcd"); - - let bytes2 = bytes.clone(); - assert_eq!(bytes2.as_vec(), b"abcd"); - } - - #[test] - fn it_reuses_buffers() { - let mut slab = Slab::new(128, 32); - assert_eq!(slab.num_in_use(), 0); - assert_eq!(slab.num_available(), 0); - - let bytes_mut = slab.get(); - //let buf_ptr = bytes_mut.inner.buf.0.buf; - assert_eq!(slab.num_in_use(), 1); - assert_eq!(slab.num_available(), 0); - - drop(bytes_mut); - let _bytes_mut = slab.get(); - //let buf2_ptr = bytes_mut.inner.buf.0.buf; - assert_eq!(slab.num_in_use(), 1); - assert_eq!(slab.num_available(), 0); - - //assert_eq!(buf_ptr, buf2_ptr); - } - - #[test] - fn it_doesnt_reuse_in_use_buffer() { - let mut slab = Slab::new(128, 32); - - let bytes_mut = slab.get(); - let bytes_mut2 = slab.get(); - assert_eq!(bytes_mut.ref_count().ref_count(), Some(1)); - assert_eq!(bytes_mut2.ref_count().ref_count(), Some(1)); - } -} diff --git a/byst/src/bytes/bytes.rs b/byst/src/bytes/bytes.rs deleted file mode 100644 index 16ba0c5..0000000 --- a/byst/src/bytes/bytes.rs +++ /dev/null @@ -1,182 +0,0 @@ -use std::fmt::Debug; - -use super::{ - r#impl::BytesImpl, - r#static::Static, - view::View, -}; -use crate::{ - buf::{ - Empty, - Length, - }, - impl_me, - io::{ - BufReader, - End, - Seek, - }, - util::{ - buf_eq, - cfg_pub, - debug_as_hexdump, - }, - Buf, - Range, - RangeOutOfBounds, -}; - -#[derive(Clone)] -pub struct Bytes { - inner: View<'static>, -} - -impl Bytes { - /// Creates an empty [`Bytes`]. - /// - /// This doesn't allocate. - #[inline] - pub fn new() -> Self { - // note: this really doesn't allocate, since [`Empty`] is a ZST, and a `dyn ZST` - // is ZST itself.[1] - // - // [1]: https://users.rust-lang.org/t/what-does-box-dyn-actually-allocate/56618/2 - Self::from_impl(Box::new(Empty)) - } - - cfg_pub! { - #[inline] - pub(#[cfg(feature = "bytes-impl")]) fn from_impl(inner: Box + 'static>) -> Self { - View::from_impl(inner).into() - } - } -} - -impl From> for Bytes { - #[inline] - fn from(inner: View<'static>) -> Self { - Self { inner } - } -} - -impl Default for Bytes { - /// Creates an empty [`Bytes`]. - /// - /// This doesn't allocate. - #[inline] - fn default() -> Self { - Self::new() - } -} - -impl Debug for Bytes { - #[inline] - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - debug_as_hexdump(f, self) - } -} - -impl PartialEq for Bytes { - #[inline] - fn eq(&self, other: &R) -> bool { - buf_eq(self, other) - } -} - -impl From<&'static [u8]> for Bytes { - #[inline] - fn from(value: &'static [u8]) -> Self { - Self::from_impl(Box::new(Static(value))) - } -} - -impl Buf for Bytes { - type View<'a> = Self - where - Self: 'a; - - type Reader<'a> = Self - where - Self: 'a; - - #[inline] - fn view(&self, range: impl Into) -> Result, RangeOutOfBounds> { - Ok(Buf::view(&self.inner, range.into())?.into()) - } - - #[inline] - fn reader(&self) -> Self::Reader<'_> { - self.clone() - } -} - -impl BufReader for Bytes { - type View = Self; - - #[inline] - fn peek_chunk(&self) -> Option<&[u8]> { - ::peek_chunk(&self.inner) - } - - #[inline] - fn view(&mut self, length: usize) -> Result { - Ok(Bytes::from(::view( - &mut self.inner, - length, - )?)) - } - - #[inline] - fn peek_view(&self, length: usize) -> Result { - Ok(Bytes::from(::peek_view( - &self.inner, - length, - )?)) - } - - #[inline] - fn rest(&mut self) -> Self::View { - Bytes::from(::rest(&mut self.inner)) - } - - #[inline] - fn peek_rest(&self) -> Self::View { - Bytes::from(::peek_rest(&self.inner)) - } - - #[inline] - fn advance(&mut self, by: usize) -> Result<(), End> { - ::advance(&mut self.inner, by) - } - - #[inline] - fn remaining(&self) -> usize { - ::remaining(&self.inner) - } -} - -impl Seek for Bytes { - type Position = Self; - - #[inline] - fn tell(&self) -> Self::Position { - Bytes::from(self.inner.tell()) - } - - #[inline] - fn seek(&mut self, position: &Self::Position) -> Self::Position { - Bytes::from(self.inner.seek(&position.inner)) - } -} - -impl Length for Bytes { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } -} - -impl_me! { - impl Reader for Bytes as BufReader; - impl Read<_, ()> for Bytes as BufReader::View; -} diff --git a/byst/src/bytes/bytes_mut.rs b/byst/src/bytes/bytes_mut.rs deleted file mode 100644 index c9f154a..0000000 --- a/byst/src/bytes/bytes_mut.rs +++ /dev/null @@ -1,131 +0,0 @@ -use std::fmt::Debug; - -use super::{ - r#impl::BytesMutImpl, - view::{ - View, - ViewMut, - ViewMutWriter, - }, -}; -use crate::{ - buf::{ - arc_buf::ArcBufMut, - Empty, - Full, - Length, - SizeLimit, - }, - util::{ - buf_eq, - cfg_pub, - debug_as_hexdump, - }, - Buf, - BufMut, - Range, - RangeOutOfBounds, -}; - -pub struct BytesMut { - inner: ViewMut<'static>, -} - -impl BytesMut { - cfg_pub! { - #[inline] - pub(#[cfg(feature = "bytes-impl")]) fn from_impl(inner: Box) -> Self { - Self { - inner: ViewMut::from_impl(inner), - } - } - } - - #[inline] - pub fn new() -> Self { - Self::from_impl(Box::new(Empty)) - } - - #[inline] - pub fn with_capacity(capacity: usize) -> Self { - Self::from_impl(Box::new(ArcBufMut::new(capacity))) - } -} - -impl Default for BytesMut { - #[inline] - fn default() -> Self { - Self::new() - } -} - -impl Debug for BytesMut { - #[inline] - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - debug_as_hexdump(f, self) - } -} - -impl PartialEq for BytesMut { - #[inline] - fn eq(&self, other: &R) -> bool { - buf_eq(self, other) - } -} - -impl Length for BytesMut { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } -} - -impl Buf for BytesMut { - type View<'a> = View<'a> - where - Self: 'a; - - type Reader<'a> = View<'a> - where - Self: 'a; - - #[inline] - fn view(&self, range: impl Into) -> Result, RangeOutOfBounds> { - self.inner.view(range.into()) - } - - #[inline] - fn reader(&self) -> Self::Reader<'_> { - self.inner.reader() - } -} - -impl BufMut for BytesMut { - type ViewMut<'a> = ViewMut<'a> - where - Self: 'a; - - type Writer<'a> = ViewMutWriter<'a> - where - Self: 'a; - - #[inline] - fn view_mut(&mut self, range: impl Into) -> Result, RangeOutOfBounds> { - self.inner.view_mut(range) - } - - #[inline] - fn writer(&mut self) -> Self::Writer<'_> { - self.inner.writer() - } - - #[inline] - fn reserve(&mut self, size: usize) -> Result<(), Full> { - self.inner.reserve(size) - } - - #[inline] - fn size_limit(&self) -> SizeLimit { - self.inner.size_limit() - } -} diff --git a/byst/src/bytes/impl.rs b/byst/src/bytes/impl.rs deleted file mode 100644 index 4229344..0000000 --- a/byst/src/bytes/impl.rs +++ /dev/null @@ -1,128 +0,0 @@ -#![allow(dead_code)] - -use crate::{ - buf::{ - Full, - Length, - SizeLimit, - }, - io::{BufReader, BufWriter, End}, - Buf, - BufMut, - IndexOutOfBounds, - Range, - RangeOutOfBounds, -}; - -/// The trait backing the [`Bytes`] implementation. -/// -/// Implement this for your type, for it to be usable as a [`Bytes`]. Use -/// [`Bytes::from_impl`] to implement a conversion from your type to [`Bytes`]. -/// -/// [`Bytes`]: super::Bytes -/// [`Bytes::from_impl`]: super::Bytes::from_impl -pub trait BytesImpl<'b>: Length + Send + Sync { - fn clone(&self) -> Box + 'b>; - fn peek_chunk(&self) -> Option<&[u8]>; - fn view(&self, range: Range) -> Result + 'b>, RangeOutOfBounds>; - fn advance(&mut self, by: usize) -> Result<(), End>; -} - -/// The trait backing the [`BytesMut`] implementation. -/// -/// Implement this for your type, for it to be usable as a [`BytesMut`]. Use -/// [`BytesMut::from_impl`] to implement a conversion from your type to -/// [`BytesMut`]. -/// -/// [`BytesMut`]: super::BytesMut -/// [`BytesMut::from_impl`]: super::BytesMut::from_impl -pub trait BytesMutImpl: Length + Send + Sync { - fn view(&self, range: Range) -> Result + '_>, RangeOutOfBounds>; - fn view_mut(&mut self, range: Range) -> Result, RangeOutOfBounds>; - fn reader(&self) -> Box + '_>; - fn writer(&mut self) -> Box; - fn reserve(&mut self, size: usize) -> Result<(), Full>; - fn size_limit(&self) -> SizeLimit; - fn split_at( - &mut self, - at: usize, - ) -> Result, IndexOutOfBounds>; -} - -pub trait WriterImpl { - fn peek_chunk_mut(&mut self) -> Option<&mut [u8]>; - fn advance(&mut self, by: usize) -> Result<(), crate::io::Full>; - fn remaining(&self) -> usize; - fn extend(&mut self, with: &[u8]) -> Result<(), crate::io::Full>; -} - -impl<'b> BytesImpl<'b> for &'b [u8] { - fn view(&self, range: Range) -> Result + 'b>, RangeOutOfBounds> { - Ok(Box::new(Buf::view(self, range)?)) - } - - fn clone(&self) -> Box + 'b> { - Box::new(*self) - } - - fn peek_chunk(&self) -> Option<&[u8]> { - BufReader::peek_chunk(self) - } - - fn advance(&mut self, by: usize) -> Result<(), End> { - BufReader::advance(self, by) - } -} - -impl<'b> BytesMutImpl for &'b mut [u8] { - fn view(&self, range: Range) -> Result, RangeOutOfBounds> { - Ok(Box::new(Buf::view(self, range)?)) - } - - fn view_mut(&mut self, range: Range) -> Result, RangeOutOfBounds> { - Ok(Box::new(BufMut::view_mut(self, range)?)) - } - - fn reader(&self) -> Box + '_> { - Box::new(&**self) - } - - fn writer(&mut self) -> Box { - Box::new(&mut **self) - } - - fn reserve(&mut self, size: usize) -> Result<(), Full> { - BufMut::reserve(self, size) - } - - fn size_limit(&self) -> SizeLimit { - BufMut::size_limit(self) - } - - fn split_at( - &mut self, - at: usize, - ) -> Result, IndexOutOfBounds> { - let (left, right) = <[u8]>::split_at_mut(std::mem::take(self), at); - *self = right; - Ok(Box::new(left)) - } -} - -impl<'b> WriterImpl for &'b mut [u8] { - fn peek_chunk_mut(&mut self) -> Option<&mut [u8]> { - BufWriter::peek_chunk_mut(self) - } - - fn advance(&mut self, by: usize) -> Result<(), crate::io::Full> { - BufWriter::advance(self, by) - } - - fn remaining(&self) -> usize { - <[u8]>::len(self) - } - - fn extend(&mut self, with: &[u8]) -> Result<(), crate::io::Full> { - BufWriter::extend(self, with) - } -} diff --git a/byst/src/bytes/mod.rs b/byst/src/bytes/mod.rs deleted file mode 100644 index 978fe9d..0000000 --- a/byst/src/bytes/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -#[allow(clippy::module_inception)] -pub mod bytes; -pub mod bytes_mut; -//mod spilled; -mod r#static; -pub mod view; - -cfg_pub! { - pub(#[cfg(feature = "bytes-impl")]) mod r#impl; -} - -pub use self::{ - bytes::Bytes, - bytes_mut::BytesMut, -}; -use crate::util::cfg_pub; diff --git a/byst/src/bytes/spilled.rs b/byst/src/bytes/spilled.rs deleted file mode 100644 index bdeb20d..0000000 --- a/byst/src/bytes/spilled.rs +++ /dev/null @@ -1,44 +0,0 @@ -#![allow(unused_variables, dead_code)] - -use std::sync::Arc; - -use super::r#impl::BytesMutImpl; -use crate::buf::{ - chunks::WithOffset, - Length, -}; - -struct Segment<'b> { - start: usize, - end: usize, - buf: Box>, -} - -struct Spilled<'b> { - inner: Arc>>, -} - -impl<'b> FromIterator>> for Spilled<'b> { - #[inline] - fn from_iter>>>(iter: T) -> Self { - Self { - inner: Arc::new( - WithOffset::new(iter.into_iter()) - .map(|(offset, buf)| { - Segment { - start: offset, - end: offset + buf.len(), - buf, - } - }) - .collect(), - ), - } - } -} - -impl<'b> Length for Spilled<'b> { - fn len(&self) -> usize { - self.inner.last().map(|last| last.end).unwrap_or_default() - } -} diff --git a/byst/src/bytes/static.rs b/byst/src/bytes/static.rs deleted file mode 100644 index 2a0bf68..0000000 --- a/byst/src/bytes/static.rs +++ /dev/null @@ -1,41 +0,0 @@ -use super::r#impl::BytesImpl; -use crate::{ - buf::Length, - io::{ - BufReader, - End, - }, - Buf, - Range, - RangeOutOfBounds, -}; - -#[derive(Clone, Copy)] -pub struct Static(pub &'static [u8]); - -impl Length for Static { - #[inline] - fn len(&self) -> usize { - self.0.len() - } -} - -impl<'b> BytesImpl<'b> for Static { - #[inline] - fn clone(&self) -> Box + 'b> { - Box::new(*self) - } - - fn peek_chunk(&self) -> Option<&[u8]> { - BufReader::peek_chunk(&self.0) - } - - #[inline] - fn view(&self, range: Range) -> Result + 'b>, RangeOutOfBounds> { - Ok(Box::new(Buf::view(&self.0, range)?)) - } - - fn advance(&mut self, by: usize) -> Result<(), End> { - BufReader::advance(&mut self.0, by) - } -} diff --git a/byst/src/bytes/view.rs b/byst/src/bytes/view.rs deleted file mode 100644 index 329edc3..0000000 --- a/byst/src/bytes/view.rs +++ /dev/null @@ -1,303 +0,0 @@ -use std::fmt::Debug; - -use super::r#impl::{ - BytesImpl, - BytesMutImpl, - WriterImpl, -}; -use crate::{ - buf::{ - Empty, - Full, - Length, - SizeLimit, - }, - impl_me, - io::{ - BufReader, - BufWriter, - End, - Seek, - }, - util::{ - buf_eq, - cfg_pub, - debug_as_hexdump, - }, - Buf, - BufMut, - Range, - RangeOutOfBounds, -}; - -pub struct View<'b> { - inner: Box + 'b>, -} - -impl<'b> View<'b> { - cfg_pub! { - #[inline] - pub(#[cfg(feature = "bytes-impl")]) fn from_impl(inner: Box + 'b>) -> Self { - Self { inner } - } - } -} - -impl<'b> Default for View<'b> { - fn default() -> Self { - Self::from_impl(Box::new(Empty)) - } -} - -impl<'b> Clone for View<'b> { - #[inline] - fn clone(&self) -> Self { - Self::from_impl(self.inner.clone()) - } -} - -impl<'b> Debug for View<'b> { - #[inline] - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - debug_as_hexdump(f, self) - } -} - -impl<'b, R: Buf> PartialEq for View<'b> { - #[inline] - fn eq(&self, other: &R) -> bool { - buf_eq(self, other) - } -} - -impl<'b> Length for View<'b> { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } -} - -impl<'b> Buf for View<'b> { - type View<'a> = Self - where - Self: 'a; - - type Reader<'a> = Self - where - Self: 'a; - - #[inline] - fn view(&self, range: impl Into) -> Result, RangeOutOfBounds> { - Ok(View::from_impl(self.inner.view(range.into())?)) - } - - #[inline] - fn reader(&self) -> Self::Reader<'_> { - self.clone() - } -} - -impl<'b> BufReader for View<'b> { - type View = Self; - - #[inline] - fn peek_chunk(&self) -> Option<&[u8]> { - self.inner.peek_chunk() - } - - #[inline] - fn view(&mut self, length: usize) -> Result { - let view = self.peek_view(length)?; - self.inner - .advance(length) - .unwrap_or_else(|_| unreachable!()); - Ok(view) - } - - #[inline] - fn peek_view(&self, length: usize) -> Result { - Buf::view(self, Range::default().with_start(0).with_length(length)).map_err(|_| { - End { - read: 0, - requested: length, - remaining: self.inner.len(), - } - }) - } - - #[inline] - fn rest(&mut self) -> Self::View { - std::mem::take(self) - } - - #[inline] - fn peek_rest(&self) -> Self::View { - self.clone() - } - - #[inline] - fn advance(&mut self, by: usize) -> Result<(), End> { - self.inner.advance(by) - } - - #[inline] - fn remaining(&self) -> usize { - self.inner.len() - } -} - -impl<'b> Seek for View<'b> { - type Position = View<'b>; - - #[inline] - fn tell(&self) -> Self::Position { - self.clone() - } - - #[inline] - fn seek(&mut self, position: &Self::Position) -> Self::Position { - std::mem::replace(self, position.clone()) - } -} - -pub struct ViewMut<'b> { - inner: Box, -} - -impl<'b> ViewMut<'b> { - cfg_pub! { - #[inline] - pub(#[cfg(feature = "bytes-impl")]) fn from_impl(inner: Box) -> Self { - Self { inner } - } - } -} - -impl<'b> Debug for ViewMut<'b> { - #[inline] - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - debug_as_hexdump(f, self) - } -} - -impl<'b, R: Buf> PartialEq for ViewMut<'b> { - #[inline] - fn eq(&self, other: &R) -> bool { - buf_eq(self, other) - } -} - -impl<'b> Length for ViewMut<'b> { - #[inline] - fn len(&self) -> usize { - self.inner.len() - } -} - -impl<'b> Buf for ViewMut<'b> { - type View<'a> = View<'a> - where - Self: 'a; - - type Reader<'a> = View<'a> - where - Self: 'a; - - #[inline] - fn view(&self, range: impl Into) -> Result, RangeOutOfBounds> { - Ok(View::from_impl(self.inner.view(range.into())?)) - } - - #[inline] - fn reader(&self) -> Self::Reader<'_> { - View::from_impl(self.inner.reader()) - } -} - -impl<'b> BufMut for ViewMut<'b> { - type ViewMut<'a> = ViewMut<'a> - where - Self: 'a; - - type Writer<'a> = ViewMutWriter<'a> - where - Self: 'a; - - #[inline] - fn view_mut(&mut self, range: impl Into) -> Result, RangeOutOfBounds> { - Ok(ViewMut::from_impl(self.inner.view_mut(range.into())?)) - } - - #[inline] - fn writer(&mut self) -> Self::Writer<'_> { - ViewMutWriter::from_impl(self.inner.writer()) - } - - #[inline] - fn reserve(&mut self, size: usize) -> Result<(), Full> { - self.inner.reserve(size) - } - - #[inline] - fn size_limit(&self) -> SizeLimit { - self.inner.size_limit() - } -} - -pub struct ViewMutWriter<'b> { - inner: Box, -} - -impl<'b> ViewMutWriter<'b> { - cfg_pub! { - #[inline] - pub(#[cfg(feature = "bytes-impl")]) fn from_impl(inner: Box) -> Self { - Self { inner } - } - } -} - -impl<'b> BufWriter for ViewMutWriter<'b> { - type ViewMut<'a> = ViewMut<'a> where Self: 'a; - - fn peek_chunk_mut(&mut self) -> Option<&mut [u8]> { - self.inner.peek_chunk_mut() - } - - fn view_mut(&mut self, _length: usize) -> Result, crate::io::Full> { - todo!(); - } - - #[inline] - fn peek_view_mut(&mut self, _length: usize) -> Result, crate::io::Full> { - todo!(); - } - - #[inline] - fn rest_mut(&mut self) -> Self::ViewMut<'_> { - todo!(); - } - - #[inline] - fn peek_rest_mut(&mut self) -> Self::ViewMut<'_> { - todo!(); - } - - fn advance(&mut self, by: usize) -> Result<(), crate::io::Full> { - self.inner.advance(by) - } - - fn remaining(&self) -> usize { - self.inner.remaining() - } - - fn extend(&mut self, with: &[u8]) -> Result<(), crate::io::Full> { - self.inner.extend(with) - } -} - -impl_me! { - impl['a] Reader for View<'a> as BufReader; - impl['a] Read<_, ()> for View<'a> as BufReader::View; - impl['a] Writer for ViewMutWriter<'a> as BufWriter; -} diff --git a/byst/src/copy.rs b/byst/src/copy.rs deleted file mode 100644 index a27a694..0000000 --- a/byst/src/copy.rs +++ /dev/null @@ -1,230 +0,0 @@ -use std::cmp::Ordering; - -use crate::{ - buf::{ - Buf, - BufMut, - Full, - }, - io::{ - BufReader, - BufWriter, - }, - Range, - RangeOutOfBounds, -}; - -/// Copies bytes from `source` to `destination`. -pub fn copy(mut destination: impl BufMut, source: impl Buf) -> Result<(), Full> { - let source_len = source.len(); - destination.reserve(source_len)?; - - let writer = destination.writer(); - let reader = source.reader(); - - let total_copied = copy_io(writer, reader, None); - - match total_copied.cmp(&source_len) { - Ordering::Equal => {} - Ordering::Less => { - panic!("Reserved {source_len} bytes, but only {total_copied} bytes could be written."); - } - Ordering::Greater => { - panic!("Copied buffer with length {source_len}, but {total_copied} bytes were copied."); - } - } - - Ok(()) -} - -/// Error while copying from a [`Buf`] to a [`BufMut`]. -#[derive(Debug, PartialEq, Eq, thiserror::Error)] -#[error("Copy error")] -pub enum CopyRangeError { - #[error("Source index out of bounds")] - SourceRangeOutOfBounds(RangeOutOfBounds), - - LengthMismatch(#[from] LengthMismatch), - - DestinationFull(#[source] Full), -} - -#[derive(Debug, PartialEq, Eq, thiserror::Error)] -#[error("Length mismatch: destination ({destination_length}) != source ({source_length})")] -pub struct LengthMismatch { - pub destination_range: Range, - pub destination_length: usize, - pub source_range: Range, - pub source_length: usize, -} - -/// Copies bytes from `source` to `destination` with respective ranges. -pub fn copy_range( - mut destination: impl BufMut, - destination_range: impl Into, - source: impl Buf, - source_range: impl Into, -) -> Result<(), CopyRangeError> { - let destination_range: Range = destination_range.into(); - let source_range: Range = source_range.into(); - - let destination_start = destination_range.start.unwrap_or_default(); - let source_start = source_range.start.unwrap_or_default(); - let source_end = if let Some(end) = source_range.end { - if end > source.len() { - return Err(CopyRangeError::SourceRangeOutOfBounds(RangeOutOfBounds { - required: source_range, - bounds: (0, source.len()), - })); - } - end - } - else { - source.len() - }; - let source_length = source_end - source_start; - let destination_end = destination_range - .end - .unwrap_or_else(|| destination_start + source_length); - let destination_length = destination_end - destination_start; - - if destination_length != source_length { - return Err(LengthMismatch { - destination_range, - destination_length, - source_range, - source_length, - } - .into()); - } - - let mut destination_writer = destination.writer(); - if destination_start != 0 { - destination_writer - .advance(destination_start) - .map_err(|e| CopyRangeError::DestinationFull(e.into()))?; - } - - let mut source_reader = source.reader(); - if source_start != 0 { - source_reader - .advance(source_start) - .expect("Advancing the source reader to {source_start} unexpectedly failed."); - } - - let total_copied = copy_io(destination_writer, source_reader, source_length); - - assert_eq!( - total_copied, source_length, - "Expected to copy {source_length} bytes, but copied {total_copied}." - ); - - Ok(()) -} - -/// Copies `amount` bytes from `source` to `destination`. -pub fn copy_io( - mut destination: impl BufWriter, - mut source: impl BufReader, - amount: impl Into>, -) -> usize { - let mut amount = amount.into(); - let mut total_copied = 0; - - while amount.map_or(true, |n| n > 0) { - match (destination.peek_chunk_mut(), source.peek_chunk()) { - (Some(dest_chunk), Some(src_chunk)) => { - let mut n = std::cmp::min(dest_chunk.len(), src_chunk.len()); - if let Some(amount) = &mut amount { - n = std::cmp::min(n, *amount); - *amount -= n; - } - - dest_chunk[..n].copy_from_slice(&src_chunk[..n]); - - total_copied += n; - - destination - .advance(n) - .expect("Expected at least {n} more bytes in BufWriter"); - source - .advance(n) - .expect("Expected at least {n} more bytes in BufReader"); - } - (None, Some(src_chunk)) => { - if let Err(crate::io::Full { written, .. }) = destination.extend(src_chunk) { - // todo: we could try to fill any remaining bytes in the destination. - total_copied += written; - break; - } - - total_copied += src_chunk.len(); - source - .advance(src_chunk.len()) - .expect("Expected at least {n} more bytes in BufReader"); - } - (_, None) => break, - } - } - - total_copied -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn fails_if_source_longer_than_destination() { - let mut destination = [0; 4]; - let source = [1; 16]; - - match copy(&mut destination, source) { - Ok(_) => panic!("copy didn't fail"), - Err(Full { - required, - capacity: buf_length, - }) => { - assert_eq!(required, 16); - assert_eq!(buf_length, 4); - } - } - } - - #[test] - fn it_copies() { - let mut destination = [42; 16]; - let mut source = [0; 16]; - for i in 0..16 { - source[i] = i as u8; - } - let expected = source; - - match copy(&mut destination, source) { - Err(e) => panic!("copy failed: {e:?}"), - Ok(()) => { - assert_eq!(expected, destination); - } - } - } - - #[test] - fn it_copies_io() { - let mut destination: [u8; 8] = [42; 8]; - let source: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; - - let total_copied = copy_io(destination.as_mut(), &mut source.as_ref(), None); - assert_eq!(total_copied, 8); - assert_eq!(source, destination); - } - - #[test] - fn it_copies_partial() { - let mut destination: [u8; 8] = [42; 8]; - let source: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; - - let total_copied = copy_io(destination.as_mut(), &mut source.as_ref(), Some(4)); - assert_eq!(total_copied, 4); - assert_eq!([1, 2, 3, 4, 42, 42, 42, 42], destination); - } -} diff --git a/byst/src/endianness.rs b/byst/src/endianness.rs deleted file mode 100644 index 7c13394..0000000 --- a/byst/src/endianness.rs +++ /dev/null @@ -1,252 +0,0 @@ -//! [Endianness](https://en.wikipedia.org/wiki/Endianness) -//! -//! # TODO -//! -//! - Remove `Size`, `Encode` and `Decode` traits as they require unstable -//! features, and we don't really need them. - -use crate::io::{ - Read, - Reader, - ReaderExt, - Write, - Writer, -}; - -mod sealed { - pub trait Sealed {} -} - -/// Trait for types that represent endianesses. -/// -/// This trait is sealed and can't be implemented for custom types. It is only -/// implemented for [`BigEndian`], [`LittleEndian`] and [`NativeEndian`] (and -/// the type alias [`NetworkEndian`]). -pub trait Endianness: sealed::Sealed {} - -/// Big endian byte order -#[derive(Clone, Copy, Debug, Default)] -pub struct BigEndian; -impl Endianness for BigEndian {} -impl sealed::Sealed for BigEndian {} - -/// Little endian byte order -#[derive(Clone, Copy, Debug, Default)] -pub struct LittleEndian; -impl Endianness for LittleEndian {} -impl sealed::Sealed for LittleEndian {} - -/// System native byte order. -/// -/// # Notes -/// -/// > Why is this not a type alias to either [`BigEndian`] or [`LittleEndian`]? -/// -/// Some implementations might depend on knowing at compile time whether -/// something is native endian, but also not generate different code depending -/// on system endianness. This is the case for reading slices like `&[u32]` from -/// a byte buffer, which is only possible in native endian. With a type alias -/// such a read implementation would either be for [`BigEndian`] or -/// [`LittleEndian`], and thus code that compiles fine on a [`LittleEndian`] -/// system, might not compile no a [`BigEndian`] system. -#[derive(Clone, Copy, Debug, Default)] -pub struct NativeEndian; -impl Endianness for NativeEndian {} -impl sealed::Sealed for NativeEndian {} - -/// Network byte order. -/// -/// This is always big endian. -pub use self::BigEndian as NetworkEndian; - -/// Trait defining what length in bytes. -pub trait Size { - const BYTES: usize; - const BITS: usize; -} - -/// Trait for types that can be encoded using a specified endianness. -pub trait Encode: Size { - fn encode(&self) -> [u8; ::BYTES]; -} - -/// Trait for types that can be decoded using a specified endianness. -pub trait Decode: Size { - fn decode(bytes: &[u8; ::BYTES]) -> Self; -} - -// this implements `Encode` and `Decode` for integer (and float) types from -// [`core`]. -macro_rules! impl_endianness { - { - $( - $ty:ty : $bytes:expr; - )* - } => { - $( - impl Size for $ty { - const BYTES: usize = $bytes; - const BITS: usize = $bytes * 8; - } - - impl_endianness!(for $ty: $bytes => from_be_bytes, to_be_bytes); - impl_endianness!(for $ty: $bytes => from_le_bytes, to_le_bytes); - - #[cfg(target_endian = "little")] - const _: () = { - impl_endianness!(for $ty: $bytes => from_le_bytes, to_le_bytes); - }; - - #[cfg(target_endian = "big")] - const _: () = { - impl_endianness!(for $ty: $bytes => from_be_bytes, to_be_bytes); - }; - )* - }; - (for<$endianness:ty> $ty:ty: $bytes:expr => $from_bytes:ident, $to_bytes:ident) => { - impl Encode<$endianness> for $ty { - #[inline] - fn encode(&self) -> [u8; $bytes] { - <$ty>::$to_bytes(*self) - } - } - - impl Decode<$endianness> for $ty { - #[inline] - fn decode(bytes: &[u8; $bytes]) -> Self { - <$ty>::$from_bytes(*bytes) - } - } - - impl Read for $ty { - type Error = ::Error; - - #[inline] - fn read(reader: &mut R, _context: $endianness) -> Result { - Ok(<$ty>::$from_bytes(reader.read_byte_array()?)) - } - } - - impl Write for $ty { - type Error = ::Error; - - #[inline] - fn write(&self, writer: &mut W, _context: $endianness) -> Result<(), Self::Error> { - let buf = <$ty>::$to_bytes(*self); - writer.write_buf(&buf) - } - } - }; -} - -impl_endianness! { - u16: 2; - i16: 2; - u32: 4; - i32: 4; - u64: 8; - i64: 8; - u128: 16; - i128: 16; - f32: 4; - f64: 8; -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::hexdump::Hexdump; - - macro_rules! make_tests { - { - $( - $name:ident : $ty:ty => { $value:expr } == { $be:expr, $le:expr }; - )* - } => { - $( - #[test] - fn $name() { - let got = <$ty as Encode::>::encode(&$value); - if got != *$be { - panic!( - r#"encoding big endian: - -expected: -{} - -got: -{}"#, - Hexdump::new($be), - Hexdump::new(&got), - ) - } - - let got = <$ty as Encode::>::encode(&$value); - if got != *$le { - panic!( - r#"encoding little endian: - -expected: -{} - -got: -{}"#, - Hexdump::new($le), - Hexdump::new(&got), - ) - } - - let got = <$ty as Decode::>::decode($be); - let expected: $ty = $value; - if got != expected { - panic!( - r#"decoding big endian: -expected: {:?} -got: {:?}"#, - expected, - got, - ) - } - - let got = <$ty as Decode::>::decode($le); - let expected: $ty = $value; - if got != expected { - panic!( - r#"decoding little endian: -expected: {:?} -got: {:?}"#, - expected, - got, - ) - } - } - )* - }; - } - - make_tests! { - test_u16 : u16 => { 0x1234 } == { b"\x12\x34", b"\x34\x12" }; - test_i16 : i16 => { 0x1234 } == { b"\x12\x34", b"\x34\x12" }; - - test_u32 : u32 => { 0x12345678 } == { b"\x12\x34\x56\x78", b"\x78\x56\x34\x12" }; - test_i32 : i32 => { 0x12345678 } == { b"\x12\x34\x56\x78", b"\x78\x56\x34\x12" }; - - test_u64 : u64 => { 0x123456789abcdef0 } == { - b"\x12\x34\x56\x78\x9a\xbc\xde\xf0", - b"\xf0\xde\xbc\x9a\x78\x56\x34\x12" - }; - test_i64 : i64 => { 0x123456789abcdef0 } == { - b"\x12\x34\x56\x78\x9a\xbc\xde\xf0", - b"\xf0\xde\xbc\x9a\x78\x56\x34\x12" - }; - - test_u128 : u128 => { 0x123456789abcdef00fedcba987654321 } == { - b"\x12\x34\x56\x78\x9a\xbc\xde\xf0\x0f\xed\xcb\xa9\x87\x65\x43\x21", - b"\x21\x43\x65\x87\xa9\xcb\xed\x0f\xf0\xde\xbc\x9a\x78\x56\x34\x12" - }; - test_i128 : i128 => { 0x123456789abcdef00fedcba987654321 } == { - b"\x12\x34\x56\x78\x9a\xbc\xde\xf0\x0f\xed\xcb\xa9\x87\x65\x43\x21", - b"\x21\x43\x65\x87\xa9\xcb\xed\x0f\xf0\xde\xbc\x9a\x78\x56\x34\x12" - }; - } -} diff --git a/byst/src/hexdump.rs b/byst/src/hexdump.rs deleted file mode 100644 index 8d546d5..0000000 --- a/byst/src/hexdump.rs +++ /dev/null @@ -1,224 +0,0 @@ -use std::fmt::{ - Debug, - Display, - Write as _, -}; - -use super::buf::Buf; -use crate::{ - copy_io, - BufMut, -}; - -#[inline] -pub fn hexdump(buf: B) -> Hexdump { - Hexdump::new(buf) -} - -pub struct Hexdump { - buf: B, - config: Config, -} - -impl Hexdump { - #[inline] - pub fn new(buf: B) -> Self { - Self::with_config(buf, Default::default()) - } - - #[inline] - pub fn with_config(buf: B, config: Config) -> Self { - Self { buf, config } - } -} - -impl Display for Hexdump { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut lines = Lines::new(&self.buf, &self.config); - - if self.config.header { - writeln!(f, "Hexdump: {} bytes", self.buf.len())?; - } - - if let Some(line) = lines.next() { - write!(f, "{line}")?; - } - - for line in lines { - write!(f, "\n{line}")?; - } - - if self.config.trailing_newline { - writeln!(f)?; - } - - Ok(()) - } -} - -impl Debug for Hexdump { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let hex = Hexdump { - buf: &self.buf, - config: Config { - offset: self.config.offset, - trailing_newline: false, - at_least_one_line: false, - header: false, - }, - }; - Display::fmt(&hex, f)?; - Ok(()) - } -} - -#[derive(Clone, Copy, Debug)] -pub struct Config { - pub offset: usize, - pub trailing_newline: bool, - pub at_least_one_line: bool, - pub header: bool, -} - -impl Default for Config { - fn default() -> Self { - Self { - offset: 0, - trailing_newline: true, - at_least_one_line: true, - header: true, - } - } -} - -pub struct Lines<'b, B: Buf + 'b> { - reader: B::Reader<'b>, - pad_offset_to: usize, - offset: usize, - remaining: usize, - emit_empty_line: bool, -} - -impl<'b, B: Buf> Lines<'b, B> { - pub fn new(buf: &'b B, config: &Config) -> Self { - let pad_offset_to = std::cmp::max(num_hex_digits(config.offset + buf.len()), 4); - Self { - reader: buf.reader(), - pad_offset_to, - offset: config.offset, - remaining: buf.len(), - emit_empty_line: config.at_least_one_line, - } - } -} - -impl<'b, B: Buf> Iterator for Lines<'b, B> { - type Item = Line; - - fn next(&mut self) -> Option { - (self.remaining > 0 || self.emit_empty_line).then(|| { - self.emit_empty_line = false; - - let mut line = [0; 16]; - let num_bytes = copy_io(line.writer(), &mut self.reader, 16); - - let offset = self.offset; - self.offset += num_bytes; - self.remaining -= num_bytes; - - Line { - line, - num_bytes, - offset, - pad_offset_to: self.pad_offset_to, - } - }) - } -} - -pub struct Line { - pub line: [u8; 16], - pub num_bytes: usize, - pub offset: usize, - pub pad_offset_to: usize, -} - -impl Display for Line { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // print offset - for _ in 0..(self.pad_offset_to - num_hex_digits(self.offset)) { - write!(f, "0")?; - } - write!(f, "{:x} ", self.offset)?; - - if !self.line.is_empty() { - // print bytes - for b in &self.line[0..self.num_bytes] { - write!(f, " {b:02x}")?; - } - - // pad bytes - for _ in self.num_bytes..16 { - write!(f, " ")?; - } - write!(f, " ")?; - - // print chars - for b in &self.line[0..self.num_bytes] { - if b.is_ascii() && !b.is_ascii_control() { - f.write_char((*b).into())?; - } - else { - write!(f, ".")?; - } - } - } - - Ok(()) - } -} - -fn num_hex_digits(mut num: usize) -> usize { - if num == 0 { - 1 - } - else { - let mut d = 0usize; - while num != 0 { - d += 1; - num >>= 4; - } - d - } -} - -#[cfg(test)] -mod tests { - use super::Hexdump; - - #[test] - fn test_display() { - let data = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."; - let formatted = Hexdump::new(&data).to_string(); - let expected = r#"Hexdump: 123 bytes -0000 4c 6f 72 65 6d 20 69 70 73 75 6d 20 64 6f 6c 6f Lorem ipsum dolo -0010 72 20 73 69 74 20 61 6d 65 74 2c 20 63 6f 6e 73 r sit amet, cons -0020 65 63 74 65 74 75 72 20 61 64 69 70 69 73 63 69 ectetur adipisci -0030 6e 67 20 65 6c 69 74 2c 20 73 65 64 20 64 6f 20 ng elit, sed do -0040 65 69 75 73 6d 6f 64 20 74 65 6d 70 6f 72 20 69 eiusmod tempor i -0050 6e 63 69 64 69 64 75 6e 74 20 75 74 20 6c 61 62 ncididunt ut lab -0060 6f 72 65 20 65 74 20 64 6f 6c 6f 72 65 20 6d 61 ore et dolore ma -0070 67 6e 61 20 61 6c 69 71 75 61 2e gna aliqua. -"#; - if expected != formatted { - panic!( - r#"expected: -{expected} - -got: -{formatted} -"# - ); - } - } -} diff --git a/byst/src/io/count.rs b/byst/src/io/count.rs deleted file mode 100644 index a289599..0000000 --- a/byst/src/io/count.rs +++ /dev/null @@ -1,155 +0,0 @@ -use super::{ - read::ReadError, - BufReader, - End, - Reader, - Seek, -}; -use crate::buf::{ - BufMut, - Length, -}; - -#[derive(Clone, Debug)] -pub struct Count { - inner: R, - count: usize, -} - -impl Count { - #[inline] - pub fn new(inner: R) -> Self { - Self { inner, count: 0 } - } - - #[inline] - pub fn count(&self) -> usize { - self.count - } - - #[inline] - pub fn into_inner(self) -> R { - self.inner - } -} - -impl From for Count { - #[inline] - fn from(value: R) -> Self { - Self::new(value) - } -} - -impl Reader for Count { - type Error = ::Error; - - fn read_into( - &mut self, - dest: D, - limit: impl Into>, - ) -> Result { - match self.inner.read_into(dest, limit) { - Ok(n_read) => { - self.count += n_read; - Ok(n_read) - } - Err(e) => { - self.count += e.amount_read(); - Err(e) - } - } - } - - fn read_into_exact(&mut self, dest: D, length: usize) -> Result<(), Self::Error> { - match self.inner.read_into_exact(dest, length) { - Ok(()) => { - self.count += length; - Ok(()) - } - Err(e) => { - self.count += e.amount_read(); - Err(e) - } - } - } - - fn skip(&mut self, amount: usize) -> Result<(), Self::Error> { - match Reader::skip(&mut self.inner, amount) { - Ok(()) => { - self.count += amount; - Ok(()) - } - Err(e) => { - self.count += e.amount_read(); - Err(e) - } - } - } -} - -impl BufReader for Count { - type View = R::View; - - #[inline] - fn peek_chunk(&self) -> Option<&[u8]> { - self.inner.peek_chunk() - } - - #[inline] - fn view(&mut self, length: usize) -> Result { - let view = self.inner.view(length)?; - self.count += view.len(); - Ok(view) - } - - #[inline] - fn peek_view(&self, length: usize) -> Result { - self.inner.peek_view(length) - } - - #[inline] - fn rest(&mut self) -> Self::View { - let view = self.inner.rest(); - self.count += view.len(); - view - } - - #[inline] - fn peek_rest(&self) -> Self::View { - self.inner.peek_rest() - } - - #[inline] - fn advance(&mut self, by: usize) -> Result<(), End> { - self.inner.advance(by)?; - self.count += by; - Ok(()) - } - - #[inline] - fn remaining(&self) -> usize { - self.inner.remaining() - } -} - -impl Seek for Count { - type Position = Count; - - #[inline] - fn tell(&self) -> Self::Position { - Count { - inner: self.inner.tell(), - count: self.count, - } - } - - #[inline] - fn seek(&mut self, position: &Self::Position) -> Self::Position { - let position = Count { - inner: self.inner.seek(&position.inner), - count: self.count, - }; - self.count = position.count; - position - } -} diff --git a/byst/src/io/limit.rs b/byst/src/io/limit.rs deleted file mode 100644 index c8593fd..0000000 --- a/byst/src/io/limit.rs +++ /dev/null @@ -1,217 +0,0 @@ -use super::{ - read::ReadError, - BufReader, - End, - Reader, - Seek, -}; -use crate::BufMut; - -#[derive(Clone, Debug)] -pub struct Limit { - inner: R, - limit: usize, -} - -impl Limit { - #[inline] - pub fn new(inner: R, limit: usize) -> Self { - Self { inner, limit } - } - - #[inline] - pub fn remaining_limit(&self) -> usize { - self.limit - } - - #[inline] - pub fn into_inner(self) -> R { - self.inner - } -} - -impl Limit { - pub fn skip_remaining(&mut self) -> Result<(), ::Error> { - match self.inner.skip(self.limit) { - Ok(()) => { - self.limit = 0; - Ok(()) - } - Err(e) => { - self.limit -= e.amount_read(); - Err(e) - } - } - } -} - -impl Reader for Limit { - type Error = ::Error; - - fn read_into( - &mut self, - dest: D, - limit: impl Into>, - ) -> Result { - let limit = if let Some(limit) = limit.into() { - std::cmp::min(self.limit, limit) - } - else { - self.limit - }; - - match self.inner.read_into(dest, limit) { - Ok(n_read) => { - self.limit -= n_read; - Ok(n_read) - } - Err(e) => { - self.limit -= e.amount_read(); - Err(e) - } - } - } - - fn read_into_exact(&mut self, dest: D, length: usize) -> Result<(), Self::Error> { - if length > self.limit { - Err(Self::Error::from_end(End { - read: 0, - requested: length, - remaining: self.limit, - })) - } - else { - match self.inner.read_into_exact(dest, length) { - Ok(()) => { - self.limit -= length; - Ok(()) - } - Err(e) => { - self.limit -= e.amount_read(); - Err(e) - } - } - } - } - - fn skip(&mut self, amount: usize) -> Result<(), Self::Error> { - let amount = std::cmp::min(self.limit, amount); - - match Reader::skip(&mut self.inner, amount) { - Ok(()) => { - self.limit -= amount; - Ok(()) - } - Err(e) => { - self.limit -= e.amount_read(); - Err(e) - } - } - } -} - -impl BufReader for Limit { - type View = R::View; - - #[inline] - fn peek_chunk(&self) -> Option<&[u8]> { - if self.limit == 0 { - None - } - else { - let chunk = self.inner.peek_chunk()?; - Some(&chunk[..std::cmp::min(chunk.len(), self.limit)]) - } - } - - #[inline] - fn view(&mut self, length: usize) -> Result { - if length > self.limit { - Err(End { - read: 0, - requested: length, - remaining: self.limit.min(self.inner.remaining()), - }) - } - else { - self.limit -= length; - self.inner.view(length) - } - } - - #[inline] - fn peek_view(&self, length: usize) -> Result { - if length > self.limit { - Err(End { - read: 0, - requested: length, - remaining: self.limit.min(self.inner.remaining()), - }) - } - else { - self.inner.peek_view(length) - } - } - - #[inline] - fn rest(&mut self) -> Self::View { - match self.inner.view(self.limit) { - Ok(view) => { - self.limit = 0; - view - } - Err(_) => self.inner.rest(), - } - } - - #[inline] - fn peek_rest(&self) -> Self::View { - match self.inner.peek_view(self.limit) { - Ok(view) => view, - Err(_) => self.inner.peek_rest(), - } - } - - #[inline] - fn advance(&mut self, by: usize) -> Result<(), End> { - if by > self.limit { - Err(End { - read: 0, - requested: by, - remaining: self.limit.min(self.inner.remaining()), - }) - } - else { - self.inner.advance(by)?; - self.limit -= by; - Ok(()) - } - } - - #[inline] - fn remaining(&self) -> usize { - std::cmp::min(self.limit, self.inner.remaining()) - } -} - -impl Seek for Limit { - type Position = Limit; - - #[inline] - fn tell(&self) -> Self::Position { - Limit { - inner: self.inner.tell(), - limit: self.limit, - } - } - - #[inline] - fn seek(&mut self, position: &Self::Position) -> Self::Position { - let position = Limit { - inner: self.inner.seek(&position.inner), - limit: self.limit, - }; - self.limit = position.limit; - position - } -} diff --git a/byst/src/io/mod.rs b/byst/src/io/mod.rs deleted file mode 100644 index 04d7d35..0000000 --- a/byst/src/io/mod.rs +++ /dev/null @@ -1,78 +0,0 @@ -mod count; -mod limit; -mod read; -mod write; - -pub use byst_macros::{ - Read, - Write, -}; - -pub use self::{ - count::Count, - limit::Limit, - read::{ - read, - BufReader, - End, - InvalidDiscriminant, - Read, - ReadError, - Reader, - ReaderExt, - }, - write::{ - BufWriter, - Full, - Write, - Writer, - WriterExt, - }, -}; - -/// A reader or writer that also has knowledge about the position in the -/// underlying buffer. -pub trait Seek { - type Position; - - fn tell(&self) -> Self::Position; - fn seek(&mut self, position: &Self::Position) -> Self::Position; -} - -impl<'a, T: Seek> Seek for &'a mut T { - type Position = T::Position; - - #[inline] - fn tell(&self) -> Self::Position { - T::tell(*self) - } - - #[inline] - fn seek(&mut self, position: &Self::Position) -> Self::Position { - T::seek(*self, position) - } -} - -impl<'a> Seek for &'a [u8] { - type Position = &'a [u8]; - - #[inline] - fn tell(&self) -> Self::Position { - self - } - - #[inline] - fn seek(&mut self, position: &Self::Position) -> Self::Position { - std::mem::replace(self, *position) - } -} - -/// A reader or writer that knows how many bytes are remaining. -pub trait Remaining { - fn remaining(&self) -> usize; - - #[inline] - fn is_at_end(&self) -> bool { - self.remaining() == 0 - } -} diff --git a/byst/src/io/read.rs b/byst/src/io/read.rs deleted file mode 100644 index 5bf8ac2..0000000 --- a/byst/src/io/read.rs +++ /dev/null @@ -1,729 +0,0 @@ -use std::{ - convert::Infallible, - marker::PhantomData, - net::{ - Ipv4Addr, - Ipv6Addr, - }, -}; - -use byst_macros::for_tuple; - -use super::{ - Limit, - Seek, -}; -use crate::{ - impl_me, - Buf, - BufMut, -}; - -/// Something that can be read from a reader `R`, given the context `C`. -#[diagnostic::on_unimplemented( - message = "The type `{Self}` cannot be be read from reader `{R}` with context `{C}`.", - label = "Trying to read this", - note = "Are you using the right context? Most integers for example need an endianness specified as context: e.g. `reader.read_with(NetworkEndian)`" -)] -pub trait Read: Sized { - type Error; - - fn read(reader: &mut R, context: C) -> Result; -} - -pub trait Reader { - type Error: ReadError; - - /// This may return succesful with less bytes that space is available in - /// `dest` or `limit` specifies. It should only fail if the underlying data - /// source fails, but needs to still provide a way to tell how many bytes - /// have been read. - fn read_into( - &mut self, - dest: D, - limit: impl Into>, - ) -> Result; - - fn read_into_exact(&mut self, dest: D, length: usize) -> Result<(), Self::Error>; - - fn skip(&mut self, amount: usize) -> Result<(), Self::Error>; -} - -pub trait ReadError { - fn from_end(end: End) -> Self; - - fn is_end(&self) -> bool; - - fn amount_read(&self) -> usize; - - fn is_exact_end(&self) -> bool { - self.is_end() && self.amount_read() == 0 - } -} - -pub trait ReaderExt: Reader { - #[inline] - fn read>(&mut self) -> Result { - self.read_with(()) - } - - #[inline] - fn read_with, C>(&mut self, context: C) -> Result { - T::read(self, context) - } - - #[inline] - fn read_byte_array(&mut self) -> Result<[u8; N], Self::Error> { - let mut buf = [0u8; N]; - self.read_into_exact(&mut buf, N)?; - Ok(buf) - } - - #[inline] - fn limit(&mut self, limit: usize) -> Limit<&mut Self> { - Limit::new(self, limit) - } -} - -impl ReaderExt for R {} - -pub trait BufReader: Reader + Seek { - type View: Buf; - - /// Returns a single chunk starting at the current position. - /// - /// This doesn't advance the cursor. You can use [`advance`][Self::advance] - /// to advance the cursor. - fn peek_chunk(&self) -> Option<&[u8]>; - - /// Returns a view of `length` bytes starting at the current position. - /// - /// This advances the cursor by `length` bytes. - fn view(&mut self, length: usize) -> Result; - - /// Returns a view of `length` bytes starting at the current position. - /// - /// This doesn't advance the cursor. You can use [`advance`][Self::advance] - /// to advance the cursor. - fn peek_view(&self, length: usize) -> Result; - - /// Returns a view of the rest of this reader. - /// - /// This advances the cursor to the end of the reader. - fn rest(&mut self) -> Self::View; - - /// Returns a view of the rest of this reader. - /// - /// This doesn't advance the cursor. - fn peek_rest(&self) -> Self::View; - - /// Advances the cursor by `by` bytes. - fn advance(&mut self, by: usize) -> Result<(), End>; - - /// Returns the number of bytes remaining. - fn remaining(&self) -> usize; -} - -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, thiserror::Error)] -#[error("End of reader: Tried to read {requested} bytes, but only {read} could be read.")] -pub struct End { - pub read: usize, - pub requested: usize, - pub remaining: usize, -} - -impl ReadError for End { - #[inline] - fn from_end(end: End) -> Self { - end - } - - #[inline] - fn amount_read(&self) -> usize { - self.read - } - - #[inline] - fn is_end(&self) -> bool { - true - } -} - -impl From for std::io::ErrorKind { - #[inline] - fn from(_: End) -> Self { - std::io::ErrorKind::UnexpectedEof - } -} - -impl From for std::io::Error { - #[inline] - fn from(_: End) -> Self { - std::io::ErrorKind::UnexpectedEof.into() - } -} - -impl From for End { - #[inline] - fn from(value: Infallible) -> Self { - match value {} - } -} - -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, thiserror::Error)] -#[error("Invalid discriminant: {0}")] -pub struct InvalidDiscriminant(pub D); - -impl<'a, R: Reader> Reader for &'a mut R { - type Error = ::Error; - - #[inline] - fn read_into( - &mut self, - dest: D, - limit: impl Into>, - ) -> Result { - ::read_into(*self, dest, limit) - } - - #[inline] - fn read_into_exact(&mut self, dest: D, length: usize) -> Result<(), Self::Error> { - ::read_into_exact(*self, dest, length) - } - - #[inline] - fn skip(&mut self, amount: usize) -> Result<(), Self::Error> { - ::skip(*self, amount) - } -} - -impl_me! { - impl['a] Reader for &'a [u8] as BufReader; - impl['a] Read<_, ()> for &'a [u8] as BufReader::View; -} - -impl<'a, R: BufReader> BufReader for &'a mut R { - type View = R::View; - - #[inline] - fn peek_chunk(&self) -> Option<&[u8]> { - R::peek_chunk(*self) - } - - #[inline] - fn view(&mut self, length: usize) -> Result { - R::view(*self, length) - } - - #[inline] - fn peek_view(&self, length: usize) -> Result { - R::peek_view(*self, length) - } - - #[inline] - fn rest(&mut self) -> Self::View { - R::rest(*self) - } - - #[inline] - fn peek_rest(&self) -> Self::View { - R::peek_rest(*self) - } - - #[inline] - fn advance(&mut self, by: usize) -> Result<(), End> { - R::advance(*self, by) - } - - #[inline] - fn remaining(&self) -> usize { - R::remaining(*self) - } -} - -impl<'a> BufReader for &'a [u8] { - type View = &'a [u8]; - - #[inline] - fn peek_chunk(&self) -> Option<&[u8]> { - if self.is_empty() { - None - } - else { - Some(*self) - } - } - - #[inline] - fn view(&mut self, length: usize) -> Result { - if length <= self.len() { - let (left, right) = self.split_at(length); - *self = right; - Ok(left) - } - else { - Err(End { - requested: length, - read: 0, - remaining: self.len(), - }) - } - } - - #[inline] - fn peek_view(&self, length: usize) -> Result { - if length <= self.len() { - Ok(&self[..length]) - } - else { - Err(End { - requested: length, - read: 0, - remaining: self.len(), - }) - } - } - - #[inline] - fn rest(&mut self) -> Self::View { - std::mem::take(self) - } - - #[inline] - fn peek_rest(&self) -> Self::View { - self - } - - #[inline] - fn advance(&mut self, by: usize) -> Result<(), End> { - if by <= self.len() { - *self = &self[by..]; - Ok(()) - } - else { - Err(End { - read: 0, - requested: by, - remaining: self.len(), - }) - } - } - - #[inline] - fn remaining(&self) -> usize { - self.len() - } -} - -impl Read for () { - type Error = Infallible; - - #[inline] - fn read(_reader: &mut R, _context: ()) -> Result { - Ok(()) - } -} - -impl Read for PhantomData { - type Error = Infallible; - - #[inline] - fn read(_reader: &mut R, _context: ()) -> Result { - Ok(PhantomData) - } -} -/* -impl, const N: usize> Read for [T; N] { - type Error = End; - - #[inline] - fn read(reader: &mut R, _context: C) -> Result { - todo!(); - } -} -*/ - -impl Read for [u8; N] { - type Error = ::Error; - - #[inline] - fn read(reader: &mut R, _context: ()) -> Result { - reader.read_byte_array() - } -} - -impl Read for u8 { - type Error = ::Error; - - #[inline] - fn read(reader: &mut R, _context: ()) -> Result { - Ok(reader.read_byte_array::<1>()?[0]) - } -} - -impl Read for i8 { - type Error = ::Error; - - #[inline] - fn read(reader: &mut R, _context: ()) -> Result { - Ok(reader.read::()? as i8) - } -} - -impl Read for Ipv4Addr { - type Error = ::Error; - - #[inline] - fn read(reader: &mut R, _context: ()) -> Result { - Ok(Ipv4Addr::from(reader.read::<[u8; 4]>()?)) - } -} - -impl Read for Ipv6Addr { - type Error = ::Error; - - #[inline] - fn read(reader: &mut R, _context: ()) -> Result { - Ok(Ipv6Addr::from(reader.read::<[u8; 16]>()?)) - } -} - -/// Implements [`Read`] for tuples. -/// -/// # TODO -/// -/// - add params -macro_rules! impl_read_for_tuple { - ( - $index:tt => $name:ident: $ty:ident - ) => { - impl_read_for_tuple! { - $index => $name: $ty, - } - }; - ( - $first_index:tt => $first_name:ident: $first_ty:ident, - $($tail_index:tt => $tail_name:ident: $tail_ty:ident),* - ) => { - impl Read for ($first_ty, $($tail_ty,)*) - where - $first_ty: Read, - $($tail_ty: Read>::Error>,)* - { - type Error = <$first_ty as Read>::Error; - - fn read(mut reader: &mut R, _context: ()) -> Result { - let $first_name = <$first_ty as Read>::read(&mut reader, ())?; - $( - let $tail_name = <$tail_ty as Read>::read(&mut reader, ())?; - )* - Ok(( - $first_name, - $($tail_name,)* - )) - } - } - }; -} -for_tuple!(impl_read_for_tuple! for 1..=8); - -/// Read macro -/// -/// # TODO -/// -/// - deprecate this. `reader.read::()` and `reader.read_with::(context)` are nicer. -#[macro_export] -macro_rules! read { - ($reader:expr => $ty:ty; $params:expr) => { - { - <$ty as ::byst::io::Read::<_, _>>::read($reader, $params) - } - }; - ($reader:expr => $ty:ty) => { - read!($reader => $ty; ()) - }; - ($reader:expr; $params:expr) => { - read!($reader => _; $params) - }; - ($reader:expr) => { - read!($reader => _; ()) - }; -} -pub use read; - -#[cfg(test)] -mod tests { - use std::marker::PhantomData; - - use crate::io::{ - read, - End, - InvalidDiscriminant, - Read, - ReaderExt, - }; - - macro_rules! assert_derive_read { - ($($ty:ty),*) => { - { - let mut reader: &'static [u8] = b""; - $( - match reader.read::<$ty>() { - Ok(v) => { - let _: $ty = v; - } - Err(_) => {} - } - )* - } - }; - } - - macro_rules! assert_read { - ($ty:ty, $input:expr, $expected:expr $(, $($arg:tt)+)?) => { - { - let mut reader: &'static [u8] = $input; - let got = reader.read::<$ty>().expect("Expected read to be successful"); - assert_eq!(got, $expected $(, $($arg)+)?); - } - }; - } - - macro_rules! assert_read_fail { - ($ty:ty, $input:expr, $expected:expr $(, $($arg:tt)+)?) => { - { - let mut reader: &'static [u8] = $input; - let got = reader.read::<$ty>().expect_err("Expected read to fail"); - assert_eq!(got, $expected $(, $($arg)+)?); - } - }; - } - - #[test] - fn derive_read_for_unit_struct() { - #[derive(Read)] - struct Foo; - #[derive(Read)] - struct Bar(); - #[derive(Read)] - struct Nya {} - assert_derive_read!(Foo, Bar, Nya); - } - - #[test] - fn derive_read_for_struct_of_basic_types() { - #[derive(Read)] - #[allow(dead_code)] - struct Foo { - x1: u8, - x2: i8, - - #[byst(big)] - x3: u16, - #[byst(little)] - x4: u16, - #[byst(big)] - x5: i16, - #[byst(little)] - x6: i16, - - #[byst(big)] - x7: u32, - #[byst(little)] - x8: u32, - #[byst(big)] - x9: i32, - #[byst(little)] - x10: i32, - - #[byst(big)] - x11: u64, - #[byst(little)] - x12: u64, - #[byst(big)] - x13: i64, - #[byst(little)] - x14: i64, - - #[byst(big)] - x15: u128, - #[byst(little)] - x16: u128, - #[byst(big)] - x17: i128, - #[byst(little)] - x18: i128, - - x19: (), - x20: PhantomData<()>, - x21: [u8; 4], - } - assert_derive_read!(Foo); - } - - #[test] - fn derive_read_for_nested_struct() { - #[derive(Read)] - #[allow(dead_code)] - struct Bar(u8); - #[derive(Read)] - #[allow(dead_code)] - struct Foo(Bar); - assert_derive_read!(Foo); - } - - #[test] - fn derive_read_uses_specified_endianness() { - #[derive(Read, Debug, PartialEq)] - struct Foo { - #[byst(big)] - x: u16, - #[byst(little)] - y: u16, - #[byst(network)] - z: u16, - } - assert_read!( - Foo, - b"\x12\x34\x12\x34\x12\x34", - Foo { - x: 0x1234, - y: 0x3412, - z: 0x1234 - } - ); - } - - #[test] - fn derive_read_for_empty_enum() { - #[derive(Debug, PartialEq, Eq, thiserror::Error)] - #[error("oops")] - enum MyErr { - Incomplete(#[from] End), - Invalid(#[from] InvalidDiscriminant), - } - - #[derive(Read, Debug, PartialEq)] - #[byst(tag(ty = "u8"), error = "MyErr")] - enum Foo {} - - let mut reader: &'static [u8] = b"\x00\x00"; - let result = read!(&mut reader => Foo); - assert!(matches!( - result, - Err(MyErr::Invalid(InvalidDiscriminant(0))) - )); - } - - #[test] - fn derive_read_for_simple_enum() { - #[derive(Debug, PartialEq, Eq, thiserror::Error)] - #[error("oops")] - enum MyErr { - Incomplete(#[from] End), - Invalid(#[from] InvalidDiscriminant), - } - - #[derive(Read, Debug, PartialEq)] - #[byst(tag(ty = "u16", big), error = "MyErr")] - enum Foo { - One = 1, - Two = 2, - } - - assert_read!(Foo, b"\x00\x01", Foo::One); - assert_read!(Foo, b"\x00\x02", Foo::Two); - assert_read_fail!(Foo, b"\x00\x03", MyErr::Invalid(InvalidDiscriminant(3))); - } - - #[test] - fn derive_read_for_enum_with_fields() { - #[derive(Debug, PartialEq, Eq, thiserror::Error)] - #[error("oops")] - enum MyErr { - Incomplete(#[from] End), - Invalid(#[from] InvalidDiscriminant), - } - - #[derive(Read, Debug, PartialEq)] - #[byst(tag(ty = "u8"), error = "MyErr")] - enum Foo { - #[byst(tag = 1)] - One { - #[byst(big)] - x: u16, - #[byst(big)] - y: u16, - }, - #[byst(tag = 2)] - Two(#[byst(big)] u16), - } - - assert_read!( - Foo, - b"\x01\x01\x02\xab\xcd", - Foo::One { - x: 0x0102, - y: 0xabcd - } - ); - assert_read!(Foo, b"\x02\xac\xab", Foo::Two(0xacab)); - } - - #[test] - fn derive_read_for_enum_with_external_discriminant() { - #[derive(Debug, PartialEq, Eq, thiserror::Error)] - #[error("oops")] - enum MyErr { - End(#[from] End), - Invalid(#[from] InvalidDiscriminant), - } - - #[derive(Read, Debug, PartialEq)] - #[byst(tag(ty = "u8"), context(name = "discriminant", ty = "u8"), match_expr = discriminant * 2, error = "MyErr")] - enum Foo { - #[byst(tag = 2)] - One { - #[byst(big)] - x: u16, - #[byst(big)] - y: u16, - }, - #[byst(tag = 4)] - Two(#[byst(big)] u16), - } - - #[derive(Read, Debug, PartialEq)] - #[byst(error = "MyErr")] - struct Bar { - my_tag: u8, - #[byst(big)] - some_data: u16, - #[byst(context(ty = "u8", with = my_tag))] - foo: Foo, - } - - assert_read!( - Bar, - b"\x01\x12\x34\x01\x02\xab\xcd", - Bar { - my_tag: 1, - some_data: 0x1234, - foo: Foo::One { - x: 0x0102, - y: 0xabcd - } - } - ); - assert_read!( - Bar, - b"\x02\x12\x34\xac\xab", - Bar { - my_tag: 2, - some_data: 0x1234, - foo: Foo::Two(0xacab) - } - ); - } -} diff --git a/byst/src/io/write.rs b/byst/src/io/write.rs deleted file mode 100644 index 5d6246b..0000000 --- a/byst/src/io/write.rs +++ /dev/null @@ -1,460 +0,0 @@ -use std::{ - convert::Infallible, - marker::PhantomData, -}; - -use byst_macros::for_tuple; - -use super::Limit; -use crate::{ - buf::Buf, - impl_me, - BufMut, -}; - -/// Something that can be written to a writer `W`, given the context `C`. -#[diagnostic::on_unimplemented( - message = "The type `{Self}` cannot be be written to writer `{W}` with context `{C}`.", - label = "Trying to write this", - note = "Are you using the right context? Most integers for example need an endianness specified as context: e.g. `writer.write_with(123, NetworkEndian)`" -)] -pub trait Write { - type Error; - - fn write(&self, writer: &mut W, context: C) -> Result<(), Self::Error>; -} - -pub trait Writer { - type Error; - - fn write_buf(&mut self, buf: B) -> Result<(), Self::Error>; - fn skip(&mut self, amount: usize) -> Result<(), Self::Error>; -} - -pub trait WriterExt: Writer { - #[inline] - fn write>(&mut self, value: &T) -> Result<(), T::Error> { - Self::write_with(self, value, ()) - } - - #[inline] - fn write_with, C>(&mut self, value: &T, context: C) -> Result<(), T::Error> { - T::write(value, self, context) - } - - #[inline] - fn limit(&mut self, limit: usize) -> Limit<&mut Self> { - Limit::new(self, limit) - } -} - -impl WriterExt for W {} - -pub trait BufWriter: Writer { - type ViewMut<'a>: BufMut - where - Self: 'a; - - fn peek_chunk_mut(&mut self) -> Option<&mut [u8]>; - - fn view_mut(&mut self, length: usize) -> Result, Full>; - - fn peek_view_mut(&mut self, length: usize) -> Result, Full>; - - fn rest_mut(&mut self) -> Self::ViewMut<'_>; - - fn peek_rest_mut(&mut self) -> Self::ViewMut<'_>; - - fn advance(&mut self, by: usize) -> Result<(), Full>; - - fn remaining(&self) -> usize; - - fn extend(&mut self, with: &[u8]) -> Result<(), Full>; -} - -#[derive(Clone, Copy, Debug, Default, thiserror::Error)] -#[error( - "Writer full: Tried to write {requested} bytes, but only {written} bytes could be written." -)] -pub struct Full { - pub written: usize, - pub requested: usize, - pub remaining: usize, -} - -impl From for Full { - fn from(value: Infallible) -> Self { - match value {} - } -} - -impl From for Full { - fn from(value: crate::buf::Full) -> Self { - Self { - written: 0, - requested: value.required, - remaining: value.capacity, - } - } -} - -impl<'w, W: Writer> Writer for &'w mut W { - type Error = W::Error; - - #[inline] - fn write_buf(&mut self, buf: B) -> Result<(), Self::Error> { - ::write_buf(*self, buf) - } - - #[inline] - fn skip(&mut self, amount: usize) -> Result<(), Self::Error> { - ::skip(*self, amount) - } -} - -impl_me! { - impl['a] Writer for &'a mut [u8] as BufWriter; - impl['a] Write<_, ()> for &'a [u8] as Writer::write_buf; - //impl['a] Writer for &'a mut Vec as BufWriter; -} - -impl<'b, W: BufWriter> BufWriter for &'b mut W { - type ViewMut<'a> = ::ViewMut<'a> where Self: 'a; - - #[inline] - fn peek_chunk_mut(&mut self) -> Option<&mut [u8]> { - W::peek_chunk_mut(*self) - } - - #[inline] - fn view_mut(&mut self, length: usize) -> Result, Full> { - W::view_mut(*self, length) - } - - #[inline] - fn peek_view_mut(&mut self, length: usize) -> Result, Full> { - W::peek_view_mut(*self, length) - } - - #[inline] - fn rest_mut(&mut self) -> Self::ViewMut<'_> { - W::rest_mut(*self) - } - - #[inline] - fn peek_rest_mut(&mut self) -> Self::ViewMut<'_> { - W::peek_rest_mut(*self) - } - - #[inline] - fn advance(&mut self, by: usize) -> Result<(), Full> { - W::advance(*self, by) - } - - #[inline] - fn remaining(&self) -> usize { - W::remaining(*self) - } - - #[inline] - fn extend(&mut self, with: &[u8]) -> Result<(), Full> { - W::extend(*self, with) - } -} - -impl<'b> BufWriter for &'b mut [u8] { - type ViewMut<'a> = &'a mut [u8] where Self: 'a; - - #[inline] - fn peek_chunk_mut(&mut self) -> Option<&mut [u8]> { - if self.is_empty() { - None - } - else { - Some(&mut **self) - } - } - - fn view_mut(&mut self, length: usize) -> Result, crate::io::Full> { - if length <= self.len() { - let (left, right) = std::mem::take(self).split_at_mut(length); - *self = right; - Ok(left) - } - else { - Err(Full { - requested: length, - remaining: self.len(), - written: 0, - }) - } - } - - #[inline] - fn peek_view_mut(&mut self, length: usize) -> Result, Full> { - if length <= self.len() { - Ok(&mut self[..length]) - } - else { - Err(Full { - requested: length, - remaining: self.len(), - written: 0, - }) - } - } - - #[inline] - fn rest_mut(&mut self) -> Self::ViewMut<'_> { - std::mem::take(self) - } - - #[inline] - fn peek_rest_mut(&mut self) -> Self::ViewMut<'_> { - &mut **self - } - - #[inline] - fn advance(&mut self, by: usize) -> Result<(), Full> { - if by <= self.len() { - let (_, rest) = std::mem::take(self).split_at_mut(by); - *self = rest; - Ok(()) - } - else { - Err(Full { - requested: by, - remaining: self.len(), - written: 0, - }) - } - } - - #[inline] - fn remaining(&self) -> usize { - self.len() - } - - #[inline] - fn extend(&mut self, with: &[u8]) -> Result<(), Full> { - if with.len() <= self.len() { - let (dest, rest) = std::mem::take(self).split_at_mut(with.len()); - dest.copy_from_slice(with); - *self = rest; - Ok(()) - } - else { - Err(Full { - requested: with.len(), - remaining: self.len(), - written: 0, - }) - } - } -} - -impl Write for () { - type Error = Infallible; - - #[inline] - fn write(&self, _writer: &mut W, _context: ()) -> Result<(), Self::Error> { - Ok(()) - } -} - -impl Write for PhantomData { - type Error = Infallible; - - #[inline] - fn write(&self, _writer: &mut W, _context: ()) -> Result<(), Self::Error> { - Ok(()) - } -} - -impl Write for [u8; N] { - type Error = ::Error; - - #[inline] - fn write(&self, writer: &mut W, _context: ()) -> Result<(), Self::Error> { - writer.write_buf(self) - } -} - -impl Write for u8 { - type Error = ::Error; - - #[inline] - fn write(&self, writer: &mut W, _context: ()) -> Result<(), Self::Error> { - writer.write_buf([*self]) - } -} - -impl Write for i8 { - type Error = ::Error; - - #[inline] - fn write(&self, writer: &mut W, _context: ()) -> Result<(), Self::Error> { - writer.write(&(*self as u8)) - } -} - -macro_rules! impl_read_for_tuple { - ( - $index:tt => $name:ident: $ty:ident - ) => { - impl_read_for_tuple! { - $index => $name: $ty, - } - }; - ( - $first_index:tt => $first_name:ident: $first_ty:ident, - $($tail_index:tt => $tail_name:ident: $tail_ty:ident),* - ) => { - impl Write for ($first_ty, $($tail_ty,)*) - where - $first_ty: Write, - $($tail_ty: Write>::Error>,)* - { - type Error = <$first_ty as Write>::Error; - - fn write(&self, mut writer: &mut W, _context: ()) -> Result<(), Self::Error> { - <$first_ty as Write>::write(&self.$first_index, &mut writer, ())?; - $( - <$tail_ty as Write>::write(&self.$tail_index, &mut writer, ())?; - )* - Ok(()) - } - } - }; -} -for_tuple!(impl_read_for_tuple! for 1..=8); - -#[cfg(test)] -mod tests { - use std::marker::PhantomData; - - use crate::{ - buf::BufMut, - io::{ - Write, - WriterExt, - }, - }; - - macro_rules! assert_derive_write { - ($($ty:ty),*) => { - { - let mut buf = vec![]; - let mut writer = buf.writer(); - $( - let _ = writer.write::<$ty>(&Default::default()); - )* - } - }; - } - - macro_rules! assert_write { - ($input:expr, $expected:expr $(, $($arg:tt)+)?) => { - { - let mut buf = vec![]; - let mut writer = buf.writer(); - writer.write(&$input).expect("Expected write to be successful"); - assert_eq!(buf, $expected $(, $($arg)+)?); - } - }; - } - - #[test] - fn derive_write_for_unit_struct() { - #[derive(Write, Default)] - struct Foo; - #[derive(Write, Default)] - struct Bar(); - #[derive(Write, Default)] - struct Nya {} - assert_derive_write!(Foo, Bar, Nya); - } - - #[test] - fn derive_write_for_struct_of_basic_types() { - #[derive(Write, Default)] - #[allow(dead_code)] - struct Foo { - x1: u8, - x2: i8, - - #[byst(big)] - x3: u16, - #[byst(little)] - x4: u16, - #[byst(big)] - x5: i16, - #[byst(little)] - x6: i16, - - #[byst(big)] - x7: u32, - #[byst(little)] - x8: u32, - #[byst(big)] - x9: i32, - #[byst(little)] - x10: i32, - - #[byst(big)] - x11: u64, - #[byst(little)] - x12: u64, - #[byst(big)] - x13: i64, - #[byst(little)] - x14: i64, - - #[byst(big)] - x15: u128, - #[byst(little)] - x16: u128, - #[byst(big)] - x17: i128, - #[byst(little)] - x18: i128, - - x19: (), - x20: PhantomData<()>, - x21: [u8; 4], - } - assert_derive_write!(Foo); - } - - #[test] - fn derive_write_for_nested_struct() { - #[derive(Write, Default)] - #[allow(dead_code)] - struct Bar(u8); - #[derive(Write, Default)] - #[allow(dead_code)] - struct Foo(Bar); - assert_derive_write!(Foo); - } - - #[test] - fn derive_write_uses_specified_endianness() { - #[derive(Write, Default, Debug, PartialEq)] - struct Foo { - #[byst(big)] - x: u16, - #[byst(little)] - y: u16, - #[byst(network)] - z: u16, - } - assert_write!( - Foo { - x: 0x1234, - y: 0x3412, - z: 0x1234 - }, - b"\x12\x34\x12\x34\x12\x34" - ); - } -} diff --git a/byst/src/lib.rs b/byst/src/lib.rs deleted file mode 100644 index 5876b83..0000000 --- a/byst/src/lib.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! bytes, bytter, `byst`! -//! -//! Read and write bytes on steriods! - -// enabled nightly features -// todo: we might get around these by just copying their source code. - -// required by `crate::buf::partially_initialized`. -#![feature(maybe_uninit_slice, maybe_uninit_write_slice, maybe_uninit_fill)] -// required by `crate::buf::array_vec` -#![feature(maybe_uninit_array_assume_init)] -// required by `crate::endianness::{Encode, Decode}`. -#![allow(incomplete_features)] -#![feature(generic_const_exprs)] -// required by `crate::buf::slab` -#![feature(new_uninit, slice_ptr_get)] - -mod bits; -pub mod buf; -pub mod bytes; -mod copy; -pub mod endianness; -pub mod hexdump; -pub mod io; -mod range; -pub mod util; - -pub use self::{ - buf::{ - Buf, - BufMut, - }, - bytes::{ - Bytes, - BytesMut, - }, - copy::{ - copy, - copy_io, - copy_range, - }, - range::{ - Range, - RangeOutOfBounds, - }, -}; - -// hack to get the proc-macro working from this crate -extern crate self as byst; - -#[derive(Debug, PartialEq, Eq, thiserror::Error)] -#[error("Index out of bounds: {required} not in buffer ({}..{})", .bounds.0, .bounds.1)] -pub struct IndexOutOfBounds { - pub required: usize, - pub bounds: (usize, usize), -} diff --git a/byst/src/range.rs b/byst/src/range.rs deleted file mode 100644 index a9f1690..0000000 --- a/byst/src/range.rs +++ /dev/null @@ -1,271 +0,0 @@ -use std::{ - fmt::Debug, - ops::{ - Bound, - RangeBounds, - }, -}; - -#[derive(Clone, Copy, PartialEq, Eq, Default)] -pub struct Range { - pub start: Option, - pub end: Option, -} - -impl Range { - #[inline] - fn from_range_bounds(range: impl RangeBounds) -> Self { - let start = match range.start_bound() { - Bound::Included(start) => Some(*start), - Bound::Excluded(start) => Some(*start + 1), - Bound::Unbounded => None, - }; - let end = match range.end_bound() { - Bound::Included(end) => Some(*end + 1), - Bound::Excluded(end) => Some(*end), - Bound::Unbounded => None, - }; - - Self { start, end } - } -} - -macro_rules! impl_from_range_bounds { - { - $( - $ty:ty; - )* - } => { - $( - impl From<$ty> for Range { - #[inline] - fn from(value: $ty) -> Self { - Self::from_range_bounds(value) - } - } - )* - }; -} - -impl_from_range_bounds! { - std::ops::Range; - std::ops::RangeFrom; - std::ops::RangeFull; - std::ops::RangeInclusive; - std::ops::RangeTo; - std::ops::RangeToInclusive; -} - -impl From for Range { - #[inline] - fn from(value: usize) -> Self { - Self { - start: Some(value), - end: Some(value + 1), - } - } -} - -impl<'a> From<&'a Range> for Range { - #[inline] - fn from(value: &'a Range) -> Self { - *value - } -} - -impl From<(usize, usize)> for Range { - #[inline] - fn from((start, end): (usize, usize)) -> Self { - Self { - start: Some(start), - end: Some(end), - } - } -} - -impl Range { - pub fn with_start(mut self, start: usize) -> Self { - self.start = Some(start); - self - } - - pub fn with_end(mut self, end: usize) -> Self { - self.end = Some(end); - self - } - - /// # Panic - /// - /// Panics if `self.start.is_none()`. - pub fn with_length(mut self, length: usize) -> Self { - self.end = Some(self.start.expect("Range::with_length called without start") + length); - self - } - - #[inline] - pub fn as_slice_index(&self) -> (Bound, Bound) { - ( - match self.start { - None => Bound::Unbounded, - Some(start) => Bound::Included(start), - }, - match self.end { - None => Bound::Unbounded, - Some(end) => Bound::Excluded(end), - }, - ) - } - - pub fn slice_get<'a>(&self, slice: &'a [u8]) -> Result<&'a [u8], RangeOutOfBounds> { - slice.get(self.as_slice_index()).ok_or({ - RangeOutOfBounds { - required: *self, - bounds: (0, slice.len()), - } - }) - } - - pub fn slice_get_mut<'a>(&self, slice: &'a mut [u8]) -> Result<&'a mut [u8], RangeOutOfBounds> { - let buf_length = slice.len(); - slice.get_mut(self.as_slice_index()).ok_or({ - RangeOutOfBounds { - required: *self, - bounds: (0, buf_length), - } - }) - } - - pub fn indices_unchecked_in(&self, start: usize, end: usize) -> (usize, usize) { - let index_start = self.start.unwrap_or_default() + start; - let mut index_end = self.end.map_or(end, |i| i + start); - if index_end < index_start { - index_end = index_start; - } - (index_start, index_end) - } - - pub fn indices_checked_in( - &self, - start: usize, - end: usize, - ) -> Result<(usize, usize), RangeOutOfBounds> { - let err = || { - Err(RangeOutOfBounds { - required: *self, - bounds: (start, end), - }) - }; - - let index_start = if let Some(range_start) = self.start { - let index_start = range_start + start; - if index_start > end { - return err(); - } - index_start - } - else { - start - }; - - let index_end = if let Some(range_end) = self.end { - let index_end = range_end + start; - if index_end > end { - return err(); - } - - // for now we will return RangeOutOfBounds, even though it should be - // InvalidRange or something - if index_end < index_start { - return err(); - } - - index_end - } - else { - end - }; - - Ok((index_start, index_end)) - } - - #[inline] - pub fn len_in(&self, start: usize, end: usize) -> usize { - let (start, end) = self.indices_unchecked_in(start, end); - end.saturating_sub(start) - } - - pub fn contains(&self, other: impl Into) -> bool { - let other = other.into(); - match (self.start, other.start) { - (Some(left), Some(right)) if left > right => return false, - _ => {} - } - !matches!( - (self.end, other.end), - (Some(left), Some(right)) if left < right - ) - } - - #[inline] - pub fn contained_by(&self, other: impl Into) -> bool { - other.into().contains(self) - } - - pub fn contains_index(&self, index: usize) -> bool { - match self.start { - Some(start) if start > index => return false, - _ => {} - } - !matches!( - self.end, - Some(end) if end < index - ) - } -} - -impl Debug for Range { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if let Some(start) = self.start { - write!(f, "{start}")?; - } - write!(f, "..")?; - if let Some(end) = self.end { - write!(f, "{end}")?; - } - Ok(()) - } -} - -#[derive(Debug, PartialEq, Eq, thiserror::Error)] -#[error("Range out of bounds: {required:?} not in buffer ({}..{})", .bounds.0, .bounds.1)] -pub struct RangeOutOfBounds { - pub required: Range, - pub bounds: (usize, usize), -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn unbounded_range() { - let r = Range::from(..); - - assert_eq!(r.start, None); - assert_eq!(r.end, None); - assert_eq!(r.indices_unchecked_in(12, 34), (12, 34)); - assert_eq!(r.indices_checked_in(12, 34).unwrap(), (12, 34)); - assert_eq!(r.len_in(12, 34), 34 - 12); - } - - #[test] - fn range_with_upper_bound() { - let r = Range::from(..4); - - assert_eq!(r.start, None); - assert_eq!(r.end, Some(4)); - assert_eq!(r.indices_unchecked_in(12, 34), (12, 16)); - assert_eq!(r.indices_checked_in(12, 34).unwrap(), (12, 16)); - assert_eq!(r.len_in(12, 34), 4); - } -} diff --git a/byst/src/util.rs b/byst/src/util.rs deleted file mode 100644 index 4226600..0000000 --- a/byst/src/util.rs +++ /dev/null @@ -1,583 +0,0 @@ -use std::{ - fmt::{ - Debug, - Display, - }, - iter::FusedIterator, -}; - -pub use byst_macros::for_tuple; - -use crate::{ - io::BufReader, - Buf, -}; - -pub struct Peekable { - pub inner: I, - pub peeked: Option, - pub peeked_back: Option, -} - -impl Peekable { - #[inline] - pub fn new(inner: I) -> Self { - Self { - inner, - peeked: None, - peeked_back: None, - } - } - - #[inline] - pub fn peek(&mut self) -> Option<&I::Item> { - self.peek_inner(); - // if `self.peeked` is None, we're done iterating the inner iterator, but might - // have peeked from the other side. In that case that will be the next item. - self.peeked.as_ref().or(self.peeked_back.as_ref()) - } - - #[inline] - pub fn peek_mut(&mut self) -> Option<&mut I::Item> { - self.peek_inner(); - // if `self.peeked` is None, we're done iterating the inner iterator, but might - // have peeked from the other side. In that case that will be the next item. - self.peeked.as_mut().or(self.peeked_back.as_mut()) - } - - #[inline] - fn peek_inner(&mut self) { - if self.peeked.is_none() { - self.peeked = self.next_inner(); - } - } - - #[inline] - fn next_inner(&mut self) -> Option { - self.inner.next() - } -} - -impl Peekable { - #[inline] - pub fn peek_back(&mut self) -> Option<&I::Item> { - self.peek_back_inner(); - // if `self.peeked` is None, we're done iterating the inner iterator, but might - // have peeked from the other side. In that case that will be the next item. - self.peeked_back.as_ref().or(self.peeked.as_ref()) - } - - #[inline] - pub fn peek_back_mut(&mut self) -> Option<&mut I::Item> { - self.peek_back_inner(); - // if `self.peeked` is None, we're done iterating the inner iterator, but might - // have peeked from the other side. In that case that will be the next item. - self.peeked_back.as_mut().or(self.peeked.as_mut()) - } - - #[inline] - fn peek_back_inner(&mut self) { - if self.peeked_back.is_none() { - self.peeked_back = self.next_back_inner(); - } - } - - #[inline] - fn next_back_inner(&mut self) -> Option { - self.inner.next_back() - } -} - -impl Iterator for Peekable { - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - self.peeked - .take() - .or_else(|| self.next_inner()) - // if we don't have a peeked value and the inner iterator is done, we might still have a - // peeked value from the other side. We'll return that in this case. - .or_else(|| self.peeked_back.take()) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (min, max) = self.inner.size_hint(); - let peek_count = self.peeked.is_some().then_some(1).unwrap_or_default() - + self.peeked_back.is_some().then_some(1).unwrap_or_default(); - (min + peek_count, max.map(|max| max + peek_count)) - } -} - -impl DoubleEndedIterator for Peekable { - fn next_back(&mut self) -> Option { - self.peeked_back - .take() - .or_else(|| self.next_back_inner()) - // if we don't have a peeked value and the inner iterator is done, we might still have a - // peeked value from the other side. We'll return that in this case. - .or_else(|| self.peeked.take()) - } -} - -impl ExactSizeIterator for Peekable {} - -impl FusedIterator for Peekable {} - -impl Debug for Peekable -where - I::Item: Debug, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Peekable") - .field("inner", &self.inner) - .field("peeked", &self.peeked) - .field("peeked_back", &self.peeked_back) - .finish() - } -} - -#[derive(Debug)] -pub struct Map { - inner: I, - map: M, -} - -impl Map { - #[inline] - pub fn new(inner: I, map: M) -> Self { - Self { inner, map } - } -} - -impl> Iterator for Map { - type Item = M::Output; - - #[inline] - fn next(&mut self) -> Option { - let item = self.inner.next()?; - Some(self.map.map(item)) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -impl> DoubleEndedIterator for Map { - #[inline] - fn next_back(&mut self) -> Option { - let item = self.inner.next_back()?; - Some(self.map.map(item)) - } -} - -impl> ExactSizeIterator for Map {} - -impl> FusedIterator for Map {} - -pub trait MapFunc { - type Output; - - fn map(&mut self, input: T) -> Self::Output; -} - -#[derive(Debug)] -pub struct ExactSizeIter { - inner: I, - exact_size: usize, -} - -impl ExactSizeIter { - #[inline] - pub fn new(inner: I, exact_size: usize) -> Self { - Self { inner, exact_size } - } -} - -impl Iterator for ExactSizeIter { - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - let item = self.inner.next()?; - self.exact_size -= 1; - Some(item) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - (self.exact_size, Some(self.exact_size)) - } -} - -impl DoubleEndedIterator for ExactSizeIter { - #[inline] - fn next_back(&mut self) -> Option { - let item = self.inner.next_back()?; - self.exact_size -= 1; - Some(item) - } -} - -impl ExactSizeIterator for ExactSizeIter {} - -impl FusedIterator for ExactSizeIter {} - -pub struct IsEndIter { - inner: Peekable, - iterated_from_start: bool, - iterated_from_end: bool, -} - -impl IsEndIter { - #[inline] - pub fn new(inner: I) -> Self { - Self { - inner: Peekable::new(inner), - iterated_from_end: false, - iterated_from_start: false, - } - } -} - -impl Iterator for IsEndIter { - type Item = IsEnd; - - fn next(&mut self) -> Option { - let item = self.inner.next()?; - let is_start = !self.iterated_from_start; - let is_end = !self.iterated_from_end && self.inner.peek().is_none(); - self.iterated_from_start = true; - Some(IsEnd { - is_start, - is_end, - item, - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -impl DoubleEndedIterator for IsEndIter { - fn next_back(&mut self) -> Option { - let item = self.inner.next_back()?; - let is_end = !self.iterated_from_end; - let is_start = !self.iterated_from_start && self.inner.peek_back().is_none(); - self.iterated_from_end = true; - Some(IsEnd { - is_start, - is_end, - item, - }) - } -} - -impl ExactSizeIterator for IsEndIter {} - -impl FusedIterator for IsEndIter {} - -impl Debug for IsEndIter -where - I::Item: Debug, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("IsEndIter") - .field("inner", &self.inner) - .field("iterated_from_start", &self.iterated_from_start) - .field("iterated_from_end", &self.iterated_from_end) - .finish() - } -} - -#[derive(Debug)] -pub struct IsEnd { - pub is_start: bool, - pub is_end: bool, - pub item: T, -} - -pub fn debug_as_hexdump(f: &mut std::fmt::Formatter, buf: impl Buf) -> std::fmt::Result { - use crate::hexdump::{ - Config, - Hexdump, - }; - let hex = Hexdump::with_config( - buf, - Config { - offset: 0, - trailing_newline: false, - at_least_one_line: false, - header: false, - }, - ); - Display::fmt(&hex, f) -} - -/// Checks if `needle` is a sub-slice of `haystack`, and returns the index at -/// which `needle` starts in `haystack`. -pub fn sub_slice_index(haystack: &[u8], needle: &[u8]) -> Option { - let haystack_start = haystack.as_ptr() as usize; - let haystack_end = haystack_start + haystack.len(); - let needle_start = needle.as_ptr() as usize; - let needle_end = needle_start + needle.len(); - - (needle_start >= haystack_start && needle_end <= haystack_end) - .then(|| needle_start - haystack_start) -} - -pub fn buf_eq(left: impl Buf, right: impl Buf) -> bool { - let left_len = left.len(); - let right_len = right.len(); - - if left_len != right_len { - return false; - } - - if left_len == 0 { - // this also means right_len == 0 - return true; - } - - let mut left_reader = left.reader(); - let mut right_reader = right.reader(); - - loop { - match (left_reader.peek_chunk(), right_reader.peek_chunk()) { - (None, None) => { - // boths chunks are exhausted at the same time, and they haven't been unequal - // yet. thus they're equal. - break true; - } - (Some(_), None) | (None, Some(_)) => { - // we checked that both bufs have the same length, so this should not happen. - - panic!( - "Both bufs have same length ({left_len}), but readers read different amount of bytes." - ); - } - (Some(left), Some(right)) => { - let left_len = <[u8]>::len(left); - let right_len = <[u8]>::len(right); - let n = std::cmp::min(left_len, right_len); - - if left[..n] != right[..n] { - break false; - } - - left_reader.advance(n).unwrap_or_else(|_e| { - panic!( - "Reader returned chunk of length {left_len}, but failed to advance by {n}." - ) - }); - right_reader.advance(n).unwrap_or_else(|_e| { - panic!( - "Reader returned chunk of length {right_len}, but failed to advance by {n}." - ) - }); - } - } - } -} - -macro_rules! cfg_pub { - { - $(#[$attr:meta])* - pub(#[cfg($($cfg:tt)*)]) $($rest:tt)* - } => { - #[cfg($($cfg)*)] - $(#[$attr])* - pub $($rest)* - - #[cfg(not($($cfg)*))] - $(#[$attr])* - pub(crate) $($rest)* - }; -} -pub(crate) use cfg_pub; - -// todo: make this a proc-macro -#[macro_export] -macro_rules! impl_me { - {} => {}; - { - impl $([ $($generics:tt)* ])? Reader for $ty:ty as BufReader; - $($rest:tt)* - } => { - impl<$($($generics)*)?> ::byst::io::Reader for $ty { - type Error = ::byst::io::End; - - #[inline] - fn read_into< - D: ::byst::buf::BufMut - >( - &mut self, - mut dest: D, - limit: impl Into>, - ) -> Result { - Ok(::byst::copy_io(dest.writer(), self, limit)) - } - - #[inline] - fn read_into_exact(&mut self, mut dest: D, length: usize) -> Result<(), Self::Error> { - let n_copied = ::byst::copy_io(dest.writer(), self, length); - assert!(n_copied <= length); - if n_copied == length { - Ok(()) - } - else { - // fixme: this is inaccurate if the copy fails because the destination buffer is full. - Err(::byst::io::End { read: n_copied, requested: length, remaining: 0 }) - } - } - - #[inline] - fn skip(&mut self, amount: usize) -> Result<(), Self::Error> { - ::byst::io::BufReader::advance(self, amount) - } - } - - impl<$($($generics)*)?> ::byst::io::Remaining for $ty { - #[inline] - fn remaining(&self) -> usize { - <$ty as ::byst::io::BufReader>::remaining(self) - } - } - - impl_me!{ $($rest)* } - }; - { - impl $([ $($generics:tt)* ])? Read<_, ()> for $ty:ty as BufReader::View; - $($rest:tt)* - } => { - impl<$($($generics)*,)? __R, __C> ::byst::io::Read<__R, __C> for $ty - where - __R: ::byst::io::BufReader, - { - type Error = ::std::convert::Infallible; - - #[inline] - fn read(reader: &mut __R, _context: __C) -> Result { - Ok(reader.rest()) - } - } - - impl_me!{ $($rest)* } - }; - { - impl $([ $($generics:tt)* ])? Writer for $ty:ty as BufWriter; - $($rest:tt)* - } => { - impl<$($($generics)*)?> ::byst::io::Writer for $ty { - type Error = ::byst::io::Full; - - fn write_buf<__B: ::byst::buf::Buf>(&mut self, buf: __B) -> Result<(), ::byst::io::Full> { - let n_copied = ::byst::copy_io(self, buf.reader(), None); - if n_copied < buf.len() { - Err(::byst::io::Full { - written: n_copied, - requested: buf.len(), - remaining: buf.len() - n_copied, - }) - } - else { - Ok(()) - } - } - - #[inline] - fn skip(&mut self, amount: usize) -> Result<(), ::byst::io::Full> { - <$ty as ::byst::io::BufWriter>::advance(self, amount) - } - } - - impl<$($($generics)*)?> ::byst::io::Remaining for $ty { - #[inline] - fn remaining(&self) -> usize { - <$ty as ::byst::io::BufWriter>::remaining(self) - } - } - - impl_me!{ $($rest)* } - }; - { - impl $([ $($generics:tt)* ])? Write<_, ()> for $ty:ty as Writer::write_buf; - $($rest:tt)* - } => { - impl<$($($generics)*,)? __W> ::byst::io::Write<__W, ()> for $ty - where - __W: ::byst::io::Writer, - { - type Error = <__W as ::byst::io::Writer>::Error; - - #[inline] - fn write(&self, writer: &mut __W, _context: ()) -> Result<(), Self::Error> { - writer.write_buf(self) - } - } - - impl_me!{ $($rest)* } - }; -} -pub use impl_me; - -#[cfg(test)] -mod tests { - use super::buf_eq; - use crate::buf::rope::Rope; - - #[test] - fn buf_eq_returns_false_for_different_lengths() { - assert!(!buf_eq(b"Hello", b"Wor")); - assert!(!buf_eq(b"", b"Hello")); - assert!(!buf_eq(b"Hello", b"")); - } - - #[test] - fn buf_eq_returns_false_for_same_length_buf_different_bytes() { - assert!(!buf_eq(b"Hello", b"World")); - assert!(!buf_eq(b"Hello", b"HellO")); - } - - #[test] - fn buf_eq_returns_true_for_empty_buffers() { - assert!(buf_eq(b"", b"")); - } - - #[test] - fn buf_eq_returns_true_for_equal_buffers() { - assert!(buf_eq(b"Hello", b"Hello")); - } - - #[test] - #[ignore = "Rope not fully implemented"] - fn buf_eq_returns_true_for_same_contents_but_differently_sized_chunks() { - let mut buf1 = Rope::with_capacity(2); - buf1.push(b"Hello" as &[u8]); - buf1.push(b" World" as &[u8]); - let mut buf2 = Rope::with_capacity(2); - buf2.push(b"Hel" as &[u8]); - buf2.push(b"lo World" as &[u8]); - assert!(buf_eq(buf1, buf2)); - } - - #[test] - #[ignore = "Rope not fully implemented"] - fn buf_eq_returns_true_even_if_with_empty_chunks() { - let mut buf1 = Rope::with_capacity(5); - buf1.push(b"" as &[u8]); - buf1.push(b"Hello" as &[u8]); - buf1.push(b"" as &[u8]); - buf1.push(b"World" as &[u8]); - buf1.push(b"" as &[u8]); - let mut buf2 = Rope::with_capacity(2); - buf2.push(b"Hello" as &[u8]); - buf2.push(b"World" as &[u8]); - assert!(buf_eq(buf1, buf2)); - } -} diff --git a/skunk-cli/Cargo.toml b/skunk-cli/Cargo.toml index 3f5d600..f57af4b 100644 --- a/skunk-cli/Cargo.toml +++ b/skunk-cli/Cargo.toml @@ -29,7 +29,7 @@ features = ["trigger"] [dependencies.byst] #version = "0.1.0" -path = "../byst" +git = "https://github.com/FeraeLabs/byst.git" [dependencies] axum = { version = "0.7.5", features = ["ws", "macros"] } diff --git a/skunk/Cargo.toml b/skunk/Cargo.toml index a264660..7dffd5a 100644 --- a/skunk/Cargo.toml +++ b/skunk/Cargo.toml @@ -41,7 +41,7 @@ pcap = ["dep:libc"] [dependencies.byst] #version = "0.1.0" -path = "../byst" +git = "https://github.com/FeraeLabs/byst.git" [dependencies.skunk-macros] path = "../skunk-macros"