summaryrefslogtreecommitdiff
path: root/src/info_structures.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/info_structures.rs')
-rw-r--r--src/info_structures.rs304
1 files changed, 0 insertions, 304 deletions
diff --git a/src/info_structures.rs b/src/info_structures.rs
deleted file mode 100644
index 05dc734..0000000
--- a/src/info_structures.rs
+++ /dev/null
@@ -1,304 +0,0 @@
-use crate::utils::{make_generic_arguments, make_generic_consumers, replace_this_with_lifetime};
-use proc_macro2::{Ident, TokenStream};
-use quote::{format_ident, quote, ToTokens};
-use syn::{
- punctuated::Punctuated, token::Comma, Attribute, ConstParam, Error, GenericParam, Generics,
- LifetimeDef, Type, TypeParam, Visibility,
-};
-
-#[derive(Clone, Copy)]
-pub struct Options {
- pub do_no_doc: bool,
- pub do_pub_extras: bool,
-}
-
-#[derive(Clone, Copy, PartialEq)]
-pub enum FieldType {
- /// Not borrowed by other parts of the struct.
- Tail,
- /// Immutably borrowed by at least one other field.
- Borrowed,
- /// Mutably borrowed by one other field.
- BorrowedMut,
-}
-
-impl FieldType {
- pub fn is_tail(self) -> bool {
- self == Self::Tail
- }
-}
-
-#[derive(Clone)]
-pub struct BorrowRequest {
- pub index: usize,
- pub mutable: bool,
-}
-
-#[derive(Clone)]
-pub enum Derive {
- Debug,
- PartialEq,
- Eq,
-}
-
-#[derive(Copy, Clone)]
-pub enum BuilderType {
- Sync,
- Async,
- AsyncSend,
-}
-
-impl BuilderType {
- pub fn is_async(&self) -> bool {
- match self {
- BuilderType::Sync => false,
- _ => true,
- }
- }
-}
-
-#[derive(Clone)]
-pub struct StructInfo {
- pub derives: Vec<Derive>,
- pub ident: Ident,
- pub generics: Generics,
- pub vis: Visibility,
- pub fields: Vec<StructFieldInfo>,
- pub first_lifetime: Ident,
- pub attributes: Vec<Attribute>,
-}
-
-impl StructInfo {
- // The lifetime to use in place of 'this for internal implementations,
- // should never be exposed to the user.
- pub fn fake_lifetime(&self) -> Ident {
- return self.first_lifetime.clone();
- }
-
- pub fn generic_params(&self) -> &Punctuated<GenericParam, Comma> {
- &self.generics.params
- }
-
- /// Same as generic_params but with 'this and 'outer_borrow prepended.
- pub fn borrowed_generic_params(&self) -> TokenStream {
- if self.generic_params().is_empty() {
- quote! { <'outer_borrow, 'this> }
- } else {
- let mut new_generic_params = self.generic_params().clone();
- new_generic_params.insert(0, syn::parse_quote! { 'this });
- new_generic_params.insert(0, syn::parse_quote! { 'outer_borrow });
- quote! { <#new_generic_params> }
- }
- }
-
- /// Same as generic_params but without bounds and with '_ prepended twice.
- pub fn borrowed_generic_params_inferred(&self) -> TokenStream {
- use GenericParam::*;
- let params = self.generic_params().iter().map(|p| match p {
- Type(TypeParam { ident, .. }) | Const(ConstParam { ident, .. }) => {
- ident.to_token_stream()
- }
- Lifetime(LifetimeDef { lifetime, .. }) => lifetime.to_token_stream(),
- });
- quote! { <'_, '_, #(#params,)*> }
- }
-
- pub fn generic_arguments(&self) -> Vec<TokenStream> {
- make_generic_arguments(&self.generics)
- }
-
- /// Same as generic_arguments but with 'outer_borrow and 'this prepended.
- pub fn borrowed_generic_arguments(&self) -> Vec<TokenStream> {
- let mut args = self.generic_arguments();
- args.insert(0, quote! { 'this });
- args.insert(0, quote! { 'outer_borrow });
- args
- }
-
- pub fn generic_consumers(&self) -> impl Iterator<Item = (TokenStream, Ident)> {
- make_generic_consumers(&self.generics)
- }
-}
-
-#[derive(Clone)]
-pub struct StructFieldInfo {
- pub name: Ident,
- pub typ: Type,
- pub field_type: FieldType,
- pub vis: Visibility,
- pub borrows: Vec<BorrowRequest>,
- /// If this is true and borrows is empty, the struct will borrow from self in the future but
- /// does not require a builder to be initialized. It should not be able to be removed from the
- /// struct with into_heads.
- pub self_referencing: bool,
- /// If it is None, the user has not specified whether or not the field is covariant. If this is
- /// Some(false), we should avoid making borrow_* or borrow_*_mut functions as they will not
- /// be able to compile.
- pub covariant: Option<bool>,
-}
-
-#[derive(Clone)]
-pub enum ArgType {
- /// Used when the initial value of a field can be passed directly into the constructor.
- Plain(TokenStream),
- /// Used when a field requires self references and thus requires something that implements
- /// a builder function trait instead of a simple plain type.
- TraitBound(TokenStream),
-}
-
-impl StructFieldInfo {
- pub fn builder_name(&self) -> Ident {
- format_ident!("{}_builder", self.name)
- }
-
- pub fn illegal_ref_name(&self) -> Ident {
- format_ident!("{}_illegal_static_reference", self.name)
- }
-
- pub fn is_borrowed(&self) -> bool {
- self.field_type != FieldType::Tail
- }
-
- pub fn is_mutably_borrowed(&self) -> bool {
- self.field_type == FieldType::BorrowedMut
- }
-
- pub fn boxed(&self) -> TokenStream {
- let name = &self.name;
- quote! { ::ouroboros::macro_help::aliasable_boxed(#name) }
- }
-
- pub fn stored_type(&self) -> TokenStream {
- let t = &self.typ;
- if self.is_borrowed() {
- quote! { ::ouroboros::macro_help::AliasableBox<#t> }
- } else {
- quote! { #t }
- }
- }
-
- /// Returns code which takes a variable with the same name and type as this field and turns it
- /// into a static reference to its dereffed contents.
- pub fn make_illegal_static_reference(&self) -> TokenStream {
- let field_name = &self.name;
- let ref_name = self.illegal_ref_name();
- quote! {
- let #ref_name = unsafe {
- ::ouroboros::macro_help::change_lifetime(&*#field_name)
- };
- }
- }
-
- /// Like make_illegal_static_reference, but provides a mutable reference instead.
- pub fn make_illegal_static_mut_reference(&self) -> TokenStream {
- let field_name = &self.name;
- let ref_name = self.illegal_ref_name();
- quote! {
- let #ref_name = unsafe {
- ::ouroboros::macro_help::change_lifetime_mut(&mut *#field_name)
- };
- }
- }
-
- /// Generates an error requesting that the user explicitly specify whether or not the
- /// field's type is covariant.
- pub fn covariance_error(&self) {
- let error = concat!(
- "Ouroboros cannot automatically determine if this type is covariant.\n\n",
- "If it is covariant, it should be legal to convert any instance of that type to an ",
- "instance of that type where all usages of 'this are replaced with a smaller ",
- "lifetime. For example, Box<&'this i32> is covariant because it is legal to use it as ",
- "a Box<&'a i32> where 'this: 'a. In contrast, Fn(&'this i32) cannot be used as ",
- "Fn(&'a i32).\n\n",
- "To resolve this error, add #[covariant] or #[not_covariant] to the field.\n",
- );
- proc_macro_error::emit_error!(self.typ, error);
- }
-
- pub fn make_constructor_arg_type_impl(
- &self,
- info: &StructInfo,
- make_builder_return_type: impl FnOnce() -> TokenStream,
- ) -> Result<ArgType, Error> {
- let field_type = &self.typ;
- let fake_lifetime = info.fake_lifetime();
- if self.borrows.is_empty() {
- // Even if self_referencing is true, as long as borrows is empty, we don't need to use a
- // builder to construct it.
- let field_type =
- replace_this_with_lifetime(field_type.into_token_stream(), fake_lifetime.clone());
- Ok(ArgType::Plain(quote! { #field_type }))
- } else {
- let mut field_builder_params = Vec::new();
- for borrow in &self.borrows {
- if borrow.mutable {
- let field = &info.fields[borrow.index];
- let field_type = &field.typ;
- field_builder_params.push(quote! {
- &'this mut #field_type
- });
- } else {
- let field = &info.fields[borrow.index];
- let field_type = &field.typ;
- field_builder_params.push(quote! {
- &'this #field_type
- });
- }
- }
- let return_type = make_builder_return_type();
- let bound = quote! { for<'this> ::core::ops::FnOnce(#(#field_builder_params),*) -> #return_type };
- Ok(ArgType::TraitBound(bound))
- }
- }
-
- /// Returns a trait bound if `for_field` refers to any other fields, and a plain type if not. This
- /// is the type used in the constructor to initialize the value of `for_field`.
- pub fn make_constructor_arg_type(
- &self,
- info: &StructInfo,
- builder_type: BuilderType,
- ) -> Result<ArgType, Error> {
- let field_type = &self.typ;
- let return_ty_constructor = || match builder_type {
- BuilderType::AsyncSend => {
- quote! {
- ::core::pin::Pin<::ouroboros::macro_help::alloc::boxed::Box<
- dyn ::core::future::Future<Output=#field_type> + ::core::marker::Send + 'this>>
- }
- }
- BuilderType::Async => {
- quote! { ::core::pin::Pin<::ouroboros::macro_help::alloc::boxed::Box<
- dyn ::core::future::Future<Output=#field_type> + 'this>> }
- }
- BuilderType::Sync => quote! { #field_type },
- };
- self.make_constructor_arg_type_impl(info, return_ty_constructor)
- }
-
- /// Like make_constructor_arg_type, but used for the try_new constructor.
- pub fn make_try_constructor_arg_type(
- &self,
- info: &StructInfo,
- builder_type: BuilderType,
- ) -> Result<ArgType, Error> {
- let field_type = &self.typ;
- let return_ty_constructor = || match builder_type {
- BuilderType::AsyncSend => {
- quote! {
- ::core::pin::Pin<::ouroboros::macro_help::alloc::boxed::Box<
- dyn ::core::future::Future<Output=::core::result::Result<#field_type, Error_>>
- + ::core::marker::Send + 'this>>
- }
- }
- BuilderType::Async => {
- quote! {
- ::core::pin::Pin<::ouroboros::macro_help::alloc::boxed::Box<
- dyn ::core::future::Future<Output=::core::result::Result<#field_type, Error_>>
- + 'this>>
- }
- }
- BuilderType::Sync => quote! { ::core::result::Result<#field_type, Error_> },
- };
- self.make_constructor_arg_type_impl(info, return_ty_constructor)
- }
-}