Skip to content

Commit c37feb5

Browse files
Derived extend_for_self for enums (#82)
1 parent 6342f16 commit c37feb5

File tree

2 files changed

+77
-3
lines changed

2 files changed

+77
-3
lines changed

columnar_derive/src/lib.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -991,6 +991,12 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
991991
}
992992
}).collect::<Vec<_>>();
993993

994+
// Helper identifiers for `extend_from_self` local variables.
995+
let len_idents = &names.iter().map(|n| syn::Ident::new(&format!("len_{}", n.to_string().to_lowercase()), n.span())).collect::<Vec<_>>();
996+
let count_idents = &names.iter().map(|n| syn::Ident::new(&format!("count_{}", n.to_string().to_lowercase()), n.span())).collect::<Vec<_>>();
997+
let start_idents = &names.iter().map(|n| syn::Ident::new(&format!("start_{}", n.to_string().to_lowercase()), n.span())).collect::<Vec<_>>();
998+
let variant_indices = &(0..variants.len()).map(|i| i as u8).collect::<Vec<_>>();
999+
9941000
quote! {
9951001
impl #impl_gen ::columnar::Columnar for #name #ty_gen #where_clause2 {
9961002
#[inline(always)]
@@ -1034,8 +1040,33 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
10341040
}
10351041
}
10361042

1037-
impl < #(#container_names : ::columnar::Container ),* > ::columnar::Container for #c_ident < #(#container_names),* > {
1038-
// TODO: implement `extend_from_self`.
1043+
impl < #(#container_names : ::columnar::Container + ::columnar::Len),* > ::columnar::Container for #c_ident < #(#container_names),* > {
1044+
#[inline(always)]
1045+
fn extend_from_self(&mut self, other: Self::Borrowed<'_>, range: std::ops::Range<usize>) {
1046+
if !range.is_empty() {
1047+
#( let #len_idents = ::columnar::Len::len(&self.#names); )*
1048+
#( let mut #count_idents = 0usize; )*
1049+
#( let mut #start_idents = 0u64; )*
1050+
for index in range.clone() {
1051+
let (variant, offset) = other.indexes.get(index);
1052+
match variant {
1053+
#(
1054+
#variant_indices => {
1055+
if #count_idents == 0 { #start_idents = offset; }
1056+
self.indexes.push(#variant_indices, (#len_idents + #count_idents) as u64);
1057+
#count_idents += 1;
1058+
}
1059+
)*
1060+
_ => unreachable!(),
1061+
}
1062+
}
1063+
#(
1064+
if #count_idents > 0 {
1065+
self.#names.extend_from_self(other.#names, #start_idents as usize .. #start_idents as usize + #count_idents);
1066+
}
1067+
)*
1068+
}
1069+
}
10391070

10401071
fn reserve_for<'a, I>(&mut self, selves: I) where Self: 'a, I: Iterator<Item = Self::Borrowed<'a>> + Clone {
10411072
#( self.#names.reserve_for(selves.clone().map(|x| x.#names)); )*
@@ -1227,7 +1258,10 @@ fn derive_tags(name: &syn::Ident, _generics: &syn:: Generics, data_enum: syn::Da
12271258
}
12281259

12291260
impl<CV: ::columnar::common::PushIndexAs<u8>> ::columnar::Container for #c_ident <CV> {
1230-
// TODO: implement `extend_from_self`.
1261+
#[inline(always)]
1262+
fn extend_from_self(&mut self, other: Self::Borrowed<'_>, range: std::ops::Range<usize>) {
1263+
self.variant.extend_from_self(other.variant, range);
1264+
}
12311265

12321266
fn reserve_for<'a, I>(&mut self, selves: I) where Self: 'a, I: Iterator<Item = Self::Borrowed<'a>> + Clone {
12331267
self.variant.reserve_for(selves.map(|x| x.variant));

src/main.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,46 @@ mod test {
184184
}
185185

186186

187+
#[test]
188+
fn extend_from_self_enum() {
189+
use columnar::{Borrow, Container, Index, Len, Push};
190+
191+
// Test data enum with multiple variants.
192+
let mut columns = <Test3<u8> as Columnar>::Container::default();
193+
columns.push(Test3::<u8>::Foo(vec![1, 2], 10));
194+
columns.push(Test3::<u8>::Bar(20));
195+
columns.push(Test3::<u8>::Foo(vec![3], 30));
196+
columns.push(Test3::<u8>::Void);
197+
198+
let mut dest = <Test3<u8> as Columnar>::Container::default();
199+
dest.extend_from_self(columns.borrow(), 1..3);
200+
assert_eq!(dest.len(), 2);
201+
match dest.borrow().get(0) {
202+
Test3Reference::Bar(x) => assert_eq!(*x, 20),
203+
other => panic!("Expected Bar, got {:?}", other),
204+
}
205+
match dest.borrow().get(1) {
206+
Test3Reference::Foo((v, x)) => {
207+
assert_eq!(v.len(), 1);
208+
assert_eq!(*x, 30);
209+
},
210+
other => panic!("Expected Foo, got {:?}", other),
211+
}
212+
213+
// Test unit enum.
214+
let mut tags = <Test4 as Columnar>::Container::default();
215+
tags.push(Test4::Foo);
216+
tags.push(Test4::Bar);
217+
tags.push(Test4::Foo);
218+
219+
let mut dest_tags = <Test4 as Columnar>::Container::default();
220+
dest_tags.extend_from_self(tags.borrow(), 0..3);
221+
assert_eq!(dest_tags.len(), 3);
222+
assert!(matches!(dest_tags.borrow().get(0), Test4::Foo));
223+
assert!(matches!(dest_tags.borrow().get(1), Test4::Bar));
224+
assert!(matches!(dest_tags.borrow().get(2), Test4::Foo));
225+
}
226+
187227
// Test names that collide with the prelude.
188228
#[derive(Columnar, Debug, Copy, Clone)]
189229
enum Strange { None, Some }

0 commit comments

Comments
 (0)