Skip to content

Commit

Permalink
fix(derive): ArrayType derive for unit structs
Browse files Browse the repository at this point in the history
  • Loading branch information
mbrobbel committed Jul 27, 2023
1 parent 17bf994 commit e951ed1
Show file tree
Hide file tree
Showing 11 changed files with 430 additions and 162 deletions.
24 changes: 23 additions & 1 deletion narrow-derive/src/struct/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::util;
use proc_macro2::TokenStream;
use syn::{DeriveInput, Fields};
use quote::{format_ident, quote};
use syn::{DeriveInput, Fields, Generics, Ident};

mod unit;

Expand All @@ -9,3 +11,23 @@ pub(super) fn derive(input: &DeriveInput, fields: &Fields) -> TokenStream {
_ => todo!("non unit structs derive"),
}
}

fn array_type_ident(ident: &Ident) -> Ident {
format_ident!("{}Array", ident)
}

fn array_type_impl(ident: &Ident, generics: &Generics) -> TokenStream {
let narrow = util::narrow();

let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

quote! {
impl #impl_generics #narrow::array::ArrayType for #ident #ty_generics #where_clause {
type Array<Buffer: #narrow::buffer::BufferType> = #narrow::array::StructArray<#ident #ty_generics, false, Buffer>;
}

impl #impl_generics #narrow::array::ArrayType<#ident #ty_generics> for ::std::option::Option<#ident #ty_generics> #where_clause {
type Array<Buffer: #narrow::buffer::BufferType> = #narrow::array::StructArray<#ident #ty_generics, true, Buffer>;
}
}
}
246 changes: 156 additions & 90 deletions narrow-derive/src/struct/unit.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use crate::{
r#struct::{array_type_ident, array_type_impl},
util,
};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{parse_quote, visit_mut::VisitMut, DeriveInput, Generics, Ident, Visibility};

use crate::util;
use quote::quote;
use syn::{
parse_quote, DeriveInput, Generics, Ident, ImplGenerics, TypeGenerics, Visibility, WhereClause,
};

pub(super) fn derive(input: &DeriveInput) -> TokenStream {
let DeriveInput {
Expand All @@ -12,117 +16,179 @@ pub(super) fn derive(input: &DeriveInput) -> TokenStream {
..
} = input;

// let narrow = util::narrow();

// Construct the raw array wrapper.
// let raw_array_def = quote! {
// #[doc = #raw_array_doc]
// #vis struct #raw_array_ident #array_generics
// (#narrow::array::null::NullArray<#ident #ty_generics>) #array_where_clause;
// };

// Add NullArray generics.
// let mut array_generics = generics.clone();
// AddNullableConstGeneric.visit_generics_mut(&mut array_generics);

// // let generics = SelfReplace::generics(&ident, &generics);
// let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

// // Replace `Self` with ident in where clauses.
// let mut where_clause = where_clause.cloned();
// where_clause
// .as_mut()
// .map(|where_clause|
// SelfReplace(&ident).visit_where_clause_mut(where_clause));

// let array_generics = SelfReplace::generics(ident, generics);
// let (array_impl_generics, array_ty_generics, array_where_clause) =
// array_generics.split_for_impl();

// // Add a type definition for the array of this type.
// let alias_array_ident = util::alias_array_ident(&ident);
// let alias_array = quote!(
// #[doc = #raw_array_doc]
// #[automatically_derived]
// #vis type #alias_array_ident #generics #where_clause =
// #narrow::array::r#struct::StructArray<#ident #ty_generics>; );

// Implement ArrayType for this type.
// let array_type_impl = quote! {
// #[automatically_derived]
// impl #impl_generics #narrow::array::ArrayType for #ident #ty_generics
// #where_clause { type Array<const N: bool, T: OffsetValue> =
// #raw_array_ident #array_generics; }
// };

let raw_array = raw_array_def(vis, ident, generics);

// todo impl unit for this type
// Generate the ArrayType implementation.
let array_type_impl = array_type_impl(ident, generics);

// Generate the StructArrayType implementation.
let struct_array_type_impl = struct_array_type_impl(ident, generics);

// Generate the Unit implementation.
let unit_impl = unit_impl(ident, generics);

// Generate the array type definition.
let array_type_def = array_type_def(vis, ident, generics);

// Generate the length impl.
let length_impl = length_impl(ident, generics);

// Generate the FromIterator impl.
let from_iterator_impl = from_iterator_impl(ident, generics);

// Generate the Extend impl.
let extend_impl = extend_impl(ident, generics);

// Generate the Default impl.
let default_impl = default_impl(ident, generics);

quote! {
#array_type_impl

#struct_array_type_impl

#unit_impl

#array_type_def

#from_iterator_impl

#length_impl

#extend_impl

#default_impl
}
}

fn unit_impl(ident: &Ident, generics: &Generics) -> TokenStream {
let narrow = util::narrow();

let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

quote! {
#raw_array
/// Safety:
/// - This is a unit struct.
unsafe impl #impl_generics #narrow::array::Unit for #ident #ty_generics #where_clause {}
}
}

fn struct_array_type_impl(ident: &Ident, generics: &Generics) -> TokenStream {
let narrow = util::narrow();

let array_type_ident = array_type_ident(ident);

// #array_type_impl
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

let array_generics = NullArrayGenerics::new(generics);
let (_, ty_generics_with_buffer, _) = array_generics.split_for_impl();

quote! {
impl #impl_generics #narrow::array::StructArrayType for #ident #ty_generics #where_clause {
type Array<Buffer: #narrow::buffer::BufferType> = #array_type_ident #ty_generics_with_buffer;
}
}
// #alias_array
// }
}

pub(super) fn raw_array_def(vis: &Visibility, ident: &Ident, generics: &Generics) -> TokenStream {
fn array_type_def(vis: &Visibility, ident: &Ident, generics: &Generics) -> TokenStream {
let narrow = util::narrow();

// Get the ident and doc for the raw array struct.
let (raw_array_ident, raw_array_doc) = util::raw_array(ident);
let array_type_ident = array_type_ident(ident);

// Get the ty_generics of the inner type.
let (_, ty_generics, where_clause) = generics.split_for_impl();

// Add the const generic trait bound for nullability.
let generics = NullArrayGenerics::generics(generics);
let nullarray_nullable = NullArrayGenerics::nullable_generic();
let nullarray_validity_bitmap_buffer = NullArrayGenerics::validity_bitmap_buffer_generic();
// let (_, _, _) = generics.split_for_impl();
let array_generics = NullArrayGenerics::new(generics);
let (impl_generics_with_buffer, _, _) = array_generics.split_for_impl();

quote! {
#[doc = #raw_array_doc]
#vis struct #raw_array_ident #generics(
#narrow::array::null::NullArray<
#ident #ty_generics,
#nullarray_nullable,
#nullarray_validity_bitmap_buffer
>
) #where_clause;
#vis struct #array_type_ident #impl_generics_with_buffer(
#narrow::array::NullArray<#ident #ty_generics, false, Buffer>
) #where_clause;
}
}

struct NullArrayGenerics;
fn from_iterator_impl(ident: &Ident, generics: &Generics) -> TokenStream {
let array_type_ident = array_type_ident(ident);

impl NullArrayGenerics {
fn generics(generics: &Generics) -> Generics {
let mut generics = generics.clone();
Self.visit_generics_mut(&mut generics);
generics
let (_, ty_generics, where_clause) = generics.split_for_impl();

let array_generics = NullArrayGenerics::new(generics);
let (impl_generics_with_buffer, ty_generics_with_buffer, _) = array_generics.split_for_impl();

quote! {
impl #impl_generics_with_buffer ::std::iter::FromIterator<#ident #ty_generics> for #array_type_ident #ty_generics_with_buffer #where_clause {
fn from_iter<_I: ::std::iter::IntoIterator<Item = #ident #ty_generics>>(iter: _I) -> Self {
Self(iter.into_iter().collect())
}
}
}
}

fn length_impl(ident: &Ident, generics: &Generics) -> TokenStream {
let narrow = util::narrow();

fn nullable_generic() -> Ident {
format_ident!("_NARROW_NULLABLE")
let array_type_ident = array_type_ident(ident);

let (_, _ty_generics, where_clause) = generics.split_for_impl();

let array_generics = NullArrayGenerics::new(generics);
let (impl_generics_with_buffer, ty_generics_with_buffer, _) = array_generics.split_for_impl();

quote! {
impl #impl_generics_with_buffer #narrow::Length for #array_type_ident #ty_generics_with_buffer #where_clause {
#[inline]
fn len(&self) -> usize {
self.0.len()
}
}
}
}

fn extend_impl(ident: &Ident, generics: &Generics) -> TokenStream {
let array_type_ident = array_type_ident(ident);

fn validity_bitmap_buffer_generic() -> Ident {
format_ident!("_NARROW_VALIDITY_BITMAP_BUFFER")
let (_, ty_generics, where_clause) = generics.split_for_impl();

let array_generics = NullArrayGenerics::new(generics);
let (impl_generics_with_buffer, ty_generics_with_buffer, _) = array_generics.split_for_impl();

quote! {
impl #impl_generics_with_buffer ::std::iter::Extend<#ident #ty_generics> for #array_type_ident #ty_generics_with_buffer #where_clause {
fn extend<_I: ::std::iter::IntoIterator<Item=#ident #ty_generics>>(&mut self, iter: _I) {
self.0.extend(iter)
}
}
}
}

impl VisitMut for NullArrayGenerics {
fn visit_generics_mut(&mut self, generics: &mut Generics) {
let nullable = Self::nullable_generic();
generics
.params
.push(parse_quote!(const #nullable: bool = false));
fn default_impl(ident: &Ident, generics: &Generics) -> TokenStream {
let array_type_ident = array_type_ident(ident);

let (_, _, where_clause) = generics.split_for_impl();

let array_generics = NullArrayGenerics::new(generics);
let (impl_generics_with_buffer, ty_generics_with_buffer, _) = array_generics.split_for_impl();

quote! {
impl #impl_generics_with_buffer ::std::default::Default for #array_type_ident #ty_generics_with_buffer #where_clause {
fn default() -> Self {
Self(::std::default::Default::default())
}
}
}
}

struct NullArrayGenerics(Generics);

let validity_bitmap_buffer = Self::validity_bitmap_buffer_generic();
generics
impl NullArrayGenerics {
fn new(generics: &Generics) -> Self {
let narrow = util::narrow();

let mut generics_with_buffer = generics.clone();
generics_with_buffer
.params
.push(parse_quote!(#validity_bitmap_buffer = Vec<u8>));
.push(parse_quote!(Buffer: #narrow::buffer::BufferType = #narrow::buffer::VecBuffer));
Self(generics_with_buffer)
}
fn split_for_impl(&self) -> (ImplGenerics, TypeGenerics, Option<&WhereClause>) {
self.0.split_for_impl()
}
}
16 changes: 1 addition & 15 deletions narrow-derive/src/util/mod.rs → narrow-derive/src/util.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,17 @@
use crate::NARROW;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{
parse_quote, visit::Visit, visit_mut::VisitMut, Generics, Ident, Type, TypePath, WherePredicate,
};

use crate::NARROW;

mod bounds;

/// Returns the name of the `narrow` crate. Panics when the `narrow` crate is
/// not found.
pub(super) fn narrow() -> TokenStream {
let ident = format_ident!("{}", &*NARROW);
quote!(#ident)
}

pub(super) fn raw_array(ident: &Ident) -> (Ident, String) {
(
format_ident!("Raw{}Array", ident),
format!(" Array with [{ident}] values."),
)
}

// pub(super) fn alias_array_ident(ident: &Ident) -> Ident {
// format_ident!("{}Array", ident)
// }

/// Replace Self with ident in where clauses.
pub(super) struct SelfReplace<'a> {
ident: &'a Ident,
Expand Down
1 change: 0 additions & 1 deletion narrow-derive/src/util/bounds.rs

This file was deleted.

Loading

0 comments on commit e951ed1

Please sign in to comment.