use proc_macro2::{Span, TokenStream};
use syn::Ident;
use quote::TokenStreamExt;
use structs::Struct;
pub fn derive_slice(input: &Struct) -> TokenStream {
let other_derive = &input.derive_with_exceptions();
let visibility = &input.visibility;
let slice_name = &input.slice_name();
let vec_name = &input.vec_name();
let ref_name = &input.ref_name();
let slice_name_str = format!("[{}]", input.name);
let doc_url = format!("[`{0}`](struct.{0}.html)", input.name);
let vec_doc_url = format!("[`{0}`](struct.{0}.html)", input.vec_name());
let fields_names = input.fields.iter()
.map(|field| field.ident.clone().unwrap())
.collect::<Vec<_>>();
let fields_names_1 = &fields_names;
let fields_names_2 = &fields_names;
let first_field = &fields_names[0];
let slice_names_1 = &input.fields.iter()
.map(|field| field.ident.as_ref().unwrap().to_string())
.map(|ident| Ident::new(&format!("{}_slice_1", ident), Span::call_site()))
.collect::<Vec<_>>();
let slice_names_2 = &input.fields.iter()
.map(|field| field.ident.as_ref().unwrap().to_string())
.map(|ident| Ident::new(&format!("{}_slice_2", ident), Span::call_site()))
.collect::<Vec<_>>();
let fields_types = &input.fields.iter()
.map(|field| &field.ty)
.collect::<Vec<_>>();
let fields_doc = fields_names.iter()
.map(|field| format!("A slice of `{0}` from a [`{1}`](struct.{1}.html)", field, vec_name))
.collect::<Vec<_>>();
let mut generated = quote! {
#[doc = #doc_url]
#[doc = #vec_doc_url]
#[allow(dead_code)]
#[derive(Copy, Clone)]
#other_derive
#visibility struct #slice_name<'a> {
#(
#[doc = #fields_doc]
pub #fields_names_1: &'a [#fields_types],
)*
}
#[allow(dead_code)]
impl<'a> #slice_name<'a> {
#[doc = #slice_name_str]
pub fn len(&self) -> usize {
let len = self.#first_field.len();
#(debug_assert_eq!(self.#fields_names_1.len(), len);)*
len
}
#[doc = #slice_name_str]
pub fn is_empty(&self) -> bool {
let empty = self.#first_field.is_empty();
#(debug_assert_eq!(self.#fields_names_1.is_empty(), empty);)*
empty
}
#[doc = #slice_name_str]
pub fn first(&self) -> Option<#ref_name> {
if self.is_empty() {
None
} else {
#(
let #fields_names_1 = self.#fields_names_2.first().unwrap();
)*
Some(#ref_name{#(#fields_names_1: #fields_names_2),*})
}
}
#[doc = #slice_name_str]
pub fn split_first(&self) -> Option<(#ref_name, #slice_name)> {
if self.is_empty() {
None
} else {
#(
let (#fields_names_1, #slice_names_1) = self.#fields_names_2.split_first().unwrap();
)*
let ref_ = #ref_name{#(#fields_names_1: #fields_names_2),*};
let slice = #slice_name{#(#fields_names_1: #slice_names_1),*};
Some((ref_, slice))
}
}
#[doc = #slice_name_str]
pub fn last(&self) -> Option<#ref_name> {
if self.is_empty() {
None
} else {
#(
let #fields_names_1 = self.#fields_names_2.last().unwrap();
)*
Some(#ref_name{#(#fields_names_1: #fields_names_2),*})
}
}
#[doc = #slice_name_str]
pub fn split_last(&self) -> Option<(#ref_name, #slice_name)> {
if self.is_empty() {
None
} else {
#(
let (#fields_names_1, #slice_names_1) = self.#fields_names_2.split_last().unwrap();
)*
let ref_ = #ref_name{#(#fields_names_1: #fields_names_2),*};
let slice = #slice_name{#(#fields_names_1: #slice_names_1),*};
Some((ref_, slice))
}
}
#[doc = #slice_name_str]
pub fn split_at(&self, mid: usize) -> (#slice_name, #slice_name) {
#(
let (#slice_names_1, #slice_names_2) = self.#fields_names_2.split_at(mid);
)*
let left = #slice_name{#(#fields_names_1: #slice_names_1),*};
let right = #slice_name{#(#fields_names_1: #slice_names_2),*};
(left, right)
}
#[doc = #slice_name_str]
pub fn get(&self, i: usize) -> Option<#ref_name> {
if self.is_empty() || i >= self.len() {
None
} else {
Some(#ref_name {
#(#fields_names_1: self.#fields_names_2.get(i).unwrap(),)*
})
}
}
#[doc = #slice_name_str]
pub unsafe fn get_unchecked(&self, i: usize) -> #ref_name {
#ref_name {
#(#fields_names_1: self.#fields_names_2.get_unchecked(i),)*
}
}
}
};
if input.derives.contains(&Ident::new("Clone", Span::call_site())) {
generated.append_all(quote!{
#[allow(dead_code)]
impl<'a> #slice_name<'a> {
#[doc = #slice_name_str]
pub fn to_vec(&self) -> #vec_name {
#vec_name {
#(#fields_names_1: self.#fields_names_2.to_vec(),)*
}
}
}
});
}
return generated;
}
pub fn derive_slice_mut(input: &Struct) -> TokenStream {
let other_derive = &input.derive_with_exceptions();
let visibility = &input.visibility;
let slice_name = &input.slice_name();
let slice_mut_name = &input.slice_mut_name();
let vec_name = &input.vec_name();
let ref_name = &input.ref_name();
let ref_mut_name = &input.ref_mut_name();
let slice_name_str = format!("[{}]", input.name);
let doc_url = format!("[`{0}`](struct.{0}.html)", input.name);
let slice_doc_url = format!("[`{0}`](struct.{0}.html)", slice_name);
let slice_mut_doc_url = format!("[`{0}`](struct.{0}.html)", slice_mut_name);
let vec_doc_url = format!("[`{0}`](struct.{0}.html)", input.vec_name());
let fields_names = input.fields.iter()
.map(|field| field.ident.clone().unwrap())
.collect::<Vec<_>>();
let fields_names_1 = &fields_names;
let fields_names_2 = &fields_names;
let first_field = &fields_names[0];
let slice_names_1 = &input.fields.iter()
.map(|field| field.ident.as_ref().unwrap().to_string())
.map(|ident| Ident::new(&format!("{}_slice_1", ident), Span::call_site()))
.collect::<Vec<_>>();
let slice_names_2 = &input.fields.iter()
.map(|field| field.ident.as_ref().unwrap().to_string())
.map(|ident| Ident::new(&format!("{}_slice_2", ident), Span::call_site()))
.collect::<Vec<_>>();
let fields_types = &input.fields.iter()
.map(|field| &field.ty)
.collect::<Vec<_>>();
let fields_doc = fields_names.iter()
.map(|field| format!("A mutable slice of `{0}` from a [`{1}`](struct.{1}.html)", field, vec_name))
.collect::<Vec<_>>();
let mut generated = quote! {
#[doc = #doc_url]
#[doc = #vec_doc_url]
#[allow(dead_code)]
#other_derive
#visibility struct #slice_mut_name<'a> {
#(
#[doc = #fields_doc]
pub #fields_names_1: &'a mut [#fields_types],
)*
}
#[allow(dead_code)]
impl<'a> #slice_mut_name<'a> {
#[doc = #slice_mut_doc_url]
#[doc = #slice_doc_url]
pub fn as_ref(&self) -> #slice_name {
#slice_name {
#(#fields_names_1: self.#fields_names_2,)*
}
}
#[doc = #slice_name_str]
pub fn len(&self) -> usize {
let len = self.#first_field.len();
#(debug_assert_eq!(self.#fields_names_1.len(), len);)*
len
}
#[doc = #slice_name_str]
pub fn is_empty(&self) -> bool {
let empty = self.#first_field.is_empty();
#(debug_assert_eq!(self.#fields_names_1.is_empty(), empty);)*
empty
}
#[doc = #slice_name_str]
pub fn first_mut(&mut self) -> Option<#ref_mut_name> {
if self.is_empty() {
None
} else {
#(
let #fields_names_1 = self.#fields_names_2.first_mut().unwrap();
)*
Some(#ref_mut_name{#(#fields_names_1: #fields_names_2),*})
}
}
#[doc = #slice_name_str]
pub fn split_first_mut(&mut self) -> Option<(#ref_mut_name, #slice_mut_name)> {
if self.is_empty() {
None
} else {
#(
let (#fields_names_1, #slice_names_1) = self.#fields_names_2.split_first_mut().unwrap();
)*
let ref_ = #ref_mut_name{#(#fields_names_1: #fields_names_2),*};
let slice = #slice_mut_name{#(#fields_names_1: #slice_names_1),*};
Some((ref_, slice))
}
}
#[doc = #slice_name_str]
pub fn last_mut(&mut self) -> Option<#ref_mut_name> {
if self.is_empty() {
None
} else {
#(
let #fields_names_1 = self.#fields_names_2.last_mut().unwrap();
)*
Some(#ref_mut_name{#(#fields_names_1: #fields_names_2),*})
}
}
#[doc = #slice_name_str]
pub fn split_last_mut(&mut self) -> Option<(#ref_mut_name, #slice_mut_name)> {
if self.is_empty() {
None
} else {
#(
let (#fields_names_1, #slice_names_1) = self.#fields_names_2.split_last_mut().unwrap();
)*
let ref_ = #ref_mut_name{#(#fields_names_1: #fields_names_2),*};
let slice = #slice_mut_name{#(#fields_names_1: #slice_names_1),*};
Some((ref_, slice))
}
}
#[doc = #slice_name_str]
pub fn split_at_mut(&mut self, mid: usize) -> (#slice_mut_name, #slice_mut_name) {
#(
let (#slice_names_1, #slice_names_2) = self.#fields_names_2.split_at_mut(mid);
)*
let left = #slice_mut_name{#(#fields_names_1: #slice_names_1),*};
let right = #slice_mut_name{#(#fields_names_1: #slice_names_2),*};
(left, right)
}
#[doc = #slice_name_str]
pub fn swap(&mut self, a: usize, b: usize) {
#(
self.#fields_names_1.swap(a, b);
)*
}
#[doc = #slice_name_str]
pub fn get(&self, i: usize) -> Option<#ref_name> {
if self.is_empty() || i >= self.len() {
None
} else {
Some(#ref_name {
#(#fields_names_1: self.#fields_names_2.get(i).unwrap(),)*
})
}
}
#[doc = #slice_name_str]
pub unsafe fn get_unchecked(&self, i: usize) -> #ref_name {
#ref_name {
#(#fields_names_1: self.#fields_names_2.get_unchecked(i),)*
}
}
#[doc = #slice_name_str]
pub fn get_mut(&mut self, i: usize) -> Option<#ref_mut_name> {
if self.is_empty() || i >= self.len() {
None
} else {
Some(#ref_mut_name {
#(#fields_names_1: self.#fields_names_2.get_mut(i).unwrap(),)*
})
}
}
#[doc = #slice_name_str]
pub unsafe fn get_unchecked_mut(&mut self, i: usize) -> #ref_mut_name {
#ref_mut_name {
#(#fields_names_1: self.#fields_names_2.get_unchecked_mut(i),)*
}
}
}
};
if input.derives.contains(&Ident::new("Clone", Span::call_site())) {
generated.append_all(quote!{
#[allow(dead_code)]
impl<'a> #slice_mut_name<'a> {
#[doc = #slice_name_str]
pub fn to_vec(&self) -> #vec_name {
#vec_name {
#(#fields_names_1: self.#fields_names_2.to_vec(),)*
}
}
}
});
}
return generated;
}