diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 90a646e..3dae3d3 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,4 +1,4 @@ -on: [push] +on: [push, pull_request] name: CI @@ -51,7 +51,6 @@ jobs: config: - { os: ubuntu-latest, target: 'x86_64-unknown-linux-gnu' } - { os: macos-latest, target: 'x86_64-apple-darwin' } - - { os: windows-latest, target: 'x86_64-pc-windows-msvc' } steps: - uses: actions/checkout@v2 @@ -74,7 +73,6 @@ jobs: config: - { os: ubuntu-latest, target: 'x86_64-unknown-linux-gnu' } - { os: macos-latest, target: 'x86_64-apple-darwin' } - - { os: windows-latest, target: 'x86_64-pc-windows-msvc' } steps: - uses: actions/checkout@v2 @@ -97,7 +95,6 @@ jobs: config: - { os: ubuntu-latest, target: 'x86_64-unknown-linux-gnu' } - { os: macos-latest, target: 'x86_64-apple-darwin' } - - { os: windows-latest, target: 'x86_64-pc-windows-msvc' } steps: - uses: actions/checkout@v2 @@ -120,7 +117,6 @@ jobs: config: - { os: ubuntu-latest, target: 'x86_64-unknown-linux-gnu' } - { os: macos-latest, target: 'x86_64-apple-darwin' } - - { os: windows-latest, target: 'x86_64-pc-windows-msvc' } steps: - uses: actions/checkout@v2 @@ -142,7 +138,6 @@ jobs: config: - { os: ubuntu-latest, target: 'x86_64-unknown-linux-gnu' } - { os: macos-latest, target: 'x86_64-apple-darwin' } - - { os: windows-latest, target: 'x86_64-pc-windows-msvc' } steps: - uses: actions/checkout@v2 diff --git a/Cargo.toml b/Cargo.toml index d6b7024..e8fba05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "structdiff" -version = "0.7.3" +version = "0.7.4" edition = "2021" license = "Apache-2.0 OR MIT" repository = "https://github.com/knickish/structdiff" @@ -13,7 +13,7 @@ rust-version = "1.82.0" nanoserde = { version = "^0.1.37", optional = true } rustc-hash = { version = "1.1.0", optional = true } serde = { version = "^1.0.0", optional = true, features = ["derive"] } -structdiff-derive = { path = "derive", version = "=0.7.3" } +structdiff-derive = { path = "derive", version = "=0.7.4" } [features] "default" = [] diff --git a/benchmarks/Cargo.toml b/benchmarks/Cargo.toml index d22b6ff..2304642 100644 --- a/benchmarks/Cargo.toml +++ b/benchmarks/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] assert_unordered = "0.3.5" -structdiff = { path = "..", features = ["serde", "debug_diffs", "__rope_benchmarks"] } +structdiff = { path = "..", features = ["serde", "debug_diffs"] } nanorand = { version = "0.7.0" } diff-struct = { version = "0.5.3", optional = true} serde = { version = "^1.0.0", features = ["derive"] } diff --git a/derive/Cargo.toml b/derive/Cargo.toml index b613056..31e08f9 100644 --- a/derive/Cargo.toml +++ b/derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "structdiff-derive" -version = "0.7.3" +version = "0.7.4" authors = ["Makepad ", "Fedor ", "Kirk TokenStream { - let owned_derives: String = vec![ + let owned_derives: String = [ #[cfg(feature = "debug_diffs")] "core::fmt::Debug", "Clone", @@ -85,7 +85,7 @@ pub(crate) fn derive_struct_diff_struct(struct_: &Struct) -> TokenStream { ] .join(", "); - let ref_derives: String = vec![ + let ref_derives: String = [ #[cfg(feature = "debug_diffs")] "core::fmt::Debug", "Clone", @@ -112,10 +112,8 @@ pub(crate) fn derive_struct_diff_struct(struct_: &Struct) -> TokenStream { let enum_name = match exposed.clone() { Some(Some(name)) => name, - Some(None) => String::from(struct_.name.as_ref().unwrap().to_string() + "StructDiffEnum"), - _ => String::from( - "__".to_owned() + struct_.name.as_ref().unwrap().as_str() + "StructDiffEnum", - ), + Some(None) => struct_.name.as_ref().unwrap().to_string() + "StructDiffEnum", + _ => "__".to_owned() + struct_.name.as_ref().unwrap().as_str() + "StructDiffEnum", }; let struct_generics_names_hash: HashSet = @@ -133,7 +131,7 @@ pub(crate) fn derive_struct_diff_struct(struct_: &Struct) -> TokenStream { let field_name = field.field_name.as_ref().unwrap(); used_generics.extend(struct_.generics.iter().filter(|x| x.full() == field.ty.ident.path(&field.ty, false))); - let to_add = struct_.generics.iter().filter(|x| field.ty.wraps().iter().find(|&wrapped_type| &x.full() == wrapped_type ).is_some()); + let to_add = struct_.generics.iter().filter(|x| field.ty.wraps().iter().any(|wrapped_type| &x.full() == wrapped_type)); used_generics.extend(to_add); used_generics.extend(get_used_lifetimes(&field.ty).into_iter().filter_map(|x| match struct_generics_names_hash.contains(&x) { @@ -280,9 +278,9 @@ pub(crate) fn derive_struct_diff_struct(struct_: &Struct) -> TokenStream { }; }, (true, None, false) => { // Recurse inwards and generate a Vec instead of cloning the entire thing - let typename = format!("__{}StructDiffVec", field_name); + let typename = format!("__{field_name}StructDiffVec"); l!(owned_type_aliases, "///Generated aliases from StructDiff\n type {} = Vec<<{} as StructDiff>::Diff>;", typename, field.ty.full()); - let typename_ref = format!("__{}StructDiffRefVec<'__diff_target>", field_name); + let typename_ref = format!("__{field_name}StructDiffRefVec<'__diff_target>"); l!(ref_type_aliases, "///Generated aliases from StructDiff\n type {} = Vec<<{} as StructDiff>::DiffRef<'__diff_target>>;", typename_ref, field.ty.full()); l!(diff_enum_body, " {}({}),", field_name, typename); @@ -352,92 +350,68 @@ pub(crate) fn derive_struct_diff_struct(struct_: &Struct) -> TokenStream { }; }, (true, None, true) => { // Recurse inwards and generate an Option> instead of cloning the entire thing - let typename = format!("__{}StructDiffVec", field_name); + let typename = format!("__{field_name}StructDiffVec"); l!(owned_type_aliases, "///Generated aliases from StructDiff\n type {} = Vec<<{} as StructDiff>::Diff>;", typename, - field.ty.wraps.as_ref().expect("Option must wrap a type").get(0).expect("Option must wrap a type").full() + field.ty.wraps.as_ref().expect("Option must wrap a type").first().expect("Option must wrap a type").full() ); - let ref_typename = format!("__{}StructDiffRefVec<'__diff_target>", field_name); + let ref_typename = format!("__{field_name}StructDiffRefVec<'__diff_target>"); l!( ref_type_aliases, "///Generated aliases from StructDiff\n type {} = Vec<<{} as StructDiff>::DiffRef<'__diff_target>>;", ref_typename, - field.ty.wraps.as_ref().expect("Option must wrap a type").get(0).expect("Option must wrap a type").full() + field.ty.wraps.as_ref().expect("Option must wrap a type").first().expect("Option must wrap a type").full() ); l!(diff_enum_body, " {}(Option<{}>),", field_name, typename); - l!(diff_enum_body, " {}_full({}),", field_name, field.ty.wraps.as_ref().expect("Option must wrap a type").get(0).expect("Option must wrap a type").full()); + l!(diff_enum_body, " {}_full({}),", field_name, field.ty.wraps.as_ref().expect("Option must wrap a type").first().expect("Option must wrap a type").full()); l!(diff_ref_enum_body, " {}(Option<{}>),", field_name, ref_typename); - l!(diff_ref_enum_body, " {}_full(&'__diff_target {}),", field_name, field.ty.wraps.as_ref().expect("Option must wrap a type").get(0).expect("Option must wrap a type").full()); + l!(diff_ref_enum_body, " {}_full(&'__diff_target {}),", field_name, field.ty.wraps.as_ref().expect("Option must wrap a type").first().expect("Option must wrap a type").full()); let apply_single_body_partial = format!( - "Self::Diff::{}(Some(__{})) => if let Some(ref mut inner) = self.{} {{ - inner.apply_mut(__{}); - }},", - field_name, - index, - field_name, - index + "Self::Diff::{field_name}(Some(__{index})) => if let Some(ref mut inner) = self.{field_name} {{ + inner.apply_mut(__{index}); + }}," ); let apply_single_body_full = format!( - "Self::Diff::{}_full(__{}) => self.{} = Some(__{}),", - field_name, - index, - field_name, - index + "Self::Diff::{field_name}_full(__{index}) => self.{field_name} = Some(__{index})," ); let apply_single_body_none = format!( - "Self::Diff::{}(None) => self.{} = None,", - field_name, - field_name + "Self::Diff::{field_name}(None) => self.{field_name} = None," ); let diff_body_fragment = format!( - "match (&self.{}, &updated.{}) {{ - (Some(val1), Some(val2)) if &val1 != &val2 => diffs.push(Self::Diff::{}(Some(val1.diff(&val2)))), - (Some(val1), None) => diffs.push(Self::Diff::{}(None)), - (None, Some(val2)) => diffs.push(Self::Diff::{}_full(val2.clone())), + "match (&self.{field_name}, &updated.{field_name}) {{ + (Some(val1), Some(val2)) if &val1 != &val2 => diffs.push(Self::Diff::{field_name}(Some(val1.diff(&val2)))), + (Some(val1), None) => diffs.push(Self::Diff::{field_name}(None)), + (None, Some(val2)) => diffs.push(Self::Diff::{field_name}_full(val2.clone())), _ => (), - }};", - field_name, - field_name, - field_name, - field_name, - field_name + }};" ); let diff_body_fragment_ref = format!( - "match (&self.{}, &updated.{}) {{ - (Some(val1), Some(val2)) if &val1 != &val2 => diffs.push(Self::DiffRef::{}(Some(val1.diff_ref(&val2)))), - (Some(val1), None) => diffs.push(Self::DiffRef::{}(None)), - (None, Some(val2)) => diffs.push(Self::DiffRef::{}_full(&val2)), + "match (&self.{field_name}, &updated.{field_name}) {{ + (Some(val1), Some(val2)) if &val1 != &val2 => diffs.push(Self::DiffRef::{field_name}(Some(val1.diff_ref(&val2)))), + (Some(val1), None) => diffs.push(Self::DiffRef::{field_name}(None)), + (None, Some(val2)) => diffs.push(Self::DiffRef::{field_name}_full(&val2)), _ => (), - }};", - field_name, - field_name, - field_name, - field_name, - field_name + }};" ); #[cfg(feature = "generated_setters")] { let diff_body_fragment_setter = format!( - "match (&self.{}, &value) {{ - (Some(val1), Some(val2)) if &val1 != &val2 => ::Diff::{}(Some(val1.diff(&val2))), - (Some(val1), None) => ::Diff::{}(None), - (None, Some(val2)) => ::Diff::{}_full(val2.clone()), + "match (&self.{field_name}, &value) {{ + (Some(val1), Some(val2)) if &val1 != &val2 => ::Diff::{field_name}(Some(val1.diff(&val2))), + (Some(val1), None) => ::Diff::{field_name}(None), + (None, Some(val2)) => ::Diff::{field_name}_full(val2.clone()), _ => return None, - }};", - field_name, - field_name, - field_name, - field_name + }};" ); match (all_setters, attrs_setter(&field.attributes)) { (_, (_, true, _)) => (), @@ -927,7 +901,7 @@ pub(crate) fn derive_struct_diff_struct(struct_: &Struct) -> TokenStream { let start = "\n#[serde(bound = \""; let mid = used_generics .iter() - .filter(|gen| !matches!(gen, Generic::Lifetime { .. } | Generic::ConstGeneric { .. })) + .filter(|gen| !matches!(gen, Generic::Lifetime { .. } | Generic::Const { .. })) .map(|x| { format!( "{}: serde::Serialize + serde::de::DeserializeOwned", @@ -937,7 +911,7 @@ pub(crate) fn derive_struct_diff_struct(struct_: &Struct) -> TokenStream { .collect::>() .join(", "); let end = "\")]"; - vec![start, &mid, end].join("") + [start, &mid, end].join("") }; #[cfg(not(feature = "serde"))] let serde_bound = ""; @@ -959,7 +933,7 @@ pub(crate) fn derive_struct_diff_struct(struct_: &Struct) -> TokenStream { .generics .iter() .filter(|gen| !matches!(gen, Generic::WhereBounded { .. })) - .map(|gen| Generic::ident_with_const(gen)) + .map(Generic::ident_with_const) .collect::>() .join(", "), struct_ @@ -970,7 +944,7 @@ pub(crate) fn derive_struct_diff_struct(struct_: &Struct) -> TokenStream { .generics .iter() .filter(|gen| !matches!(gen, Generic::WhereBounded { .. })) - .map(|gen| Generic::ident_only(gen)) + .map(Generic::ident_only) .collect::>() .join(", "), struct_ @@ -978,7 +952,7 @@ pub(crate) fn derive_struct_diff_struct(struct_: &Struct) -> TokenStream { .iter() .filter(|gen| !matches!( gen, - Generic::ConstGeneric { .. } | Generic::WhereBounded { .. } + Generic::Const { .. } | Generic::WhereBounded { .. } )) .map(|gen| Generic::full_with_const( gen, @@ -1095,45 +1069,45 @@ pub(crate) fn derive_struct_diff_struct(struct_: &Struct) -> TokenStream { diff_ref_enum_body = diff_ref_enum_body, ref_into_owned_body = ref_into_owned_body, apply_single_body = apply_single_body, - owned_enum_def_generics = format!( + owned_enum_def_generics = format_args!( "<{}>", used_generics .iter() .filter(|gen| !matches!(gen, Generic::WhereBounded { .. })) - .map(|gen| Generic::ident_with_const(gen)) + .map(Generic::ident_with_const) .collect::>() .join(", ") ), - ref_enum_def_generics = format!( + ref_enum_def_generics = format_args!( "<{}>", std::iter::once(String::from("'__diff_target")).chain( used_generics .iter() .filter(|gen| !matches!(gen, Generic::WhereBounded { .. })) - .map(|gen| Generic::ident_with_const(gen))) + .map(Generic::ident_with_const)) .collect::>() .join(", ") ), - owned_enum_where_bounds = format!( + owned_enum_where_bounds = format_args!( "{}", used_generics .iter() .filter(|gen| !matches!( gen, - Generic::WhereBounded { .. } | Generic::ConstGeneric { .. } + Generic::WhereBounded { .. } | Generic::Const { .. } )) .filter(|g| Generic::has_where_bounds(g, false, true)) .map(|gen| Generic::full_with_const(gen, get_used_generic_bounds(), &[], true)) .collect::>() .join(",\n") ), - ref_enum_where_bounds =format!( + ref_enum_where_bounds =format_args!( "{}", used_generics .iter() .filter(|gen| !matches!( gen, - Generic::WhereBounded { .. } | Generic::ConstGeneric { .. } + Generic::WhereBounded { .. } | Generic::Const { .. } )) .filter(|g| Generic::has_where_bounds(g, true, true)) .map(|gen| Generic::full_with_const(gen, get_used_generic_bounds_ref(), &["\'__diff_target"], true)) @@ -1141,59 +1115,59 @@ pub(crate) fn derive_struct_diff_struct(struct_: &Struct) -> TokenStream { .collect::>() .join(",\n") ), - into_impl_where_bounds = format!( + into_impl_where_bounds = format_args!( "{}", used_generics .iter() .filter(|gen| !matches!( gen, - Generic::WhereBounded { .. } | Generic::ConstGeneric { .. } + Generic::WhereBounded { .. } | Generic::Const { .. } )) .filter(|g| Generic::has_where_bounds(g, true, true)) .map(|gen| Generic::full_with_const(gen, get_used_generic_bounds(), &["\'__diff_target"], true)) .collect::>() .join(",\n") ), - diff_ref_type_where_bounds = format!( + diff_ref_type_where_bounds = format_args!( "{}", struct_ .generics .iter() .filter(|gen| !matches!( gen, - Generic::WhereBounded { .. } | Generic::ConstGeneric { .. } + Generic::WhereBounded { .. } | Generic::Const { .. } )) .filter(|g| Generic::has_where_bounds(g, true, true)) .map(|gen| Generic::full_with_const(gen, &[], &["\'__diff_target"], true)) .collect::>() .join(",\n") ), - impl_generics = format!( + impl_generics = format_args!( "<{}>", struct_ .generics .iter() .filter(|gen| !matches!(gen, Generic::WhereBounded { .. })) - .map(|gen| Generic::ident_with_const(gen)) + .map(Generic::ident_with_const) .collect::>() .join(", ") ), - struct_generics = format!( + struct_generics = format_args!( "<{}>", struct_ .generics .iter() .filter(|gen| !matches!(gen, Generic::WhereBounded { .. })) - .map(|gen| Generic::ident_only(gen)) + .map(Generic::ident_only) .collect::>() .join(", ") ), - struct_where_bounds = format!( + struct_where_bounds = format_args!( "{}", struct_ .generics .iter() - .filter(|gen| !matches!(gen, Generic::ConstGeneric { .. } | Generic::WhereBounded { .. })) + .filter(|gen| !matches!(gen, Generic::Const { .. } | Generic::WhereBounded { .. })) .filter(|g| Generic::has_where_bounds(g, false, true)) .map(|gen| Generic::full_with_const(gen, get_used_generic_bounds(), &[], true)) .collect::>().into_iter().chain(struct_ @@ -1203,22 +1177,22 @@ pub(crate) fn derive_struct_diff_struct(struct_: &Struct) -> TokenStream { .map(|gen| Generic::full_with_const(gen, &[], &[], true)).collect::>().into_iter()).collect::>() .join(",\n") ), - owned_enum_impl_generics = format!( + owned_enum_impl_generics = format_args!( "<{}>", used_generics .iter() .filter(|gen| !matches!(gen, Generic::WhereBounded { .. })) - .map(|gen| Generic::ident_only(gen)) + .map(Generic::ident_only) .collect::>() .join(", ") ), - ref_enum_impl_generics = format!( + ref_enum_impl_generics = format_args!( "<{}>", std::iter::once(String::from("'__diff_target")).chain( used_generics .iter() .filter(|gen| !matches!(gen, Generic::WhereBounded { .. })) - .map(|gen| Generic::ident_only(gen))) + .map(Generic::ident_only)) .collect::>() .join(", ") ), @@ -1229,7 +1203,7 @@ pub(crate) fn derive_struct_diff_struct(struct_: &Struct) -> TokenStream { } pub(crate) fn derive_struct_diff_enum(enum_: &Enum) -> TokenStream { - let owned_derives: String = vec![ + let owned_derives: String = [ #[cfg(feature = "debug_diffs")] "core::fmt::Debug", "Clone", @@ -1244,7 +1218,7 @@ pub(crate) fn derive_struct_diff_enum(enum_: &Enum) -> TokenStream { ] .join(", "); - let ref_derives: String = vec![ + let ref_derives: String = [ #[cfg(feature = "debug_diffs")] "core::fmt::Debug", "Clone", @@ -1269,8 +1243,8 @@ pub(crate) fn derive_struct_diff_enum(enum_: &Enum) -> TokenStream { let enum_name = match exposed.clone() { Some(Some(name)) => name, - Some(None) => String::from(enum_.name.clone() + "StructDiffEnum"), - _ => String::from("__".to_owned() + &enum_.name + "StructDiffEnum"), + Some(None) => enum_.name.clone() + "StructDiffEnum", + _ => "__".to_owned() + &enum_.name + "StructDiffEnum", }; let ref_into_owned_body = format!( @@ -1284,25 +1258,24 @@ pub(crate) fn derive_struct_diff_enum(enum_: &Enum) -> TokenStream { panic!("Enum variants may not be skipped"); }; - enum_.variants.iter().enumerate().for_each(|(_, field)| { + enum_.variants.iter().for_each(|field| { let field_name = field.field_name.as_ref().unwrap(); let ty = &field.ty; used_generics.extend( enum_ .generics .iter() - .filter(|x| x.full() == ty.ident.path(&ty, false)), + .filter(|x| x.full() == ty.ident.path(ty, false)), ); let to_add = enum_.generics.iter().filter(|x| { ty.wraps() .iter() - .find(|&wrapped_type| &x.full() == wrapped_type) - .is_some() + .any(|wrapped_type| &x.full() == wrapped_type) }); used_generics.extend(to_add); - used_generics.extend(get_used_lifetimes(&ty).into_iter().filter_map(|x| { + used_generics.extend(get_used_lifetimes(ty).into_iter().filter_map(|x| { match struct_generics_names_hash.contains(&x) { true => Some( enum_ @@ -1315,7 +1288,7 @@ pub(crate) fn derive_struct_diff_enum(enum_: &Enum) -> TokenStream { } })); - for val in get_array_lens(&ty) { + for val in get_array_lens(ty) { if let Some(const_gen) = enum_.generics.iter().find(|x| x.full() == val) { used_generics.push(const_gen) } @@ -1429,7 +1402,7 @@ pub(crate) fn derive_struct_diff_enum(enum_: &Enum) -> TokenStream { let start = "\n#[serde(bound = \""; let mid = used_generics .iter() - .filter(|gen| !matches!(gen, Generic::Lifetime { .. } | Generic::ConstGeneric { .. })) + .filter(|gen| !matches!(gen, Generic::Lifetime { .. } | Generic::Const { .. })) .map(|x| { format!( "{}: serde::Serialize + serde::de::DeserializeOwned", @@ -1439,7 +1412,7 @@ pub(crate) fn derive_struct_diff_enum(enum_: &Enum) -> TokenStream { .collect::>() .join(", "); let end = "\")]"; - vec![start, &mid, end].join("") + [start, &mid, end].join("") }; #[cfg(not(feature = "serde"))] let serde_bound = ""; @@ -1533,49 +1506,49 @@ pub(crate) fn derive_struct_diff_enum(enum_: &Enum) -> TokenStream { ref_into_owned_body = ref_into_owned_body, enum_name = enum_name, apply_single_body = apply_single_body, - owned_enum_def_generics = format!( + owned_enum_def_generics = format_args!( "<{}>", enum_ .generics .iter() .filter(|gen| !matches!(gen, Generic::WhereBounded { .. })) - .map(|gen| Generic::ident_with_const(gen)) + .map(Generic::ident_with_const) .collect::>() .join(", ") ), - ref_enum_def_generics = format!( + ref_enum_def_generics = format_args!( "<{}>", std::iter::once(String::from("'__diff_target")).chain( enum_ .generics .iter() .filter(|gen| !matches!(gen, Generic::WhereBounded { .. })) - .map(|gen| Generic::ident_with_const(gen))) + .map(Generic::ident_with_const)) .collect::>() .join(", ") ), - enum_where_bounds = format!( + enum_where_bounds = format_args!( "{}", enum_ .generics .iter() .filter(|gen| !matches!( gen, - Generic::ConstGeneric { .. } + Generic::Const { .. } )) .filter(|g| Generic::has_where_bounds(g, false, true)) .map(|gen| Generic::full_with_const(gen, get_used_generic_bounds(), &[], true)) .collect::>() .join(",\n") ), - ref_enum_where_bounds = format!( + ref_enum_where_bounds = format_args!( "{}", enum_ .generics .iter() .filter(|gen| !matches!( gen, - Generic::ConstGeneric { .. } + Generic::Const { .. } )) .filter(|g| Generic::has_where_bounds(g, true, true)) .map(|gen| Generic::full_with_const(gen, get_used_generic_bounds_ref(), &["\'__diff_target"], true)) @@ -1583,60 +1556,60 @@ pub(crate) fn derive_struct_diff_enum(enum_: &Enum) -> TokenStream { .collect::>() .join(",\n") ), - into_impl_where_bounds = format!( + into_impl_where_bounds = format_args!( "{}", enum_ .generics .iter() .filter(|gen| !matches!( gen, - Generic::ConstGeneric { .. } + Generic::Const { .. } )) .filter(|g| Generic::has_where_bounds(g, true, true)) .map(|gen| Generic::full_with_const(gen, get_used_generic_bounds_ref(), &["\'__diff_target"], true)) .collect::>() .join(",\n") ), - diff_ref_type_where_bounds = format!( + diff_ref_type_where_bounds = format_args!( "{}", enum_ .generics .iter() .filter(|gen| !matches!( gen, - Generic::WhereBounded { .. } | Generic::ConstGeneric { .. } + Generic::WhereBounded { .. } | Generic::Const { .. } )) .filter(|g| Generic::has_where_bounds(g, true, true)) .map(|gen| Generic::full_with_const(gen, &[], &["\'__diff_target"], true)) .collect::>() .join(",\n") ), - impl_generics = format!( + impl_generics = format_args!( "<{}>", enum_ .generics .iter() .filter(|gen| !matches!(gen, Generic::WhereBounded { .. })) - .map(|gen| Generic::ident_with_const(gen)) + .map(Generic::ident_with_const) .collect::>() .join(", ") ), - struct_generics = format!( + struct_generics = format_args!( "<{}>", enum_ .generics .iter() .filter(|gen| !matches!(gen, Generic::WhereBounded { .. })) - .map(|gen| Generic::ident_only(gen)) + .map(Generic::ident_only) .collect::>() .join(", ") ), - struct_where_bounds = format!( + struct_where_bounds = format_args!( "{}", enum_ .generics .iter() - .filter(|gen| !matches!(gen, Generic::ConstGeneric { .. } | Generic::WhereBounded { .. })) + .filter(|gen| !matches!(gen, Generic::Const { .. } | Generic::WhereBounded { .. })) .map(|gen| Generic::full_with_const(gen, get_used_generic_bounds(), &[],true)) .collect::>().into_iter().chain(enum_ .generics @@ -1645,24 +1618,24 @@ pub(crate) fn derive_struct_diff_enum(enum_: &Enum) -> TokenStream { .map(|gen| Generic::full_with_const(gen, &[], &[], true)).collect::>().into_iter()).collect::>() .join(",\n") ), - enum_impl_generics = format!( + enum_impl_generics = format_args!( "<{}>", enum_ .generics .iter() .filter(|gen| !matches!(gen, Generic::WhereBounded { .. })) - .map(|gen| Generic::ident_only(gen)) + .map(Generic::ident_only) .collect::>() .join(", ") ), - ref_enum_impl_generics = format!( + ref_enum_impl_generics = format_args!( "<{}>", std::iter::once(String::from("'__diff_target")).chain( enum_ .generics .iter() .filter(|gen| !matches!(gen, Generic::WhereBounded { .. })) - .map(|gen| Generic::ident_only(gen))) + .map(Generic::ident_only)) .collect::>() .join(", ") ), diff --git a/derive/src/parse.rs b/derive/src/parse.rs index 75440fe..3ccd55c 100644 --- a/derive/src/parse.rs +++ b/derive/src/parse.rs @@ -79,7 +79,7 @@ pub enum Category { UnNamed, Object { is_dyn: bool, - trait_names: Vec>, + trait_names: Vec, }, Associated { base: Box, @@ -106,12 +106,12 @@ pub struct Type { #[derive(Debug, Clone, PartialEq, Hash, Eq)] pub enum Generic { - ConstGeneric { + Const { name: String, _type: Type, default: Option, }, - Generic { + Regular { name: String, default: Option, bounds: Vec, @@ -175,8 +175,8 @@ impl Data { impl Generic { pub fn full(&self) -> String { match &self { - Generic::ConstGeneric { name, .. } => name.clone(), - Generic::Generic { name, .. } => name.clone(), + Generic::Const { name, .. } => name.clone(), + Generic::Regular { name, .. } => name.clone(), Generic::Lifetime { name, .. } => name.clone(), Generic::WhereBounded { name, .. } => name.clone(), } @@ -191,7 +191,7 @@ impl Generic { fn const_prefix(&self) -> &str { match &self { - Generic::ConstGeneric { .. } => "const ", + Generic::Const { .. } => "const ", _ => "", } } @@ -202,7 +202,7 @@ impl Generic { pub fn ident_with_const(&self) -> String { match &self { - Generic::ConstGeneric { .. } => self.full_with_const(&[], &[], true), + Generic::Const { .. } => self.full_with_const(&[], &[], true), _ => format!("{}{}", self.lifetime_prefix(), self.full()), } } @@ -216,16 +216,16 @@ impl Generic { let bounds = match (bounds, &self) { (true, Generic::Lifetime { .. }) => { let mut bounds = self.get_bounds(); - bounds.extend(extra_lifetime_bounds.into_iter().map(ToString::to_string)); + bounds.extend(extra_lifetime_bounds.iter().map(ToString::to_string)); bounds.join(" + ") } (true, _) => { let mut bounds = self.get_bounds(); - bounds.extend(extra_ty_bounds.into_iter().map(ToString::to_string)); - bounds.extend(extra_lifetime_bounds.into_iter().map(ToString::to_string)); + bounds.extend(extra_ty_bounds.iter().map(ToString::to_string)); + bounds.extend(extra_lifetime_bounds.iter().map(ToString::to_string)); bounds.join(" + ") } - (_, Generic::ConstGeneric { .. }) => self.get_bounds().join(" + "), + (_, Generic::Const { .. }) => self.get_bounds().join(" + "), (false, _) => String::new(), }; match bounds.is_empty() { @@ -249,7 +249,7 @@ impl Generic { pub fn full_with_const_and_default(&self, extra_bounds: &[&str], bounds: bool) -> String { let bounds = match (bounds, &self) { (true, Generic::Lifetime { .. }) => String::new(), - (true, _) | (false, Generic::ConstGeneric { .. }) => { + (true, _) | (false, Generic::Const { .. }) => { let mut bounds = self.get_bounds().join(" + "); if !extra_bounds.is_empty() { if bounds.is_empty() { @@ -283,7 +283,7 @@ impl Generic { pub fn has_where_bounds(&self, lifetimes_bound: bool, extra_ty_bounds: bool) -> bool { match &self { - Generic::Generic { bounds, .. } => { + Generic::Regular { bounds, .. } => { !bounds.is_empty() || lifetimes_bound || extra_ty_bounds } Generic::Lifetime { bounds, .. } => !bounds.is_empty() || lifetimes_bound, @@ -294,8 +294,8 @@ impl Generic { fn get_bounds(&self) -> Vec { match &self { - Generic::ConstGeneric { _type, .. } => vec![format!("{}", _type.full())], - Generic::Generic { bounds, .. } => bounds.iter().map(Type::full).collect(), + Generic::Const { _type, .. } => vec![format!("{}", _type.full())], + Generic::Regular { bounds, .. } => bounds.iter().map(Type::full).collect(), Generic::Lifetime { bounds, .. } => { bounds.iter().map(|x| format!("'{}", x.ident)).collect() } @@ -306,13 +306,13 @@ impl Generic { #[cfg(unused)] fn get_default(&self) -> String { match &self { - Generic::ConstGeneric { + Generic::Const { default: Some(def), .. } => match def { ConstValType::Value(v) => format!("= {}", v), ConstValType::Named(v) => format!("= {}", v.full()), }, - Generic::Generic { + Generic::Regular { default: Some(def), .. } => format!("= {}", def.full()), _ => String::new(), @@ -392,7 +392,7 @@ impl Category { parent.wraps.as_ref().unwrap()[0].full(), is.full() ), - Category::Lifetime { path } => format!("\'{}", path), + Category::Lifetime { path } => format!("\'{path}"), Category::Fn { category, args, @@ -404,12 +404,12 @@ impl Category { .map(|x| format!(" -> {}", x.full())) .unwrap_or_default(); match category { - FnType::Bare => format!("fn({}){}", arg_str, return_str), + FnType::Bare => format!("fn({arg_str}){return_str}"), FnType::Closure { reusable, fn_mut } => match fn_mut { - true => format!("FnMut({}){}", arg_str, return_str), + true => format!("FnMut({arg_str}){return_str}"), false => match reusable { - true => format!("Fn({}){}", arg_str, return_str), - false => format!("FnOnce({}){}", arg_str, return_str), + true => format!("Fn({arg_str}){return_str}"), + false => format!("FnOnce({arg_str}){return_str}"), }, }, } @@ -445,7 +445,7 @@ impl Type { }, None => String::default(), }; - base.push_str(&self.ident.path(&self, false)); + base.push_str(&self.ident.path(self, false)); base } @@ -469,12 +469,12 @@ impl Type { }, None => String::default(), }; - base.push_str(&self.ident.path(&self, false)); + base.push_str(&self.ident.path(self, false)); if let (Some(wrapped), Category::Named { .. }) = (&self.wraps, &self.ident) { base.push('<'); base.push_str( wrapped - .into_iter() + .iter() .map(|x| x.full()) .collect::>() .join(",") @@ -495,7 +495,7 @@ pub fn next_visibility_modifier( source: &mut Peekable>, ) -> Option { if let Some(TokenTree::Ident(ident)) = source.peek() { - if format!("{}", ident) == "pub" { + if format!("{ident}") == "pub" { source.next(); // skip (crate) and alike @@ -509,17 +509,17 @@ pub fn next_visibility_modifier( } } - return None; + None } pub fn next_punct(source: &mut Peekable>) -> Option { if let Some(TokenTree::Punct(punct)) = source.peek() { - let punct = format!("{}", punct); + let punct = format!("{punct}"); source.next(); return Some(punct); } - return None; + None } pub fn next_exact_punct( @@ -527,14 +527,14 @@ pub fn next_exact_punct( pattern: &str, ) -> Option { if let Some(TokenTree::Punct(punct)) = source.peek() { - let punct = format!("{}", punct); + let punct = format!("{punct}"); if punct == pattern { source.next(); return Some(punct); } } - return None; + None } pub fn next_literal(source: &mut Peekable>) -> Option { @@ -550,7 +550,7 @@ pub fn next_literal(source: &mut Peekable>) -> O return Some(literal); } - return None; + None } pub fn next_eof(source: &mut Peekable) -> Option<()> { @@ -563,7 +563,7 @@ pub fn next_eof(source: &mut Peekable) -> Option<()> { pub fn next_ident(source: &mut Peekable>) -> Option { if let Some(TokenTree::Ident(ident)) = source.peek() { - let ident = format!("{}", ident); + let ident = format!("{ident}"); source.next(); Some(ident) } else { @@ -601,7 +601,7 @@ pub fn next_lifetime>(source: &mut Peekable) -> }) } -fn next_type + Clone>(mut source: &mut Peekable) -> Option { +fn next_type + Clone>(source: &mut Peekable) -> Option { fn as_associated_definition + Clone>( source: &mut Peekable, ) -> Option { @@ -627,11 +627,11 @@ fn next_type + Clone>(mut source: &mut Peekable None } pub fn next_array + Clone>( - mut source: &mut Peekable, + source: &mut Peekable, ) -> Option { - let next = next_type(&mut source).expect("Must be type after array declaration"); + let next = next_type(source).expect("Must be type after array declaration"); - let Some(_) = next_exact_punct(&mut source, ";") else { + let Some(_) = next_exact_punct(source, ";") else { // This is an unbounded array, legal at end for unsized types return Some(Type { ident: Category::Array { @@ -684,7 +684,7 @@ fn next_type + Clone>(mut source: &mut Peekable let mut path = "(".to_owned(); while let Some(next_ty) = next_type(source) { wraps.push(next_ty.clone()); - path.push_str(&format!("{}", next_ty.full())); + path.push_str(&next_ty.full().to_string()); if next_exact_punct(source, ",").is_none() { break; } @@ -701,7 +701,7 @@ fn next_type + Clone>(mut source: &mut Peekable as_other: None, }; - return Some(tuple_type); + Some(tuple_type) } pub fn next_function_like + Clone>( @@ -741,14 +741,14 @@ fn next_type + Clone>(mut source: &mut Peekable let mut base = ret .iter() .filter_map(|x| x.wraps.as_ref()) - .cloned() .flatten() + .cloned() .collect::>(); base.extend( args.iter() .filter_map(|x| x.wraps.as_ref()) - .cloned() - .flatten(), + .flatten() + .cloned(), ); Some(base) } else { @@ -766,7 +766,7 @@ fn next_type + Clone>(mut source: &mut Peekable } } - let Some(TokenTree::Ident(ident)) = source.peek().clone() else { + let Some(TokenTree::Ident(ident)) = source.peek() else { return None; }; let true = matches!(ident.to_string().as_str(), "fn" | "FnOnce" | "FnMut" | "Fn") else { @@ -792,8 +792,8 @@ fn next_type + Clone>(mut source: &mut Peekable let mut base = ret .iter() .filter_map(|x| x.wraps.as_ref()) - .cloned() .flatten() + .cloned() .collect::>(); base.extend_from_slice(args.wraps.clone().unwrap_or_default().as_ref()); Some(base) @@ -829,13 +829,10 @@ fn next_type + Clone>(mut source: &mut Peekable }; match source.next().unwrap().to_string().as_str() { "impl" => { - let mut ident_types = vec![Box::new( - next_type(source).expect("impl must be followed by trait"), - )]; - while let Some(_) = next_exact_punct(source, "+") { - ident_types.push(Box::new( - next_type(source).expect("impl must be followed by trait"), - )) + let mut ident_types = + vec![next_type(source).expect("impl must be followed by trait")]; + while next_exact_punct(source, "+").is_some() { + ident_types.push(next_type(source).expect("impl must be followed by trait")) } let ref_type = ident_types[0].ref_type.clone(); let as_other = ident_types[0].as_other.clone(); @@ -851,13 +848,10 @@ fn next_type + Clone>(mut source: &mut Peekable }) } "dyn" => { - let mut ident_types = vec![Box::new( - next_type(source).expect("impl must be followed by trait"), - )]; - while let Some(_) = next_exact_punct(source, "+") { - ident_types.push(Box::new( - next_type(source).expect("impl must be followed by trait"), - )) + let mut ident_types = + vec![next_type(source).expect("impl must be followed by trait")]; + while next_exact_punct(source, "+").is_some() { + ident_types.push(next_type(source).expect("impl must be followed by trait")) } let ref_type = ident_types[0].ref_type.clone(); let as_other = ident_types[0].as_other.clone(); @@ -879,11 +873,11 @@ fn next_type + Clone>(mut source: &mut Peekable // // - if let Some(_) = next_exact_punct(&mut source, ",") { + if next_exact_punct(source, ",").is_some() { return None; }; - if let Some(_) = next_exact_punct(&mut source, "!") { + if next_exact_punct(source, "!").is_some() { return Some(Type { ident: Category::Never, wraps: None, @@ -903,31 +897,20 @@ fn next_type + Clone>(mut source: &mut Peekable }); }; - let ref_type = match next_exact_punct(&mut source, "&") { - Some(_) => Some(next_lifetime(source)), - None => None, - }; + let ref_type = next_exact_punct(source, "&").map(|_| next_lifetime(source)); if let Some(group) = next_group(&mut source.clone()) { match group.delimiter() { Delimiter::Bracket => { - let mut group_stream = next_group(&mut source) - .unwrap() - .stream() - .into_iter() - .peekable(); + let mut group_stream = next_group(source).unwrap().stream().into_iter().peekable(); return next_array(&mut group_stream).map(|x| x.set_ref_type(ref_type)); } Delimiter::Parenthesis => { - let mut group_stream = next_group(&mut source) - .unwrap() - .stream() - .into_iter() - .peekable(); + let mut group_stream = next_group(source).unwrap().stream().into_iter().peekable(); return next_tuple(&mut group_stream).map(|x| x.set_ref_type(ref_type)); } Delimiter::Brace => { - let anonymous_struct = next_struct(&mut source); + let anonymous_struct = next_struct(source); let wraps = Some( anonymous_struct .fields @@ -965,7 +948,7 @@ fn next_type + Clone>(mut source: &mut Peekable } // read a path like a::b::c::d - let mut ty = next_ident(&mut source).unwrap_or_default(); + let mut ty = next_ident(source).unwrap_or_default(); while let Some(TokenTree::Punct(_)) = source.peek() { let mut tmp = source.clone(); let (Some(_), Some(_)) = ( @@ -977,11 +960,11 @@ fn next_type + Clone>(mut source: &mut Peekable drop(tmp); let _ = (source.next(), source.next()); //skip the colons - let next_ident = next_ident(&mut source).expect("Expecting next path part after ::"); - ty.push_str(&format!("::{}", next_ident)); + let next_ident = next_ident(source).expect("Expecting next path part after ::"); + ty.push_str(&format!("::{next_ident}")); } - let angel_bracket = next_exact_punct(&mut source, "<"); + let angel_bracket = next_exact_punct(source, "<"); if angel_bracket.is_some() { if ty.is_empty() { let ty = next_type(source).expect("Need a base type before 'as'"); @@ -995,10 +978,7 @@ fn next_type + Clone>(mut source: &mut Peekable assert_eq!(Some(">".to_owned()), next_exact_punct(source, ">")); assert_eq!( (Some(":".to_owned()), Some(":".to_owned())), - ( - next_exact_punct(&mut source, ":"), - next_exact_punct(&mut source, ":") - ) + (next_exact_punct(source, ":"), next_exact_punct(source, ":")) ); let associated = next_type(source).expect("Must be an associated type name after the trait"); @@ -1015,14 +995,14 @@ fn next_type + Clone>(mut source: &mut Peekable associated: Box::new(associated), }, wraps: ty.wraps, - ref_type: ref_type, + ref_type, as_other: None, }); } let mut generics = vec![next_type(source).expect("Expecting at least one generic argument")]; - while let Some(_comma) = next_exact_punct(&mut source, ",") { + while let Some(_comma) = next_exact_punct(source, ",") { generics.push(next_type(source).expect("Expecting generic argument after comma")); } @@ -1030,7 +1010,7 @@ fn next_type + Clone>(mut source: &mut Peekable if let Some(assoc_def) = as_associated_definition(source) { let _closing_bracket = - next_exact_punct(&mut source, ">").expect("Expecting closing generic bracket"); + next_exact_punct(source, ">").expect("Expecting closing generic bracket"); return Some(Type { ident: Category::AssociatedBound { associated: ty, @@ -1043,7 +1023,7 @@ fn next_type + Clone>(mut source: &mut Peekable } let _closing_bracket = - next_exact_punct(&mut source, ">").expect("Expecting closing generic bracket"); + next_exact_punct(source, ">").expect("Expecting closing generic bracket"); Some(Type { ident: Category::Named { path: ty }, @@ -1072,15 +1052,15 @@ fn next_type + Clone>(mut source: &mut Peekable } fn next_attribute>( - mut source: &mut Peekable, + source: &mut Peekable, ) -> Option>> { // all attributes, even doc-comments, starts with "#" - let next_attr_punct = next_punct(&mut source); + let next_attr_punct = next_punct(source); let Some("#") = next_attr_punct.as_deref() else { return None; }; - let mut attr_group = next_group(&mut source) + let mut attr_group = next_group(source) .expect("Expecting attribute body") .stream() .into_iter() @@ -1153,7 +1133,7 @@ fn next_attribute>( } } - return Some(Some(attrs)); + Some(Some(attrs)) } fn next_attributes_list(source: &mut Peekable>) -> Vec { @@ -1169,30 +1149,30 @@ fn next_attributes_list(source: &mut Peekable>) } fn next_fields + Clone>( - mut body: &mut Peekable, + body: &mut Peekable, named: bool, ) -> Vec { let mut fields = vec![]; loop { - if next_eof(&mut body).is_some() { + if next_eof(body).is_some() { break; } - let attributes = next_attributes_list(&mut body); - let _visibility = next_visibility_modifier(&mut body); + let attributes = next_attributes_list(body); + let _visibility = next_visibility_modifier(body); let field_name = if named { - let field_name = next_ident(&mut body).expect("Field name expected"); + let field_name = next_ident(body).expect("Field name expected"); - let _ = next_exact_punct(&mut body, ":").expect("Delimeter after field name expected"); + let _ = next_exact_punct(body, ":").expect("Delimeter after field name expected"); Some(field_name) } else { None }; - let ty = next_type(&mut body).expect("Expected field type"); - let _punct = next_punct(&mut body); + let ty = next_type(body).expect("Expected field type"); + let _punct = next_punct(body); fields.push(Field { attributes, @@ -1204,14 +1184,14 @@ fn next_fields + Clone>( fields } -fn next_struct + Clone>(mut source: &mut Peekable) -> Struct { - let struct_name = next_ident(&mut source); +fn next_struct + Clone>(source: &mut Peekable) -> Struct { + let struct_name = next_ident(source); let generics = get_all_bounds(source); - let group = next_group(&mut source); + let group = next_group(source); // unit struct if group.is_none() { // skip ; at the end of struct like this: "struct Foo;" - let _ = next_punct(&mut source); + let _ = next_punct(source); return Struct { name: struct_name, @@ -1234,8 +1214,8 @@ fn next_struct + Clone>(mut source: &mut Peekable< let mut body = group.stream().into_iter().peekable(); let fields = next_fields(&mut body, named); - if named == false { - next_exact_punct(&mut source, ";").expect("Expected ; on the end of tuple struct"); + if !named { + next_exact_punct(source, ";").expect("Expected ; on the end of tuple struct"); } Struct { @@ -1247,10 +1227,10 @@ fn next_struct + Clone>(mut source: &mut Peekable< } } -fn next_enum + Clone>(mut source: &mut Peekable) -> Enum { - let enum_name = next_ident(&mut source).expect("Unnamed enums are not supported"); +fn next_enum + Clone>(source: &mut Peekable) -> Enum { + let enum_name = next_ident(source).expect("Unnamed enums are not supported"); let generic_types = get_all_bounds(source); - let group = next_group(&mut source); + let group = next_group(source); // unit enum if group.is_none() { return Enum { @@ -1292,7 +1272,7 @@ fn next_enum + Clone>(mut source: &mut Peekable { variants.push(Field { field_name: Some(variant_name), - ty: ty, + ty, attributes, vis: Visibility::Public, }); @@ -1322,7 +1302,7 @@ fn next_const_generic + Clone>( "Colon should follow const generic typename" ); let cg_type = next_type(source).expect("Missing const generic type after 'colon'"); - if let Some(_) = next_exact_punct(source, "=") { + if next_exact_punct(source, "=").is_some() { if let Ok(default_value) = source .peek() .expect("default should follow equal for const generic") @@ -1344,9 +1324,8 @@ fn next_const_generic + Clone>( fn next_generic + Clone>( source: &mut Peekable, ) -> Option { - let Some(tok) = source.peek() else { - return None; - }; + let tok = source.peek()?; + match tok { TokenTree::Group(g) => { if matches!(g.delimiter(), Delimiter::Brace) { @@ -1354,7 +1333,7 @@ fn next_generic + Clone>( } let mut bounds = vec![]; let _type = next_type(source).expect("must be a type in group"); - if let Some(_) = next_exact_punct(source, ":") { + if next_exact_punct(source, ":").is_some() { while let Some(bound) = next_type(source) { bounds.push(bound); if next_exact_punct(source, "+").is_none() { @@ -1371,7 +1350,7 @@ fn next_generic + Clone>( TokenTree::Ident(c) if c.to_string() == "const" => { source.next(); let (name, _type, default) = next_const_generic(source); - Some(Generic::ConstGeneric { + Some(Generic::Const { name, _type, default, @@ -1383,7 +1362,7 @@ fn next_generic + Clone>( let mut bounds = vec![]; - if let Some(_) = next_exact_punct(source, ":") { + if next_exact_punct(source, ":").is_some() { loop { if let Some(ty) = next_type(source) { bounds.push(ty); @@ -1394,10 +1373,10 @@ fn next_generic + Clone>( } } - if let Some(_) = next_exact_punct(source, "=") { + if next_exact_punct(source, "=").is_some() { default = Some(next_type(source).expect("Must be a default after eq sign")); } - Some(Generic::Generic { + Some(Generic::Regular { name: ty.full(), default, bounds, @@ -1408,7 +1387,7 @@ fn next_generic + Clone>( '\'' => { let ty = next_lifetime(source).expect("must be lifetime after \' mark"); let mut bounds = vec![]; - if let Some(_) = next_exact_punct(source, ":") { + if next_exact_punct(source, ":").is_some() { while let Some(bound) = next_lifetime(source) { bounds.push(bound); if next_exact_punct(source, "+").is_none() { @@ -1430,7 +1409,7 @@ fn next_generic + Clone>( fn get_all_bounds + Clone>(source: &mut Peekable) -> Vec { let mut ret = Vec::new(); let mut already = HashSet::new(); - if source.peek().map_or(false, |x| x.to_string() == "<") { + if source.peek().is_some_and(|x| x.to_string() == "<") { source.next(); } else { return ret; @@ -1450,8 +1429,8 @@ fn get_all_bounds + Clone>(source: &mut Peekable + Clone>(source: &mut Peekable Generic::WhereBounded { name, bounds }, + Generic::Regular { name, bounds, .. } => Generic::WhereBounded { name, bounds }, where_bounded @ Generic::WhereBounded { .. } => where_bounded, unused => { unimplemented!( @@ -1509,8 +1488,8 @@ fn get_all_bounds + Clone>(source: &mut Peekable + Clone>(source: &mut Peekable { + Generic::Regular { bounds, .. } => { *bounds = std::mem::take(bounds) .into_iter() .collect::>() @@ -1599,7 +1578,7 @@ pub fn parse_data(input: TokenStream) -> Data { res = Data::Enum(enum_); } "union" => unimplemented!("Unions are not supported"), - unexpected => panic!("Unexpected keyword: {}", unexpected), + unexpected => panic!("Unexpected keyword: {unexpected}"), } assert!( diff --git a/derive/src/shared.rs b/derive/src/shared.rs index 2e890c9..43fb6f4 100644 --- a/derive/src/shared.rs +++ b/derive/src/shared.rs @@ -104,7 +104,7 @@ pub fn attrs_map_strategy(attributes: &[crate::parse::Attribute]) -> Option Option> { attributes.iter().find_map(|attr| match attr.tokens.len() { 1 if attr.tokens[0].starts_with("expose") => Some(None), - 2.. if attr.tokens[0] == "expose" => Some(Some((&attr.tokens[1]).to_string())), - _ => return None, + 2.. if attr.tokens[0] == "expose" => Some(Some(attr.tokens[1].to_string())), + _ => None, }) } diff --git a/src/collections/ordered_array_like.rs b/src/collections/ordered_array_like.rs index fe00dd7..72effb2 100644 --- a/src/collections/ordered_array_like.rs +++ b/src/collections/ordered_array_like.rs @@ -223,11 +223,7 @@ fn create_last_change_row<'src, 'target: 'src, T: Clone + PartialEq + 'target>( debug_assert_eq!( target_start <= target_end, source_start <= source_end, - "\ntarget start: {}\ntarget end: {}\nsource start: {}\nsource end: {}", - target_start, - target_end, - source_start, - source_end + "\ntarget start: {target_start}\ntarget end: {target_end}\nsource start: {source_start}\nsource end: {source_end}", ); let mut table = std::array::from_fn::<_, 2, _>(|_| { diff --git a/src/collections/rope/mod.rs b/src/collections/rope/mod.rs index e358749..980b576 100644 --- a/src/collections/rope/mod.rs +++ b/src/collections/rope/mod.rs @@ -1,622 +1,526 @@ use std::{ - cmp::Ordering::{Equal, Greater, Less}, + cmp::Ordering::{Equal, Greater}, collections::VecDeque, - ops::{Index, IndexMut, RangeBounds}, + fmt::Debug, + num::NonZeroUsize, + ops::{Index, IndexMut, Neg}, }; -mod slots; - -const MAX_SLOT_SIZE: usize = 16; -const BASE_SLOT_SIZE: usize = 8; -const UNDERSIZED_SLOT: usize = 1; - -type Container = slots::ArrayMap; - -#[cfg_attr(test, derive(Clone))] -pub struct Rope(Vec>); - -pub struct Iter<'rope, T> { - self_ref: &'rope Rope, - key: usize, - in_key: usize, - exhausted: bool, -} -pub struct IntoIter { - self_own: VecDeque>, - internal: Option< as IntoIterator>::IntoIter>, -} - -impl Index for Rope { - type Output = T; - - fn index(&self, index: usize) -> &Self::Output { - let mut seen = 0; - for entry in self.0.iter() { - seen += entry.len(); - if seen > index { - seen -= entry.len(); - return &entry[index - seen]; - } - } - panic!("Index is {index} but len is {seen}") - } +/// helper type for [`NodesWithCount::slot_mut_internal`] and [`NodesWithCount::remove_internal`] +enum RetType { + Further(usize), + This(usize), } -impl IndexMut for Rope { - fn index_mut(&mut self, index: usize) -> &mut T { - let mut seen = 0; - for entry in self.0.iter_mut() { - seen += entry.len(); - if seen > index { - seen -= entry.len(); - return &mut entry[index - seen]; - } - } - panic!("Index is {index} but len is {seen}") - } +#[derive(Clone, Default)] +enum Node { + #[default] + Empty, + Single(T), + Multiple(NodesWithCount), } -impl<'rope, T: 'rope> Iterator for Iter<'rope, T> { - type Item = &'rope T; - - fn next(&mut self) -> Option { - if self.exhausted { - return None; - } - - let ret = &self.self_ref.0[self.key][self.in_key]; - - self.in_key += 1; - if self.in_key >= self.self_ref.0[self.key].len() { - self.in_key = 0; - self.key += 1; - } - - if self.key >= self.self_ref.0.len() { - self.exhausted = true; - } - - Some(ret) +impl Node { + fn is_occupied(&self) -> bool { + matches!( + self, + Node::Multiple(NodesWithCount { + count: Some(..), + .. + }) | Node::Single(..) + ) } } -impl Iterator for IntoIter { - type Item = T; - - fn next(&mut self) -> Option { - if let ret @ Some(_) = self.internal.as_mut().and_then(|internal| internal.next()) { - return ret; - } - - while let Some(mut vec_iter) = self.self_own.pop_front().map(IntoIterator::into_iter) { - let ret @ Some(_) = vec_iter.next() else { - continue; - }; - - self.internal = Some(vec_iter); - return ret; - } - - None - } +#[derive(Clone)] +struct NodesWithCount { + count: Option, + nodes: VecDeque>, } -impl IntoIterator for Rope { - type Item = T; - - type IntoIter = IntoIter; - - fn into_iter(self) -> Self::IntoIter { - IntoIter { - self_own: self.0.into(), - internal: None, +impl Default for NodesWithCount { + fn default() -> Self { + Self { + count: None, + nodes: VecDeque::new(), } } } -impl<'rope, T: 'rope> IntoIterator for &'rope Rope { - type Item = &'rope T; +#[derive(Clone)] +pub struct Rope(NodesWithCount); - type IntoIter = Iter<'rope, T>; - - fn into_iter(self) -> Self::IntoIter { - Iter { - self_ref: self, - key: 0, - in_key: 0, - exhausted: self.0.is_empty() || self.0[0].is_empty(), +impl NodesWithCount { + #[inline] + fn shallow_len(&self) -> usize { + self.count.map(NonZeroUsize::get).unwrap_or_default() + } + + fn pop_front(&mut self) -> Option { + let node_mut = self + .nodes + .iter_mut() + .find(|v| matches!(v, Node::Single(..) | Node::Multiple(..)))?; + match node_mut { + Node::Empty => unreachable!(), + Node::Single(_) => { + let Node::Single(v) = std::mem::take(node_mut) else { + unreachable!() + }; + self.count = match self + .count + .expect("we're removing a node, count should be >= 1") + { + NonZeroUsize::MIN => None, + higher => Some(NonZeroUsize::new(higher.get() - 1).unwrap()), + }; + Some(v) + } + Node::Multiple(nodes) => { + let v = nodes + .pop_front() + .expect("MUST be at least one value in a Node::Multiple"); + self.count = match self + .count + .expect("we're removing a node, count should be >= 1") + { + NonZeroUsize::MIN => None, + higher => Some(NonZeroUsize::new(higher.get() - 1).unwrap()), + }; + if nodes.shallow_len() == 0 { + std::mem::take(node_mut); + } + Some(v) + } } } -} -impl FromIterator for Rope { - fn from_iter>(iter: C) -> Self { - let mut iter = iter.into_iter().peekable(); - let mut map = Vec::new(); - while iter.peek().is_some() { - let arrmap = slots::ArrayMap::from_iter(iter.by_ref().take(8)); - map.push(arrmap); - if map.last().unwrap().len() != 8 { - break; + fn index_internal(&self, idx: usize, mut last: Option) -> Option<&T> { + for node in &self.nodes { + match (node, &mut last) { + (Node::Empty, _) => continue, + (Node::Single(v), Some(last)) if *last == idx - 1 => return Some(v), + (Node::Single(_), Some(last)) => *last += 1, + (Node::Single(v), None) if idx == 0 => return Some(v), + (Node::Single(_), last @ None) => *last = Some(0), + (Node::Multiple(nodes), last) + if nodes.shallow_len() + last.unwrap_or_default() >= idx => + { + return nodes.index_internal(idx, *last) + } + (Node::Multiple(nodes), last) => { + *last = + Some(last.unwrap_or_default() + nodes.count.map_or(0, NonZeroUsize::get)) + } } } - Self(map) - } -} - -impl Default for Rope { - fn default() -> Self { - Self::new() - } -} - -impl Rope { - pub fn new() -> Self { - Self(Vec::from([slots::ArrayMap::new()])) - } - - pub fn iter(&self) -> Iter<'_, T> { - self.into_iter() + None } - #[inline] - fn _key_for_index(&self, index: usize) -> usize { - let mut seen = 0; - for (idx, entry) in self.0.iter().enumerate() { - seen += entry.len(); - if seen > index { - return idx; + fn index_mut_internal(&mut self, idx: usize, mut last: Option) -> Option<&mut T> { + for node in self.nodes.iter_mut() { + match node { + Node::Empty => continue, + Node::Single(v) => { + let curr = last.map(|l| l + 1).unwrap_or_default(); + match curr == idx { + true => return Some(v), + false => last = Some(curr), + } + } + Node::Multiple(nodes) => { + // relying here on the fact that a Multiple MUST have at least one element + let endex = match last { + Some(last) => last + nodes.shallow_len(), + None => nodes.shallow_len() - 1, + }; + match endex >= idx { + true => return nodes.index_mut_internal(idx, last), + false => last = Some(endex), + } + } } } - self.0.len() - } - #[inline] - fn key_with_count_for_index(&self, index: usize) -> (usize, usize) { - let mut seen = 0; - for (idx, entry) in self.0.iter().enumerate() { - seen += entry.len(); - if seen > index { - seen -= entry.len(); - return (idx, seen); - } - } - (self.0.len(), seen) + None } - #[inline] - fn key_with_count_for_index_from_prev( - &self, - index: usize, - prev: usize, - mut seen: usize, - ) -> (usize, usize) { - if seen > index { - // it's in the same chunk, return early - return (prev, seen); - } - for (idx, entry) in self.0.iter().enumerate().skip(prev) { - seen += entry.len(); - if seen > index { - seen -= entry.len(); - return (idx, seen); + /// returns the parent of the Node::Single which holds the item at the relevant index, the + /// index within the parent of that Node::Single, and whether cleanups are needed due to empty Nodes::Multiple. + /// + /// Apply an optional `adjustment` to the node count at each layer + fn slot_mut_internal( + &mut self, + idx: usize, + mut last: Option, + adjustment: Option, + ) -> Option<(&mut NodesWithCount, usize)> { + let mut return_idx = None; + for (inner_idx, node) in self.nodes.iter_mut().enumerate() { + match node { + Node::Empty => continue, + Node::Single(_) => { + let curr = last.map(|l| l + 1).unwrap_or_default(); + match curr == idx { + true => { + return_idx = Some(RetType::This(inner_idx)); + break; + } + false => last = Some(curr), + } + } + Node::Multiple(nodes) => { + // relying here on the fact that a Multiple MUST have at least one element + let endex = match last { + Some(last) => last + nodes.shallow_len(), + None => nodes.shallow_len() - 1, + }; + match endex >= idx { + true => { + return_idx = Some(RetType::Further(inner_idx)); + break; + } + false => last = Some(endex), + } + } } } - (self.0.len(), seen) - } - - #[inline] - pub fn len(&self) -> usize { - self.0 - .iter() - .map(slots::ArrayMap::len) - .fold(0, std::ops::Add::add) - } - #[inline] - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - fn rebalance_from_key(&mut self, start_key: usize) { - let mut carry = VecDeque::with_capacity(16); - let mut hold = Container::new(); - for key in start_key..(self.0.len()) { - let entry = self.0.get_mut(key).unwrap(); - if entry.is_empty() { - continue; + return_idx.map(|inner_idx| { + match adjustment { + Some(pos @ 1..) => { + self.count = Some(self.count.unwrap().checked_add(pos as usize).unwrap()) + } + Some(neg @ ..-1) => { + self.count = NonZeroUsize::new(self.count.unwrap().get() - neg.neg() as usize); + } + _ => (), } - - const LOW: usize = BASE_SLOT_SIZE - (BASE_SLOT_SIZE / 2); - const HIGH: usize = BASE_SLOT_SIZE + (BASE_SLOT_SIZE / 2); - if (LOW..=HIGH).contains(&entry.len()) && carry.is_empty() { - break; + match inner_idx { + RetType::Further(i) => { + let Some(Node::Multiple(mult)) = self.nodes.get_mut(i) else { + panic!() + }; + mult.slot_mut_internal(idx, last, adjustment).unwrap() + } + RetType::This(i) => (self, i), } + }) + } - // put the empty holder in the list for now - std::mem::swap(entry, &mut hold); - - // adjust size of hold, either taking elements from later chunks or carrying them - match (hold.len().cmp(&BASE_SLOT_SIZE), carry.is_empty()) { - (Less, carry_empty) => { - if !carry_empty { - carry.extend(hold.drain(..)); - hold.extend(carry.drain(..BASE_SLOT_SIZE.min(carry.len()))); + fn insert_internal(&mut self, idx: usize, element: T) { + match (self.count, idx) { + (None, 0) => { + return { + let len = self.nodes.len(); + match len == 0 { + true => self.nodes.push_back(Node::Single(element)), + false => self.nodes[len.saturating_div(2)] = Node::Single(element), } + self.count = Some(NonZeroUsize::MIN); + } + } + (Some(len), idx) if len.get() == idx => { + return { + // check if there's a Node::Empty that we can replace with a Node::Single(element), otherwise append to top level + let last_occupied = self + .nodes + .iter() + .enumerate() + .rev() + .find_map(|(idx, v)| v.is_occupied().then_some(idx)) + .unwrap(); + self.count = Some( + self.count + .map_or(NonZeroUsize::MIN, |v| v.checked_add(1).unwrap()), + ); + match self.nodes.get_mut(last_occupied + 1) { + None => self.nodes.push_back(Node::Single(element)), + Some(empty) => *empty = Node::Single(element), + }; + }; + } + _ => (), + } - let mut iter = self.0.iter_mut().skip(key); - while let (Some(take_from), false) = (iter.next(), hold.len() == BASE_SLOT_SIZE) - { - hold.extend(take_from.drain( - ..(BASE_SLOT_SIZE.saturating_sub(hold.len())).min(take_from.len()), - )); + // it's neither a front nor a back, find the internal slot that holds the item at the relevent index and either push it if + // it's at front/back of its vec, or replace the Node::Single with a Node::Multiple + let (nodes, slot, ..) = self.slot_mut_internal(idx, None, Some(1)).unwrap(); + + // check for special cases + if slot == 0 { + return nodes.nodes.push_front(Node::Single(element)); + } + if let Some(Node::Multiple(before)) = nodes.nodes.get_mut(slot - 1) { + before.count = before.count.map(|c| c.checked_add(1)).unwrap(); + before.nodes.push_back(Node::Single(element)); + return; + } + + let node_slot = &mut nodes.nodes[slot]; + let prev = std::mem::take(node_slot); + debug_assert!(matches!(prev, Node::Single(..))); + + *node_slot = Node::Multiple(NodesWithCount { + count: Some(NonZeroUsize::new(2).unwrap()), + nodes: vec![Node::Single(element), prev].into(), + }); + } + + /// Get the item at index `idx`, patching up Node type at each level if they become empty + fn remove_internal(&mut self, idx: usize, mut last: Option) -> Option { + let mut return_idx = None; + for (inner_idx, node) in self.nodes.iter_mut().enumerate() { + match node { + Node::Empty => continue, + Node::Single(_) => { + let curr = last.map(|l| l + 1).unwrap_or_default(); + match curr == idx { + true => { + return_idx = Some(RetType::This(inner_idx)); + break; + } + false => last = Some(curr), } } - (Equal, true) => (), - (Equal | Greater, false) => { - carry.extend(hold.drain(..)); - hold.extend(carry.drain(..BASE_SLOT_SIZE.min(carry.len()))); - } - (Greater, true) => { - carry.extend(hold.drain(BASE_SLOT_SIZE..)); + Node::Multiple(nodes) => { + // relying here on the fact that a Multiple MUST have at least one element + let endex = match last { + Some(last) => last + nodes.count.unwrap().get(), + None => nodes.count.unwrap().get() - 1, + }; + match endex >= idx { + true => { + return_idx = Some(RetType::Further(inner_idx)); + break; + } + false => last = Some(endex), + } } } - - // take the empty holder back and leave the values in the map entry - std::mem::swap(self.0.get_mut(key).unwrap(), &mut hold); } - assert!(hold.is_empty()); + let inner_idx = return_idx?; - self.0.retain(|v| !v.is_empty()); - - // fix up the last entry with any carried values - match (carry.len(), self.0.last_mut()) { - (0, ..) => { - return; - } - (_, Some(l_entry)) => { - l_entry.extend( - carry.drain(..(BASE_SLOT_SIZE.saturating_sub(l_entry.len())).min(carry.len())), - ); - } - _ => (), - } + self.count = NonZeroUsize::new(self.count.unwrap().get() - 1_usize); - // add any remaining carry values into new slots at the end - while carry.len() > BASE_SLOT_SIZE { - self.0.push(Container::from_iter( - carry.drain(..BASE_SLOT_SIZE.min(carry.len())), - )); - } - if !carry.is_empty() { - self.0.push(Container::from_iter(carry)); - } - } + match inner_idx { + RetType::Further(i) => { + let Some(Node::Multiple(mult)) = self.nodes.get_mut(i) else { + panic!() + }; + let ret = mult.remove_internal(idx, last); - pub fn insert(&mut self, index: usize, element: T) { - let (key, count) = self.key_with_count_for_index(index); - if key == self.0.len() { - self.0.push(Container::new()); - } - let vec = self.0.get_mut(key).unwrap(); - vec.insert(index - count, element); - if vec.len() == MAX_SLOT_SIZE { - self.rebalance_from_key(key); - } - } + if mult.count.is_none() { + self.nodes[i] = Node::Empty; + } - pub fn remove(&mut self, index: usize) { - let (key, count) = self.key_with_count_for_index(index); - let Some(vec) = self.0.get_mut(key) else { - panic!( - "Failed to remove item with index {index} from rope with {} elements", - self.len() - ); - }; - vec.remove(index - count); - if (0..=UNDERSIZED_SLOT).contains(&vec.len()) { - self.rebalance_from_key(key.saturating_sub(1)); + ret + } + RetType::This(i) => { + let Some(Node::Single(single)) = self.nodes.get_mut(i).map(std::mem::take) else { + panic!() + }; + Some(single) + } } } - pub fn drain(&mut self, range: R) - where - R: RangeBounds, - { - use std::ops::Bound; + fn swap_internal(&mut self, [low, high]: [usize; 2], _arg: i32) { + let high_elem = self.remove_internal(high, None).unwrap(); + let (nodes, slot) = self.slot_mut_internal(low, None, None).unwrap(); - let (l_idx, r_idx) = match (range.start_bound(), range.end_bound()) { - (Bound::Included(l_i), Bound::Included(r_i)) => (*l_i, *r_i), - (Bound::Included(l_i), Bound::Excluded(r_e)) => (*l_i, r_e - 1), - (Bound::Included(l_i), Bound::Unbounded) => (*l_i, self.len() - 1), - (Bound::Excluded(l_e), Bound::Included(r_i)) => (l_e + 1, *r_i), - (Bound::Excluded(l_e), Bound::Excluded(r_e)) => (l_e + 1, r_e - 1), - (Bound::Excluded(l_e), Bound::Unbounded) => (l_e + 1, self.len() - 1), - (Bound::Unbounded, Bound::Included(r_i)) => (0, *r_i), - (Bound::Unbounded, Bound::Excluded(r_e)) => (0, r_e - 1), - (Bound::Unbounded, Bound::Unbounded) => (0, self.len() - 1), + let Node::Single(low) = std::mem::replace(&mut nodes.nodes[slot], Node::Single(high_elem)) + else { + panic!(); }; + self.insert_internal(high, low); + } + + fn drain_internal(&mut self, l_idx: usize, r_idx: usize, mut last: Option) { + let mut removed = 0; + for node in self.nodes.iter_mut() { + match node { + Node::Empty => continue, + single @ Node::Single(_) => { + let new_last = last.map(|i| i + 1).unwrap_or_default(); + if (l_idx..=r_idx).contains(&new_last) { + *single = Node::Empty; + removed += 1; + } + last = Some(new_last); + } + Node::Multiple(nodes_with_count) => { + let nodes_with_count_len = nodes_with_count.count.unwrap().get(); + // get the endex of the last element of nodes_with_count + let last_after_sub = match last { + Some(last) => last + nodes_with_count_len, + None => nodes_with_count_len - 1, + }; + + // check if the endex is still lower than the lowest value we are to remove + if last_after_sub < l_idx { + last = Some(last_after_sub); + continue; + } - let (l_key, l_key_count) = self.key_with_count_for_index(l_idx); - let (r_key, r_key_count) = - self.key_with_count_for_index_from_prev(r_idx, l_key, l_key_count); - - match l_key == r_key { - true => { - let v = self.0.get_mut(l_key).expect("we just looked this key up"); - v.drain((l_idx - l_key_count)..=(r_idx - l_key_count)); - if v.len() <= UNDERSIZED_SLOT { - self.rebalance_from_key(l_key.saturating_sub(1)); + // we need to remove some things; figure out if we can remove the entire subtree or need to recurse + match r_idx.cmp(&last_after_sub) { + // we can yeet the whole thing + Equal | Greater + if last.map_or_else( + || l_idx == last.unwrap_or_default(), + |l| l_idx <= l + 1, + ) => + { + let before = nodes_with_count_len; + *node = Node::Empty; + removed += before; + } + // we need to remove only part of this node + _ => { + let before = nodes_with_count_len; + nodes_with_count.drain_internal(l_idx, r_idx, last); + let after = nodes_with_count.count.unwrap().get(); + removed += before.abs_diff(after); + } + } + last = Some(last_after_sub); } } - false => { - let l_mut = self.0.get_mut(l_key).unwrap(); - l_mut.drain((l_idx - l_key_count)..); - let l_len = l_mut.len(); - let r_mut = self.0.get_mut(r_key).unwrap(); - r_mut.drain(..=(r_idx - r_key_count)); - let r_len = r_mut.len(); - let _ = self.0.drain((l_key + 1)..r_key); - - if l_len <= UNDERSIZED_SLOT || r_len <= UNDERSIZED_SLOT { - self.rebalance_from_key(l_key); - } + + if last.is_some_and(|l| l >= r_idx) { + break; } } + + self.count = self + .count + .map(|c| c.get() - removed) + .and_then(NonZeroUsize::new); } +} - pub fn swap(&mut self, a: usize, b: usize) { - let [a, b] = [a.min(b), a.max(b)]; - let (l_key, l_key_count) = self.key_with_count_for_index(a); - let (r_key, r_key_count) = self.key_with_count_for_index_from_prev(b, l_key, l_key_count); - match l_key == r_key { - true => self - .0 - .get_mut(l_key) - .unwrap() - .swap(a - l_key_count, b - l_key_count), - false => { - let (l, r) = self.0.split_at_mut(r_key); - std::mem::swap(&mut l[l_key][a - l_key_count], &mut r[0][b - r_key_count]); - } - } +impl FromIterator for Rope { + fn from_iter>(iter: C) -> Self { + let nodes = iter + .into_iter() + .map(|t| Node::Single(t)) + .collect::>(); + Self(NodesWithCount { + count: NonZeroUsize::try_from(nodes.len()).ok(), + nodes, + }) } } -#[cfg(test)] -mod test { - use nanorand::{Rng, WyRand}; +pub struct IntoIter { + owned: NodesWithCount, +} - use super::{Rope, BASE_SLOT_SIZE, MAX_SLOT_SIZE}; +impl IntoIterator for Rope { + type Item = T; - #[derive(Debug, Clone)] - pub enum Mutation { - Insert(T, usize), - Remove(usize), - Swap(usize, usize), - Drain(usize, usize), - } + type IntoIter = IntoIter; - pub(crate) trait Random { - fn generate_random(rng: &mut WyRand) -> Self; - fn generate_random_large(rng: &mut WyRand) -> Self; - fn random_mutate(self, mutation: Mutation) -> Self; + fn into_iter(self) -> Self::IntoIter { + IntoIter { owned: self.0 } } +} - pub fn rand_string(rng: &mut WyRand) -> String { - let base = vec![(); 8]; - base.into_iter() - .map(|_| rng.generate_range::(65..=90)) - .filter_map(char::from_u32) - .collect::() - } +impl Iterator for IntoIter { + type Item = T; - impl Mutation { - pub fn random_mutation(rng: &mut WyRand, len: usize) -> Option> { - match rng.generate_range(0..4) { - 0 => Some(Self::Insert(rand_string(rng), rng.generate_range(0..=len))), - 1 => match len == 0 { - false => Some(Self::Remove(rng.generate_range(0..len))), - true => None, - }, - 2 => { - if len == 0 { - return None; - } - let l = rng.generate_range(0..len); - let r = rng.generate_range(0..len); - if l == r { - None - } else { - Some(Self::Swap(l, r)) - } - } - 3 => { - let l = rng.generate_range(0..len); - let r = rng.generate_range(l..len); - Some(Self::Drain(l, r)) - } - _ => None, - } - } + fn next(&mut self) -> Option { + self.owned.pop_front() } +} - impl Random for Vec { - fn generate_random(rng: &mut WyRand) -> Self { - (0..rng.generate_range::(5..15)) - .map(|_| rand_string(rng)) - .collect() - } - - fn generate_random_large(rng: &mut WyRand) -> Self { - (0..rng.generate_range::(0..(u16::MAX / 5))) - .map(|_| rand_string(rng)) - .collect() - } +impl Index for Rope { + type Output = T; - fn random_mutate(mut self, mutation: Mutation) -> Self { - match mutation { - Mutation::Insert(s, i) => self.insert(i, s), - Mutation::Remove(i) => { - self.remove(i); - } - Mutation::Swap(l, r) => self.swap(l, r), - Mutation::Drain(l, r) => { - self.drain(l..=r); - } - } - self - } + fn index(&self, index: usize) -> &Self::Output { + self.0 + .index_internal(index, None) + .expect("Failed to find element") } +} - impl std::fmt::Display for Rope { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut seen = 0; - for vals in self.0.iter() { - write!(f, "{seen}: [")?; - for val in vals { - write!(f, "{},", val)?; - } - writeln!(f, "];")?; - seen += vals.len(); - } - Ok(()) - } +impl IndexMut for Rope { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + self.0 + .index_mut_internal(index, None) + .expect("Failed to find element") } +} - impl Random for Rope { - fn generate_random(rng: &mut WyRand) -> Self { - (0..rng.generate_range::(5..15)) - .map(|_| rand_string(rng)) - .collect() - } - - fn generate_random_large(rng: &mut WyRand) -> Self { - (0..rng.generate_range::(0..(u16::MAX / 5))) - .map(|_| rand_string(rng)) - .collect() - } - - fn random_mutate(mut self, mutation: Mutation) -> Self { - match mutation { - Mutation::Insert(s, i) => self.insert(i, s), - Mutation::Remove(i) => self.remove(i), - Mutation::Swap(l, r) => self.swap(l, r), - Mutation::Drain(l, r) => self.drain(l..=r), - } - self +impl std::fmt::Debug for Node { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Empty => write!(f, "Node::Empty"), + Self::Single(arg0) => f.debug_tuple("Node::Single").field(arg0).finish(), + Self::Multiple(arg0) => f.debug_tuple("Node::Multiple").field(arg0).finish(), } } +} - fn test(generator: impl Fn(&mut WyRand) -> Vec, count: usize) { - let mut rng = WyRand::new(); - let mut start_vec = generator(&mut rng); - let mut start_rope = start_vec.clone().into_iter().collect::>(); - assert_eq!( - start_rope.clone().into_iter().collect::>(), - start_vec - ); - for _ in 0..count { - let prev_rope = start_rope.clone(); - let Some(mutation) = Mutation::random_mutation(&mut rng, start_vec.len()) else { - continue; - }; - - let sr_clone = start_rope.clone(); - let mut_clone = mutation.clone(); - let result = std::panic::catch_unwind(|| { - sr_clone.random_mutate(mut_clone); - }); - - let Ok(_) = result else { - println!("{:?}", mutation); - println!("prev_rope: {}", prev_rope); - panic!("Caught panic"); - }; - - start_rope = start_rope.random_mutate(mutation.clone()); - start_vec = start_vec.random_mutate(mutation.clone()); - - if start_rope.clone().into_iter().collect::>() != start_vec { - println!("{:?}", mutation); - println!("prev_rope: {}", prev_rope); - println!("curr_rope: {}", start_rope); - } - pretty_assertions::assert_eq!( - (&start_rope).into_iter().cloned().collect::>(), - start_rope.clone().into_iter().collect::>() - ); - pretty_assertions::assert_eq!( - (&start_rope).into_iter().cloned().collect::>(), - start_vec - ); - } +impl std::fmt::Debug for NodesWithCount { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("NodesWithCount") + .field("count", &self.count) + .field("nodes", &self.nodes) + .finish() } +} - #[test] - fn paired_small() { - test(Vec::generate_random, 1_000_000) +impl std::fmt::Debug for Rope { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("Rope").field(&self.0).finish() } +} - #[test] - fn paired_large() { - test(Vec::generate_random_large, 100_000) +impl Rope { + pub fn len(&self) -> usize { + self.0.count.map_or(0, usize::from) } - #[test] - #[should_panic] - fn get_from_empty() { - #[expect(clippy::unnecessary_operation)] - Rope::<()>::new()[0]; + pub fn insert(&mut self, index: usize, element: T) { + self.0.insert_internal(index, element); } - #[test] - #[should_panic] - fn get_past_end() { - #[expect(clippy::unnecessary_operation)] - Rope::<()>::from_iter([(), ()])[2]; + pub fn remove(&mut self, index: usize) { + self.0 + .remove_internal(index, None) + .expect("No item at index"); } - #[test] - fn get_last() { - for i in 1..33 { - assert_eq!( - Rope::from_iter(vec![(); i].into_iter().enumerate().map(|(i, _)| i))[i - 1], - i - 1 - ); - } - } + pub fn drain>(&mut self, range: R) { + use std::ops::Bound; - #[test] - fn delete_rebalance() { - let arr_map = { - let mut collection = Rope::from_iter((0..).take(BASE_SLOT_SIZE)); - for i in (BASE_SLOT_SIZE..).take(9) { - collection.insert(i, i); - } - collection.remove(MAX_SLOT_SIZE); - collection + let (l_idx, r_idx) = match (range.start_bound(), range.end_bound()) { + (Bound::Included(l_i), Bound::Excluded(r_e)) if l_i == r_e => return, + (Bound::Included(l_i), Bound::Included(r_i)) => (*l_i, *r_i), + (Bound::Included(l_i), Bound::Excluded(r_e)) => (*l_i, r_e - 1), + (Bound::Included(l_i), Bound::Unbounded) => (*l_i, self.len() - 1), + (Bound::Excluded(l_e), Bound::Included(r_i)) => (l_e + 1, *r_i), + (Bound::Excluded(l_e), Bound::Excluded(r_e)) => (l_e + 1, r_e - 1), + (Bound::Excluded(l_e), Bound::Unbounded) => (l_e + 1, self.len() - 1), + (Bound::Unbounded, Bound::Included(r_i)) => (0, *r_i), + (Bound::Unbounded, Bound::Excluded(r_e)) => (0, r_e - 1), + (Bound::Unbounded, Bound::Unbounded) => (0, self.len() - 1), }; - let vec = { - let mut collection = Vec::from_iter((0..).take(BASE_SLOT_SIZE)); - for i in (BASE_SLOT_SIZE..).take(9) { - collection.insert(i, i); - } + if r_idx == 0 && l_idx == 0 && self.0.shallow_len() == 0 { + return; + } - collection.remove(MAX_SLOT_SIZE); - collection - }; + self.0.drain_internal(l_idx, r_idx, None); + } - assert_eq!( - vec.iter().collect::>(), - arr_map.iter().collect::>() - ); - assert_eq!( - vec.into_iter().collect::>(), - arr_map.into_iter().collect::>() - ); + pub fn swap(&mut self, a: usize, b: usize) { + if a != b { + self.0.swap_internal([a.min(b), a.max(b)], 0); + } } } diff --git a/src/collections/rope/slots.rs b/src/collections/rope/slots.rs deleted file mode 100644 index 18ef1f3..0000000 --- a/src/collections/rope/slots.rs +++ /dev/null @@ -1,357 +0,0 @@ -use std::{ - fmt::Debug, - ops::{Index, IndexMut, RangeBounds}, -}; - -#[derive(Clone)] -pub(crate) struct ArrayMap([Option<(u8, T)>; N], usize); - -impl Debug for ArrayMap { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("ArrayMap") - .field(&self.0.iter().filter_map(|o| o.as_ref()).collect::>()) - .field(&self.1) - .finish() - } -} - -impl ArrayMap { - #[inline] - fn find_empty_slot(&self) -> Option { - self.0.iter().position(Option::is_none) - } - - #[inline] - fn find_empty_slots(&self) -> [Option; N] { - let mut ret = [const { None }; N]; - for (slot, idx) in self - .0 - .iter() - .enumerate() - .filter(|i| i.1.is_none()) - .map(|e| e.0) - .zip(0..) - { - ret[idx] = Some(slot); - } - ret - } - - fn get_lookups(&self) -> [Option; N] { - let list_of_logical_indices: [Option; N] = std::array::from_fn(|storage_idx| { - self.0[storage_idx] - .as_ref() - .map(|(logical_idx, _)| Some(*logical_idx)) - .unwrap_or_default() - }); - let mut lookup_tmp: [(usize, Option); N] = - std::array::from_fn(|storage_idx| (storage_idx, list_of_logical_indices[storage_idx])); - lookup_tmp.sort_unstable_by_key(|(_storage_idx, logical_idx)| *logical_idx); - let start_of_somes = lookup_tmp - .iter() - .position(|(_storage, logical)| logical.is_some()) - .unwrap_or_default(); - let lookups = std::array::from_fn(|i| { - lookup_tmp - .get(start_of_somes + i) - .map(|(storage, _logical)| *storage) - }); - lookups - } -} - -impl ArrayMap { - pub const fn new() -> Self { - if N > u8::MAX as usize { - panic!("N > u8::MAX is unsupported"); - } - Self([const { None }; N], 0) - } - - pub const fn len(&self) -> usize { - self.1 - } - - pub const fn is_empty(&self) -> bool { - self.1 == 0 - } - - pub fn insert(&mut self, position: usize, value: T) { - assert!( - position < N, - "Position {position} is greater than max position of {}", - N - 1 - ); - assert!( - self.0.iter().any(Option::is_none), - "No space to insert in ArrayMap with len = {}", - self.1 - ); - - // bump each following index number - self.0 - .iter_mut() - .filter_map(|o| o.as_mut().map(|some| &mut some.0)) - .filter(|i| **i as usize >= position) - .for_each(|i| *i += 1); - - // find a free slot and put it in - let slot_idx = self.find_empty_slot().expect("failed to find free slot"); - self.0[slot_idx] = Some((position as u8, value)); - - self.1 += 1; - } - - pub fn remove(&mut self, position: usize) -> T { - let u8_idx = position as u8; - let Some(val) = self - .0 - .iter_mut() - .find(|o| o.as_ref().map(|(i, _)| *i == u8_idx).unwrap_or_default()) - .and_then(Option::take) - .map(|o| o.1) - else { - panic!("No element found at position {}", position); - }; - - // lower each following index number - self.0 - .iter_mut() - .filter_map(|o| o.as_mut().map(|some| &mut some.0)) - .filter(|i| **i > u8_idx) - .for_each(|i| *i -= 1); - - self.1 -= 1; - val - } - - pub fn swap(&mut self, a: usize, b: usize) { - if a == b { - return; - } - - let mut indices = [a, b].map(|find| { - self.0 - .iter() - .position(|o| o.as_ref().map(|(i, _)| *i == find as u8).unwrap_or(false)) - .unwrap_or_else(|| panic!("unable to find item at idx: {}", find)) - }); - indices.sort(); - let [lower, upper] = indices; - let (l, r) = self.0.split_at_mut(upper); - std::mem::swap( - l[lower].as_mut().map(|o| &mut o.0).unwrap(), - r[0].as_mut().map(|o| &mut o.0).unwrap(), - ); - } - - pub fn drain(&mut self, range: R) -> Drain - where - R: RangeBounds, - { - // stores the highest removed value, so that later ones can be decremented - let mut max_removed: Option = None; - // store the length before removing things - let before = self.1; - - let removals = self - .0 - .iter_mut() - .filter(|o| matches!(o, Some((i, _)) if range.contains(&(*i as usize)))); - - // move the items to the new list and decrement the item count - let mut drained = [const { None }; N]; - for (idx, removal) in removals.enumerate() { - let removal_logical_idx = removal.as_ref().map(|o| o.0).unwrap(); - max_removed = max_removed - .map(|current| Some(current.max(removal_logical_idx))) - .unwrap_or_else(|| Some(removal_logical_idx)); - drained[idx] = removal.take(); - self.1 -= 1; - } - - drained.sort_by_key(|e| e.as_ref().map(|o| o.0)); - let ret = Self::from_iter(drained.into_iter().filter_map(|e| e.map(|o| o.1))); - - // decrement all indices after the last removed index by the - // number of items drained - if let Some(max) = max_removed { - let removed_count = before.abs_diff(self.1) as u8; - - self.0 - .iter_mut() - .filter_map(|o| o.as_mut().map(|some| &mut some.0)) - .filter(|i| **i > max) - .for_each(|i| *i -= removed_count); - } - - Drain(ret.into_iter()) - } - - pub fn extend>(&mut self, values: I) { - let free_slots = self.find_empty_slots(); - - for (v, loc) in values.zip(free_slots.into_iter().flatten()) { - self.0[loc] = Some((self.1 as u8, v)); - self.1 += 1; - } - } -} - -pub struct Drain( as IntoIterator>::IntoIter); - -impl Iterator for Drain { - type Item = T; - - fn next(&mut self) -> Option { - self.0.next() - } -} - -impl DoubleEndedIterator for Drain { - fn next_back(&mut self) -> Option { - self.0.next_back() - } -} - -impl Index for ArrayMap { - type Output = T; - - fn index(&self, index: usize) -> &Self::Output { - self.0 - .iter() - .filter_map(|o| o.as_ref()) - .find(|(idx, _)| *idx as usize == index) - .map(|(_, v)| v) - .unwrap_or_else(|| panic!("No element found at index {index}")) - } -} - -impl IndexMut for ArrayMap { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - self.0 - .iter_mut() - .filter_map(|o| o.as_mut()) - .find(|(idx, _)| *idx as usize == index) - .map(|(_, v)| v) - .unwrap() - } -} - -// self.iter() -const _: () = { - pub struct Iter<'rope, T, const N: usize> { - self_ref: &'rope ArrayMap, - // list of indices into the backing array, stored in logical array order - lookups: [Option; N], - pos: usize, - } - - impl<'rope, T, const N: usize> Iterator for Iter<'rope, T, N> { - type Item = &'rope T; - - fn next(&mut self) -> Option { - let v_ref = self - .lookups - .get(self.pos) - .copied() - .flatten() - .and_then(|idx| self.self_ref.0.get(idx)) - .and_then(|v| v.as_ref().map(|(_, v)| v))?; - - self.pos += 1; - Some(v_ref) - } - } - - impl<'rope, T, const N: usize> IntoIterator for &'rope ArrayMap { - type Item = &'rope T; - - type IntoIter = Iter<'rope, T, N>; - - fn into_iter(self) -> Self::IntoIter { - let lookups = self.get_lookups(); - Iter { - self_ref: self, - lookups, - - pos: 0, - } - } - } -}; - -// self.into_iter() -const _: () = { - pub struct Iter { - self_owned: ArrayMap, - // list of indices into the backing array, stored in logical array order - lookups: [Option; N], - pos: usize, - rev_pos: usize, - } - - impl Iterator for Iter { - type Item = T; - - fn next(&mut self) -> Option { - let v_ref = self - .lookups - .get(self.pos) - .copied() - .flatten() - .and_then(|idx| self.self_owned.0.get_mut(idx)) - .and_then(|v| v.take().map(|(_, v)| v))?; - - self.pos += 1; - Some(v_ref) - } - } - - impl DoubleEndedIterator for Iter { - fn next_back(&mut self) -> Option { - let v_ref = self - .lookups - .get(self.rev_pos) - .copied() - .flatten() - .and_then(|idx| self.self_owned.0.get_mut(idx)) - .and_then(|v| v.take().map(|(_, v)| v))?; - - self.rev_pos += 1; - Some(v_ref) - } - } - - impl IntoIterator for ArrayMap { - type Item = T; - - type IntoIter = Iter; - - fn into_iter(self) -> Self::IntoIter { - let lookups = self.get_lookups(); - let rev_pos = self.len().saturating_sub(1); - Iter { - self_owned: self, - lookups, - - pos: 0, - rev_pos, - } - } - } -}; - -impl FromIterator for ArrayMap { - fn from_iter>(iter: C) -> Self { - let mut ret = Self::new(); - let mut count = 0; - for (i, v) in iter.into_iter().enumerate() { - ret.0[i] = Some((i as u8, v)); - count += 1; - } - - ret.1 = count; - ret - } -}