Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 26 additions & 7 deletions columnar_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@ use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Attribute, DeriveInput};

/// Build a balanced binary tree of `::columnar::chain(left, right)` calls.
///
/// This produces O(log N) nesting depth instead of O(N), avoiding the compiler's
/// recursion limit on enums/structs with many fields.
fn balanced_chain(iters: &[proc_macro2::TokenStream]) -> proc_macro2::TokenStream {
match iters {
[] => quote! { None.into_iter() },
[one] => one.clone(),
_ => {
let mid = iters.len() / 2;
let left = balanced_chain(&iters[..mid]);
let right = balanced_chain(&iters[mid..]);
quote! { ::columnar::chain(#left, #right) }
}
}
}

#[proc_macro_derive(Columnar, attributes(columnar))]
pub fn derive(input: TokenStream) -> TokenStream {

Expand Down Expand Up @@ -296,14 +313,15 @@ fn derive_struct(name: &syn::Ident, generics: &syn::Generics, data_struct: syn::
let ty_gen = quote! { < #(#container_types),* > };
let where_clause = quote! { where #(#container_types: ::columnar::AsBytes<'a>),* };

let field_iters: Vec<_> = names.iter().map(|n| quote! { self.#n.as_bytes() }).collect();
let chain_expr = balanced_chain(&field_iters);

quote! {
impl #impl_gen ::columnar::AsBytes<'a> for #c_ident #ty_gen #where_clause {
// type Borrowed<'columnar> = #c_ident < #(<#container_types as ::columnar::AsBytes>::Borrowed<'columnar>,)*>;
#[inline(always)]
fn as_bytes(&self) -> impl Iterator<Item=(u64, &'a [u8])> {
let iter = None.into_iter();
#( let iter = ::columnar::chain(iter, self.#names.as_bytes()); )*
iter
#chain_expr
}
}
}
Expand Down Expand Up @@ -888,14 +906,15 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
let ty_gen = quote! { < #(#container_types,)* CVar, COff > };
let where_clause = quote! { where #(#container_types: ::columnar::AsBytes<'a>,)* ::columnar::Discriminant<CVar, COff>: ::columnar::AsBytes<'a> };

let mut field_iters: Vec<_> = names.iter().map(|n| quote! { self.#n.as_bytes() }).collect();
field_iters.push(quote! { self.indexes.as_bytes() });
let chain_expr = balanced_chain(&field_iters);

quote! {
impl #impl_gen ::columnar::AsBytes<'a> for #c_ident #ty_gen #where_clause {
#[inline(always)]
fn as_bytes(&self) -> impl Iterator<Item=(u64, &'a [u8])> {
let iter = None.into_iter();
#( let iter = ::columnar::chain(iter,self.#names.as_bytes()); )*
let iter = ::columnar::chain(iter, self.indexes.as_bytes());
iter
#chain_expr
}
}
}
Expand Down
315 changes: 315 additions & 0 deletions examples/enum_as_bytes_asm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,315 @@
//! Assembly inspection for enum as_bytes paths.
//!
//! Build with: `cargo rustc --example enum_as_bytes_asm --release -- --emit asm`

use columnar::*;
use columnar::bytes::indexed;

#[derive(Columnar)]
pub enum Small {
Click(u64, u64),
Scroll(i64),
Key(String),
}

#[derive(Columnar)]
pub enum Big {
V0(u64),
V1(u64),
V2(u64),
V3(u64),
V4(u64),
V5(u64),
V6(u64),
V7(u64),
V8(u64),
V9(u64),
V10(u64),
V11(u64),
V12(u64),
V13(u64),
V14(u64),
V15(u64),
V16(u64),
V17(u64),
V18(u64),
V19(u64),
V20(u64),
V21(u64),
V22(u64),
V23(u64),
V24(u64),
V25(u64),
V26(u64),
V27(u64),
V28(u64),
V29(u64),
V30(u64),
V31(u64),
V32(u64),
V33(u64),
V34(u64),
V35(u64),
V36(u64),
V37(u64),
V38(u64),
V39(u64),
V40(u64),
V41(u64),
V42(u64),
V43(u64),
V44(u64),
V45(u64),
V46(u64),
V47(u64),
V48(u64),
V49(u64),
V50(u64),
V51(u64),
V52(u64),
V53(u64),
V54(u64),
V55(u64),
V56(u64),
V57(u64),
V58(u64),
V59(u64),
V60(u64),
V61(u64),
V62(u64),
V63(u64),
V64(u64),
V65(u64),
V66(u64),
V67(u64),
V68(u64),
V69(u64),
V70(u64),
V71(u64),
V72(u64),
V73(u64),
V74(u64),
V75(u64),
V76(u64),
V77(u64),
V78(u64),
V79(u64),
V80(u64),
V81(u64),
V82(u64),
V83(u64),
V84(u64),
V85(u64),
V86(u64),
V87(u64),
V88(u64),
V89(u64),
V90(u64),
V91(u64),
V92(u64),
V93(u64),
V94(u64),
V95(u64),
V96(u64),
V97(u64),
V98(u64),
V99(u64),
V100(u64),
V101(u64),
V102(u64),
V103(u64),
V104(u64),
V105(u64),
V106(u64),
V107(u64),
V108(u64),
V109(u64),
V110(u64),
V111(u64),
V112(u64),
V113(u64),
V114(u64),
V115(u64),
V116(u64),
V117(u64),
V118(u64),
V119(u64),
V120(u64),
V121(u64),
V122(u64),
V123(u64),
V124(u64),
V125(u64),
V126(u64),
V127(u64),
V128(u64),
V129(u64),
V130(u64),
V131(u64),
V132(u64),
V133(u64),
V134(u64),
V135(u64),
V136(u64),
V137(u64),
V138(u64),
V139(u64),
V140(u64),
V141(u64),
V142(u64),
V143(u64),
V144(u64),
V145(u64),
V146(u64),
V147(u64),
V148(u64),
V149(u64),
V150(u64),
V151(u64),
V152(u64),
V153(u64),
V154(u64),
V155(u64),
V156(u64),
V157(u64),
V158(u64),
V159(u64),
V160(u64),
V161(u64),
V162(u64),
V163(u64),
V164(u64),
V165(u64),
V166(u64),
V167(u64),
V168(u64),
V169(u64),
V170(u64),
V171(u64),
V172(u64),
V173(u64),
V174(u64),
V175(u64),
V176(u64),
V177(u64),
V178(u64),
V179(u64),
V180(u64),
V181(u64),
V182(u64),
V183(u64),
V184(u64),
V185(u64),
V186(u64),
V187(u64),
V188(u64),
V189(u64),
V190(u64),
V191(u64),
V192(u64),
V193(u64),
V194(u64),
V195(u64),
V196(u64),
V197(u64),
V198(u64),
V199(u64),
V200(u64),
V201(u64),
V202(u64),
V203(u64),
V204(u64),
V205(u64),
V206(u64),
V207(u64),
V208(u64),
V209(u64),
V210(u64),
V211(u64),
V212(u64),
V213(u64),
V214(u64),
V215(u64),
V216(u64),
V217(u64),
V218(u64),
V219(u64),
V220(u64),
V221(u64),
V222(u64),
V223(u64),
V224(u64),
V225(u64),
V226(u64),
V227(u64),
V228(u64),
V229(u64),
V230(u64),
V231(u64),
V232(u64),
V233(u64),
V234(u64),
V235(u64),
V236(u64),
V237(u64),
V238(u64),
V239(u64),
V240(u64),
V241(u64),
V242(u64),
V243(u64),
V244(u64),
V245(u64),
V246(u64),
V247(u64),
V248(u64),
V249(u64),
V250(u64),
V251(u64),
V252(u64),
V253(u64),
V254(u64),
V255(u64),
}

type SmallBorrowed<'a> = BorrowedOf<'a, Small>;
type BigBorrowed<'a> = BorrowedOf<'a, Big>;

/// Count the number of byte slices produced by as_bytes (small enum).
#[no_mangle]
pub fn small_as_bytes_count(container: &SmallBorrowed<'_>) -> usize {
container.as_bytes().count()
}

/// Sum the lengths of all byte slices (small enum).
#[no_mangle]
pub fn small_as_bytes_total_len(container: &SmallBorrowed<'_>) -> usize {
container.as_bytes().map(|(_, b)| b.len()).sum()
}

/// Count the number of byte slices produced by as_bytes (big 256-variant enum).
#[no_mangle]
pub fn big_as_bytes_count(container: &BigBorrowed<'_>) -> usize {
container.as_bytes().count()
}

/// Sum the lengths of all byte slices (big 256-variant enum).
#[no_mangle]
pub fn big_as_bytes_total_len(container: &BigBorrowed<'_>) -> usize {
container.as_bytes().map(|(_, b)| b.len()).sum()
}

/// Encode a small enum container into bytes.
#[no_mangle]
pub fn small_encode(container: &SmallBorrowed<'_>, store: &mut Vec<u64>) {
indexed::encode(store, container);
}

/// Encode a big enum container into bytes.
#[no_mangle]
pub fn big_encode(container: &BigBorrowed<'_>, store: &mut Vec<u64>) {
indexed::encode(store, container);
}

fn main() {}

Loading