WIP: use HdlOption[the_type_var] or UInt[123 + n] for creating types
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				/ test (push) Successful in 14s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	/ test (push) Successful in 14s
				
			This commit is contained in:
		
							parent
							
								
									cd99dbc849
								
							
						
					
					
						commit
						ee54404f06
					
				
					 18 changed files with 5894 additions and 6908 deletions
				
			
		| 
						 | 
				
			
			@ -7,13 +7,14 @@ jobs:
 | 
			
		|||
      - uses: https://code.forgejo.org/actions/checkout@v3
 | 
			
		||||
        with:
 | 
			
		||||
          fetch-depth: 0
 | 
			
		||||
      - run: |
 | 
			
		||||
          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.79.0
 | 
			
		||||
          source "$HOME/.cargo/env"
 | 
			
		||||
          echo "$PATH" >> "$GITHUB_PATH"
 | 
			
		||||
      - uses: https://github.com/Swatinem/rust-cache@v2
 | 
			
		||||
        with:
 | 
			
		||||
          save-if: ${{ github.ref == 'refs/heads/master' }}
 | 
			
		||||
      - run: cargo test
 | 
			
		||||
      - run: cargo test --features=unstable-doc
 | 
			
		||||
      - run: cargo doc --features=unstable-doc
 | 
			
		||||
# FIXME: uncomment once the code works again
 | 
			
		||||
#      - run: |
 | 
			
		||||
#          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.79.0
 | 
			
		||||
#          source "$HOME/.cargo/env"
 | 
			
		||||
#          echo "$PATH" >> "$GITHUB_PATH"
 | 
			
		||||
#      - uses: https://github.com/Swatinem/rust-cache@v2
 | 
			
		||||
#        with:
 | 
			
		||||
#          save-if: ${{ github.ref == 'refs/heads/master' }}
 | 
			
		||||
#      - run: cargo test
 | 
			
		||||
#      - run: cargo test --features=unstable-doc
 | 
			
		||||
#      - run: cargo doc --features=unstable-doc
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										766
									
								
								crates/fayalite-proc-macros-impl/src/hdl_bundle.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										766
									
								
								crates/fayalite-proc-macros-impl/src/hdl_bundle.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,766 @@
 | 
			
		|||
use crate::{
 | 
			
		||||
    hdl_type_common::{
 | 
			
		||||
        common_derives, get_target, ItemOptions, MaybeParsed, ParsedFieldsNamed, ParsedGenerics,
 | 
			
		||||
        SplitForImpl, TypesParser, WrappedInConst,
 | 
			
		||||
    },
 | 
			
		||||
    kw, Errors, HdlAttr, PairsIterExt,
 | 
			
		||||
};
 | 
			
		||||
use proc_macro2::TokenStream;
 | 
			
		||||
use quote::{format_ident, quote_spanned, ToTokens};
 | 
			
		||||
use syn::{
 | 
			
		||||
    parse_quote, parse_quote_spanned,
 | 
			
		||||
    punctuated::{Pair, Punctuated},
 | 
			
		||||
    spanned::Spanned,
 | 
			
		||||
    token::Brace,
 | 
			
		||||
    AngleBracketedGenericArguments, Attribute, Field, FieldMutability, Fields, FieldsNamed,
 | 
			
		||||
    GenericParam, Generics, Ident, ItemStruct, Path, Token, Type, Visibility,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub(crate) struct ParsedBundle {
 | 
			
		||||
    pub(crate) attrs: Vec<Attribute>,
 | 
			
		||||
    pub(crate) options: HdlAttr<ItemOptions>,
 | 
			
		||||
    pub(crate) vis: Visibility,
 | 
			
		||||
    pub(crate) struct_token: Token![struct],
 | 
			
		||||
    pub(crate) ident: Ident,
 | 
			
		||||
    pub(crate) generics: MaybeParsed<ParsedGenerics, Generics>,
 | 
			
		||||
    pub(crate) fields: MaybeParsed<ParsedFieldsNamed, FieldsNamed>,
 | 
			
		||||
    pub(crate) field_flips: Vec<Option<HdlAttr<kw::flip>>>,
 | 
			
		||||
    pub(crate) mask_type_ident: Ident,
 | 
			
		||||
    pub(crate) mask_type_match_variant_ident: Ident,
 | 
			
		||||
    pub(crate) match_variant_ident: Ident,
 | 
			
		||||
    pub(crate) builder_ident: Ident,
 | 
			
		||||
    pub(crate) mask_type_builder_ident: Ident,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ParsedBundle {
 | 
			
		||||
    fn parse_field(
 | 
			
		||||
        errors: &mut Errors,
 | 
			
		||||
        field: &mut Field,
 | 
			
		||||
        index: usize,
 | 
			
		||||
    ) -> Option<HdlAttr<kw::flip>> {
 | 
			
		||||
        let Field {
 | 
			
		||||
            attrs,
 | 
			
		||||
            vis: _,
 | 
			
		||||
            mutability,
 | 
			
		||||
            ident,
 | 
			
		||||
            colon_token,
 | 
			
		||||
            ty,
 | 
			
		||||
        } = field;
 | 
			
		||||
        let ident = ident.get_or_insert_with(|| format_ident!("_{}", index, span = ty.span()));
 | 
			
		||||
        if !matches!(mutability, FieldMutability::None) {
 | 
			
		||||
            // FIXME: use mutability as the spanned tokens,
 | 
			
		||||
            // blocked on https://github.com/dtolnay/syn/issues/1717
 | 
			
		||||
            errors.error(&ident, "field mutability is not supported");
 | 
			
		||||
            *mutability = FieldMutability::None;
 | 
			
		||||
        }
 | 
			
		||||
        *mutability = FieldMutability::None;
 | 
			
		||||
        colon_token.get_or_insert(Token));
 | 
			
		||||
        let options = errors.unwrap_or_default(HdlAttr::parse_and_take_attr(attrs));
 | 
			
		||||
        options
 | 
			
		||||
    }
 | 
			
		||||
    fn parse(item: ItemStruct) -> syn::Result<Self> {
 | 
			
		||||
        let ItemStruct {
 | 
			
		||||
            mut attrs,
 | 
			
		||||
            vis,
 | 
			
		||||
            struct_token,
 | 
			
		||||
            ident,
 | 
			
		||||
            mut generics,
 | 
			
		||||
            fields,
 | 
			
		||||
            semi_token,
 | 
			
		||||
        } = item;
 | 
			
		||||
        let mut errors = Errors::new();
 | 
			
		||||
        let mut options = errors
 | 
			
		||||
            .unwrap_or_default(HdlAttr::<ItemOptions>::parse_and_take_attr(&mut attrs))
 | 
			
		||||
            .unwrap_or_default();
 | 
			
		||||
        errors.ok(options.body.validate());
 | 
			
		||||
        let ItemOptions {
 | 
			
		||||
            outline_generated: _,
 | 
			
		||||
            connect_inexact: _,
 | 
			
		||||
            target: _,
 | 
			
		||||
            custom_bounds,
 | 
			
		||||
            no_static: _,
 | 
			
		||||
        } = options.body;
 | 
			
		||||
        let mut fields = match fields {
 | 
			
		||||
            syn::Fields::Named(fields) => fields,
 | 
			
		||||
            syn::Fields::Unnamed(fields) => {
 | 
			
		||||
                errors.error(&fields, "#[hdl] struct must use curly braces: {}");
 | 
			
		||||
                FieldsNamed {
 | 
			
		||||
                    brace_token: Brace(fields.paren_token.span),
 | 
			
		||||
                    named: fields.unnamed,
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            syn::Fields::Unit => {
 | 
			
		||||
                errors.error(&fields, "#[hdl] struct must use curly braces: {}");
 | 
			
		||||
                FieldsNamed {
 | 
			
		||||
                    brace_token: Brace(semi_token.unwrap_or_default().span),
 | 
			
		||||
                    named: Punctuated::default(),
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        let mut field_flips = Vec::with_capacity(fields.named.len());
 | 
			
		||||
        for (index, field) in fields.named.iter_mut().enumerate() {
 | 
			
		||||
            field_flips.push(Self::parse_field(&mut errors, field, index));
 | 
			
		||||
        }
 | 
			
		||||
        let generics = if custom_bounds.is_some() {
 | 
			
		||||
            MaybeParsed::Unrecognized(generics)
 | 
			
		||||
        } else if let Some(generics) = errors.ok(ParsedGenerics::parse(&mut generics)) {
 | 
			
		||||
            MaybeParsed::Parsed(generics)
 | 
			
		||||
        } else {
 | 
			
		||||
            MaybeParsed::Unrecognized(generics)
 | 
			
		||||
        };
 | 
			
		||||
        let fields = TypesParser::maybe_run(generics.as_ref(), fields, &mut errors);
 | 
			
		||||
        errors.finish()?;
 | 
			
		||||
        Ok(Self {
 | 
			
		||||
            attrs,
 | 
			
		||||
            options,
 | 
			
		||||
            vis,
 | 
			
		||||
            struct_token,
 | 
			
		||||
            generics,
 | 
			
		||||
            fields,
 | 
			
		||||
            field_flips,
 | 
			
		||||
            mask_type_ident: format_ident!("__{}__MaskType", ident),
 | 
			
		||||
            mask_type_match_variant_ident: format_ident!("__{}__MaskType__MatchVariant", ident),
 | 
			
		||||
            match_variant_ident: format_ident!("__{}__MatchVariant", ident),
 | 
			
		||||
            mask_type_builder_ident: format_ident!("__{}__MaskType__Builder", ident),
 | 
			
		||||
            builder_ident: format_ident!("__{}__Builder", ident),
 | 
			
		||||
            ident,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
struct Builder {
 | 
			
		||||
    vis: Visibility,
 | 
			
		||||
    struct_token: Token![struct],
 | 
			
		||||
    ident: Ident,
 | 
			
		||||
    target: Path,
 | 
			
		||||
    generics: Generics,
 | 
			
		||||
    fields: FieldsNamed,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
 | 
			
		||||
enum BuilderFieldState {
 | 
			
		||||
    Unfilled,
 | 
			
		||||
    Generic,
 | 
			
		||||
    Filled,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Builder {
 | 
			
		||||
    fn phantom_field_name(&self) -> Ident {
 | 
			
		||||
        format_ident!("__phantom", span = self.ident.span())
 | 
			
		||||
    }
 | 
			
		||||
    fn phantom_field(&self) -> Field {
 | 
			
		||||
        let target = &self.target;
 | 
			
		||||
        let type_generics = self.generics.split_for_impl().1;
 | 
			
		||||
        Field {
 | 
			
		||||
            attrs: vec![],
 | 
			
		||||
            vis: Visibility::Inherited,
 | 
			
		||||
            mutability: FieldMutability::None,
 | 
			
		||||
            ident: Some(self.phantom_field_name()),
 | 
			
		||||
            colon_token: Some(Token)),
 | 
			
		||||
            ty: parse_quote_spanned! {self.ident.span()=>
 | 
			
		||||
                ::fayalite::__std::marker::PhantomData<#target #type_generics>
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn builder_struct_generics(
 | 
			
		||||
        &self,
 | 
			
		||||
        mut get_field_state: impl FnMut(usize) -> BuilderFieldState,
 | 
			
		||||
    ) -> Generics {
 | 
			
		||||
        let mut retval = self.generics.clone();
 | 
			
		||||
        for (field_index, field) in self.fields.named.iter().enumerate() {
 | 
			
		||||
            match get_field_state(field_index) {
 | 
			
		||||
                BuilderFieldState::Unfilled | BuilderFieldState::Filled => continue,
 | 
			
		||||
                BuilderFieldState::Generic => {}
 | 
			
		||||
            }
 | 
			
		||||
            if !retval.params.empty_or_trailing() {
 | 
			
		||||
                retval.params.push_punct(Token));
 | 
			
		||||
            }
 | 
			
		||||
            retval.params.push_value(GenericParam::Type(
 | 
			
		||||
                type_var_for_field_name(field.ident.as_ref().unwrap()).into(),
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
        retval
 | 
			
		||||
    }
 | 
			
		||||
    fn builder_struct_ty(
 | 
			
		||||
        &self,
 | 
			
		||||
        mut get_field_state: impl FnMut(usize) -> BuilderFieldState,
 | 
			
		||||
    ) -> Type {
 | 
			
		||||
        let mut ty_arguments: AngleBracketedGenericArguments = if self.generics.params.is_empty() {
 | 
			
		||||
            parse_quote_spanned! {self.ident.span()=>
 | 
			
		||||
                <>
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            let builder_type_generics = self.generics.split_for_impl().1;
 | 
			
		||||
            parse_quote! { #builder_type_generics }
 | 
			
		||||
        };
 | 
			
		||||
        for (field_index, Field { ident, ty, .. }) in self.fields.named.iter().enumerate() {
 | 
			
		||||
            let ident = ident.as_ref().unwrap();
 | 
			
		||||
            if !ty_arguments.args.empty_or_trailing() {
 | 
			
		||||
                ty_arguments.args.push_punct(Token));
 | 
			
		||||
            }
 | 
			
		||||
            ty_arguments
 | 
			
		||||
                .args
 | 
			
		||||
                .push_value(match get_field_state(field_index) {
 | 
			
		||||
                    BuilderFieldState::Unfilled => parse_quote_spanned! {self.ident.span()=>
 | 
			
		||||
                        ::fayalite::bundle::Unfilled<#ty>
 | 
			
		||||
                    },
 | 
			
		||||
                    BuilderFieldState::Generic => {
 | 
			
		||||
                        let type_var = type_var_for_field_name(ident);
 | 
			
		||||
                        parse_quote_spanned! {self.ident.span()=>
 | 
			
		||||
                            #type_var
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    BuilderFieldState::Filled => parse_quote_spanned! {self.ident.span()=>
 | 
			
		||||
                        ::fayalite::expr::Expr<#ty>
 | 
			
		||||
                    },
 | 
			
		||||
                });
 | 
			
		||||
        }
 | 
			
		||||
        let ident = &self.ident;
 | 
			
		||||
        parse_quote_spanned! {ident.span()=>
 | 
			
		||||
            #ident #ty_arguments
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn type_var_for_field_name(ident: &Ident) -> Ident {
 | 
			
		||||
    format_ident!("__T_{}", ident)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn field_fn_for_field_name(ident: &Ident) -> Ident {
 | 
			
		||||
    format_ident!("field_{}", ident)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ToTokens for Builder {
 | 
			
		||||
    fn to_tokens(&self, tokens: &mut TokenStream) {
 | 
			
		||||
        let Self {
 | 
			
		||||
            vis,
 | 
			
		||||
            struct_token,
 | 
			
		||||
            ident,
 | 
			
		||||
            target,
 | 
			
		||||
            generics: _,
 | 
			
		||||
            fields,
 | 
			
		||||
        } = self;
 | 
			
		||||
        let phantom_field_name = self.phantom_field_name();
 | 
			
		||||
        let builder_struct = ItemStruct {
 | 
			
		||||
            attrs: vec![parse_quote_spanned! {ident.span()=>
 | 
			
		||||
                #[allow(non_camel_case_types, dead_code)]
 | 
			
		||||
            }],
 | 
			
		||||
            vis: vis.clone(),
 | 
			
		||||
            struct_token: *struct_token,
 | 
			
		||||
            ident: ident.clone(),
 | 
			
		||||
            generics: self.builder_struct_generics(|_| BuilderFieldState::Generic),
 | 
			
		||||
            fields: Fields::Named(FieldsNamed {
 | 
			
		||||
                brace_token: fields.brace_token,
 | 
			
		||||
                named: Punctuated::from_iter(
 | 
			
		||||
                    [Pair::Punctuated(
 | 
			
		||||
                        self.phantom_field(),
 | 
			
		||||
                        Token),
 | 
			
		||||
                    )]
 | 
			
		||||
                    .into_iter()
 | 
			
		||||
                    .chain(fields.named.pairs().map_pair_value_ref(|field| {
 | 
			
		||||
                        let ident = field.ident.as_ref().unwrap();
 | 
			
		||||
                        let type_var = type_var_for_field_name(ident);
 | 
			
		||||
                        Field {
 | 
			
		||||
                            vis: Visibility::Inherited,
 | 
			
		||||
                            ty: parse_quote_spanned! {ident.span()=>
 | 
			
		||||
                                #type_var
 | 
			
		||||
                            },
 | 
			
		||||
                            ..field.clone()
 | 
			
		||||
                        }
 | 
			
		||||
                    })),
 | 
			
		||||
                ),
 | 
			
		||||
            }),
 | 
			
		||||
            semi_token: None,
 | 
			
		||||
        };
 | 
			
		||||
        builder_struct.to_tokens(tokens);
 | 
			
		||||
        let field_idents = Vec::from_iter(
 | 
			
		||||
            self.fields
 | 
			
		||||
                .named
 | 
			
		||||
                .iter()
 | 
			
		||||
                .map(|field| field.ident.as_ref().unwrap()),
 | 
			
		||||
        );
 | 
			
		||||
        for (
 | 
			
		||||
            field_index,
 | 
			
		||||
            Field {
 | 
			
		||||
                vis,
 | 
			
		||||
                ident: field_ident,
 | 
			
		||||
                ty,
 | 
			
		||||
                ..
 | 
			
		||||
            },
 | 
			
		||||
        ) in self.fields.named.iter().enumerate()
 | 
			
		||||
        {
 | 
			
		||||
            let field_ident = field_ident.as_ref().unwrap();
 | 
			
		||||
            let fn_ident = field_fn_for_field_name(field_ident);
 | 
			
		||||
            let fn_generics = self.builder_struct_generics(|i| {
 | 
			
		||||
                if i == field_index {
 | 
			
		||||
                    BuilderFieldState::Unfilled
 | 
			
		||||
                } else {
 | 
			
		||||
                    BuilderFieldState::Generic
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            let (impl_generics, _, where_clause) = fn_generics.split_for_impl();
 | 
			
		||||
            let unfilled_ty = self.builder_struct_ty(|i| {
 | 
			
		||||
                if i == field_index {
 | 
			
		||||
                    BuilderFieldState::Unfilled
 | 
			
		||||
                } else {
 | 
			
		||||
                    BuilderFieldState::Generic
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            let filled_ty = self.builder_struct_ty(|i| {
 | 
			
		||||
                if i == field_index {
 | 
			
		||||
                    BuilderFieldState::Filled
 | 
			
		||||
                } else {
 | 
			
		||||
                    BuilderFieldState::Generic
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            let pat_fields =
 | 
			
		||||
                Vec::from_iter(self.fields.named.iter().enumerate().map(|(i, field)| {
 | 
			
		||||
                    let field_ident = field.ident.as_ref().unwrap();
 | 
			
		||||
                    if field_index == i {
 | 
			
		||||
                        quote_spanned! {self.ident.span()=>
 | 
			
		||||
                            #field_ident: _,
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        quote_spanned! {self.ident.span()=>
 | 
			
		||||
                            #field_ident,
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }));
 | 
			
		||||
            quote_spanned! {self.ident.span()=>
 | 
			
		||||
                #[automatically_derived]
 | 
			
		||||
                #[allow(non_camel_case_types, dead_code)]
 | 
			
		||||
                impl #impl_generics #unfilled_ty
 | 
			
		||||
                #where_clause
 | 
			
		||||
                {
 | 
			
		||||
                    #vis fn #fn_ident(
 | 
			
		||||
                        self,
 | 
			
		||||
                        #field_ident: ::fayalite::expr::Expr<#ty>,
 | 
			
		||||
                    ) -> #filled_ty {
 | 
			
		||||
                        let Self {
 | 
			
		||||
                            #phantom_field_name: _,
 | 
			
		||||
                            #(#pat_fields)*
 | 
			
		||||
                        } = self;
 | 
			
		||||
                        #ident {
 | 
			
		||||
                            #phantom_field_name: ::fayalite::__std::marker::PhantomData,
 | 
			
		||||
                            #(#field_idents,)*
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .to_tokens(tokens);
 | 
			
		||||
        }
 | 
			
		||||
        let unfilled_generics = self.builder_struct_generics(|_| BuilderFieldState::Unfilled);
 | 
			
		||||
        let unfilled_ty = self.builder_struct_ty(|_| BuilderFieldState::Unfilled);
 | 
			
		||||
        let (unfilled_impl_generics, _, unfilled_where_clause) = unfilled_generics.split_for_impl();
 | 
			
		||||
        quote_spanned! {self.ident.span()=>
 | 
			
		||||
            #[automatically_derived]
 | 
			
		||||
            #[allow(non_camel_case_types, dead_code)]
 | 
			
		||||
            impl #unfilled_impl_generics ::fayalite::__std::default::Default for #unfilled_ty
 | 
			
		||||
            #unfilled_where_clause
 | 
			
		||||
            {
 | 
			
		||||
                fn default() -> Self {
 | 
			
		||||
                    #ident {
 | 
			
		||||
                        #phantom_field_name: ::fayalite::__std::marker::PhantomData,
 | 
			
		||||
                        #(#field_idents: ::fayalite::__std::default::Default::default(),)*
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        .to_tokens(tokens);
 | 
			
		||||
        let filled_generics = self.builder_struct_generics(|_| BuilderFieldState::Filled);
 | 
			
		||||
        let filled_ty = self.builder_struct_ty(|_| BuilderFieldState::Filled);
 | 
			
		||||
        let (filled_impl_generics, _, filled_where_clause) = filled_generics.split_for_impl();
 | 
			
		||||
        let type_generics = self.generics.split_for_impl().1;
 | 
			
		||||
        quote_spanned! {self.ident.span()=>
 | 
			
		||||
            #[automatically_derived]
 | 
			
		||||
            #[allow(non_camel_case_types, dead_code)]
 | 
			
		||||
            impl #filled_impl_generics ::fayalite::expr::ToExpr for #filled_ty
 | 
			
		||||
            #filled_where_clause
 | 
			
		||||
            {
 | 
			
		||||
                type Type = #target #type_generics;
 | 
			
		||||
                fn to_expr(
 | 
			
		||||
                    &self,
 | 
			
		||||
                ) -> ::fayalite::expr::Expr<<Self as ::fayalite::expr::ToExpr>::Type> {
 | 
			
		||||
                    let __ty = #target {
 | 
			
		||||
                        #(#field_idents: ::fayalite::expr::Expr::ty(self.#field_idents),)*
 | 
			
		||||
                    };
 | 
			
		||||
                    let __field_values = [
 | 
			
		||||
                        #(::fayalite::expr::Expr::canonical(self.#field_idents),)*
 | 
			
		||||
                    ];
 | 
			
		||||
                    ::fayalite::expr::ToExpr::to_expr(
 | 
			
		||||
                        &::fayalite::expr::ops::BundleLiteral::new(__ty, &__field_values),
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        .to_tokens(tokens);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ToTokens for ParsedBundle {
 | 
			
		||||
    fn to_tokens(&self, tokens: &mut TokenStream) {
 | 
			
		||||
        let Self {
 | 
			
		||||
            attrs,
 | 
			
		||||
            options,
 | 
			
		||||
            vis,
 | 
			
		||||
            struct_token,
 | 
			
		||||
            ident,
 | 
			
		||||
            generics,
 | 
			
		||||
            fields,
 | 
			
		||||
            field_flips,
 | 
			
		||||
            mask_type_ident,
 | 
			
		||||
            mask_type_match_variant_ident,
 | 
			
		||||
            match_variant_ident,
 | 
			
		||||
            builder_ident,
 | 
			
		||||
            mask_type_builder_ident,
 | 
			
		||||
        } = self;
 | 
			
		||||
        let ItemOptions {
 | 
			
		||||
            outline_generated: _,
 | 
			
		||||
            connect_inexact,
 | 
			
		||||
            target,
 | 
			
		||||
            custom_bounds: _,
 | 
			
		||||
            no_static,
 | 
			
		||||
        } = &options.body;
 | 
			
		||||
        let target = get_target(target, ident);
 | 
			
		||||
        let mut item_attrs = attrs.clone();
 | 
			
		||||
        item_attrs.push(common_derives(ident.span()));
 | 
			
		||||
        ItemStruct {
 | 
			
		||||
            attrs: item_attrs,
 | 
			
		||||
            vis: vis.clone(),
 | 
			
		||||
            struct_token: *struct_token,
 | 
			
		||||
            ident: ident.clone(),
 | 
			
		||||
            generics: generics.into(),
 | 
			
		||||
            fields: Fields::Named(fields.clone().into()),
 | 
			
		||||
            semi_token: None,
 | 
			
		||||
        }
 | 
			
		||||
        .to_tokens(tokens);
 | 
			
		||||
        let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
 | 
			
		||||
        let mut wrapped_in_const = WrappedInConst::new(tokens, ident.span());
 | 
			
		||||
        let tokens = wrapped_in_const.inner();
 | 
			
		||||
        let builder = Builder {
 | 
			
		||||
            vis: vis.clone(),
 | 
			
		||||
            struct_token: *struct_token,
 | 
			
		||||
            ident: builder_ident.clone(),
 | 
			
		||||
            target: target.clone(),
 | 
			
		||||
            generics: generics.into(),
 | 
			
		||||
            fields: fields.clone().into(),
 | 
			
		||||
        };
 | 
			
		||||
        builder.to_tokens(tokens);
 | 
			
		||||
        let unfilled_builder_ty = builder.builder_struct_ty(|_| BuilderFieldState::Unfilled);
 | 
			
		||||
        let filled_builder_ty = builder.builder_struct_ty(|_| BuilderFieldState::Filled);
 | 
			
		||||
        let mut mask_type_fields = FieldsNamed::from(fields.clone());
 | 
			
		||||
        for Field { ident, ty, .. } in &mut mask_type_fields.named {
 | 
			
		||||
            let ident = ident.as_ref().unwrap();
 | 
			
		||||
            *ty = parse_quote_spanned! {ident.span()=>
 | 
			
		||||
                <#ty as ::fayalite::ty::Type>::MaskType
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        let mask_type_builder = Builder {
 | 
			
		||||
            vis: vis.clone(),
 | 
			
		||||
            struct_token: *struct_token,
 | 
			
		||||
            ident: mask_type_builder_ident.clone(),
 | 
			
		||||
            target: mask_type_ident.clone().into(),
 | 
			
		||||
            generics: generics.into(),
 | 
			
		||||
            fields: mask_type_fields.clone(),
 | 
			
		||||
        };
 | 
			
		||||
        mask_type_builder.to_tokens(tokens);
 | 
			
		||||
        let unfilled_mask_type_builder_ty =
 | 
			
		||||
            mask_type_builder.builder_struct_ty(|_| BuilderFieldState::Unfilled);
 | 
			
		||||
        let filled_mask_type_builder_ty =
 | 
			
		||||
            mask_type_builder.builder_struct_ty(|_| BuilderFieldState::Filled);
 | 
			
		||||
        ItemStruct {
 | 
			
		||||
            attrs: vec![
 | 
			
		||||
                common_derives(ident.span()),
 | 
			
		||||
                parse_quote_spanned! {ident.span()=>
 | 
			
		||||
                    #[allow(non_camel_case_types, dead_code)]
 | 
			
		||||
                },
 | 
			
		||||
            ],
 | 
			
		||||
            vis: vis.clone(),
 | 
			
		||||
            struct_token: *struct_token,
 | 
			
		||||
            ident: mask_type_ident.clone(),
 | 
			
		||||
            generics: generics.into(),
 | 
			
		||||
            fields: Fields::Named(mask_type_fields.clone()),
 | 
			
		||||
            semi_token: None,
 | 
			
		||||
        }
 | 
			
		||||
        .to_tokens(tokens);
 | 
			
		||||
        let mut mask_type_match_variant_fields = mask_type_fields;
 | 
			
		||||
        for Field { ident, ty, .. } in &mut mask_type_match_variant_fields.named {
 | 
			
		||||
            let ident = ident.as_ref().unwrap();
 | 
			
		||||
            *ty = parse_quote_spanned! {ident.span()=>
 | 
			
		||||
                ::fayalite::expr::Expr<#ty>
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        ItemStruct {
 | 
			
		||||
            attrs: vec![
 | 
			
		||||
                common_derives(ident.span()),
 | 
			
		||||
                parse_quote_spanned! {ident.span()=>
 | 
			
		||||
                    #[allow(non_camel_case_types, dead_code)]
 | 
			
		||||
                },
 | 
			
		||||
            ],
 | 
			
		||||
            vis: vis.clone(),
 | 
			
		||||
            struct_token: *struct_token,
 | 
			
		||||
            ident: mask_type_match_variant_ident.clone(),
 | 
			
		||||
            generics: generics.into(),
 | 
			
		||||
            fields: Fields::Named(mask_type_match_variant_fields),
 | 
			
		||||
            semi_token: None,
 | 
			
		||||
        }
 | 
			
		||||
        .to_tokens(tokens);
 | 
			
		||||
        let mut match_variant_fields = FieldsNamed::from(fields.clone());
 | 
			
		||||
        for Field { ident, ty, .. } in &mut match_variant_fields.named {
 | 
			
		||||
            let ident = ident.as_ref().unwrap();
 | 
			
		||||
            *ty = parse_quote_spanned! {ident.span()=>
 | 
			
		||||
                ::fayalite::expr::Expr<#ty>
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        ItemStruct {
 | 
			
		||||
            attrs: vec![
 | 
			
		||||
                common_derives(ident.span()),
 | 
			
		||||
                parse_quote_spanned! {ident.span()=>
 | 
			
		||||
                    #[allow(non_camel_case_types, dead_code)]
 | 
			
		||||
                },
 | 
			
		||||
            ],
 | 
			
		||||
            vis: vis.clone(),
 | 
			
		||||
            struct_token: *struct_token,
 | 
			
		||||
            ident: match_variant_ident.clone(),
 | 
			
		||||
            generics: generics.into(),
 | 
			
		||||
            fields: Fields::Named(match_variant_fields),
 | 
			
		||||
            semi_token: None,
 | 
			
		||||
        }
 | 
			
		||||
        .to_tokens(tokens);
 | 
			
		||||
        let match_variant_body_fields = Vec::from_iter(fields.named().into_iter().map(|field| {
 | 
			
		||||
            let ident: &Ident = field.ident().as_ref().unwrap();
 | 
			
		||||
            let ident_str = ident.to_string();
 | 
			
		||||
            quote_spanned! {ident.span()=>
 | 
			
		||||
                #ident: ::fayalite::expr::Expr::field(__this, #ident_str),
 | 
			
		||||
            }
 | 
			
		||||
        }));
 | 
			
		||||
        let mask_type_body_fields = Vec::from_iter(fields.named().into_iter().map(|field| {
 | 
			
		||||
            let ident: &Ident = field.ident().as_ref().unwrap();
 | 
			
		||||
            quote_spanned! {ident.span()=>
 | 
			
		||||
                #ident: ::fayalite::ty::Type::mask_type(&self.#ident),
 | 
			
		||||
            }
 | 
			
		||||
        }));
 | 
			
		||||
        let from_canonical_body_fields =
 | 
			
		||||
            Vec::from_iter(fields.named().into_iter().enumerate().zip(field_flips).map(
 | 
			
		||||
                |((index, field), flip)| {
 | 
			
		||||
                    let ident: &Ident = field.ident().as_ref().unwrap();
 | 
			
		||||
                    let ident_str = ident.to_string();
 | 
			
		||||
                    let flipped = flip.is_some();
 | 
			
		||||
                    quote_spanned! {ident.span()=>
 | 
			
		||||
                        #ident: {
 | 
			
		||||
                            let ::fayalite::bundle::BundleField {
 | 
			
		||||
                                name: __name,
 | 
			
		||||
                                flipped: __flipped,
 | 
			
		||||
                                ty: __ty,
 | 
			
		||||
                            } = __fields[#index];
 | 
			
		||||
                            ::fayalite::__std::assert_eq!(&*__name, #ident_str);
 | 
			
		||||
                            ::fayalite::__std::assert_eq!(__flipped, #flipped);
 | 
			
		||||
                            ::fayalite::ty::Type::from_canonical(__ty)
 | 
			
		||||
                        },
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
            ));
 | 
			
		||||
        let fields_body_fields = Vec::from_iter(fields.named().into_iter().zip(field_flips).map(
 | 
			
		||||
            |(field, flip)| {
 | 
			
		||||
                let ident: &Ident = field.ident().as_ref().unwrap();
 | 
			
		||||
                let ident_str = ident.to_string();
 | 
			
		||||
                let flipped = flip.is_some();
 | 
			
		||||
                quote_spanned! {ident.span()=>
 | 
			
		||||
                    ::fayalite::bundle::BundleField {
 | 
			
		||||
                        name: ::fayalite::intern::Intern::intern(#ident_str),
 | 
			
		||||
                        flipped: #flipped,
 | 
			
		||||
                        ty: ::fayalite::ty::Type::canonical(&self.#ident),
 | 
			
		||||
                    },
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
        ));
 | 
			
		||||
        let fields_len = fields.named().into_iter().len();
 | 
			
		||||
        quote_spanned! {ident.span()=>
 | 
			
		||||
            #[automatically_derived]
 | 
			
		||||
            impl #impl_generics ::fayalite::ty::Type for #mask_type_ident #type_generics
 | 
			
		||||
            #where_clause
 | 
			
		||||
            {
 | 
			
		||||
                type MaskType = #mask_type_ident #type_generics;
 | 
			
		||||
                type MatchVariant = #mask_type_match_variant_ident #type_generics;
 | 
			
		||||
                type MatchActiveScope = ();
 | 
			
		||||
                type MatchVariantAndInactiveScope = ::fayalite::ty::MatchVariantWithoutScope<
 | 
			
		||||
                    <Self as ::fayalite::ty::Type>::MatchVariant,
 | 
			
		||||
                >;
 | 
			
		||||
                type MatchVariantsIter = ::fayalite::__std::iter::Once<
 | 
			
		||||
                    <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope,
 | 
			
		||||
                >;
 | 
			
		||||
                fn match_variants(
 | 
			
		||||
                    __this: ::fayalite::expr::Expr<Self>,
 | 
			
		||||
                    __module_builder: &mut ::fayalite::module::ModuleBuilder<
 | 
			
		||||
                        ::fayalite::module::NormalModule,
 | 
			
		||||
                    >,
 | 
			
		||||
                    __source_location: ::fayalite::source_location::SourceLocation,
 | 
			
		||||
                ) -> <Self as ::fayalite::ty::Type>::MatchVariantsIter {
 | 
			
		||||
                    let __retval = #mask_type_match_variant_ident {
 | 
			
		||||
                        #(#match_variant_body_fields)*
 | 
			
		||||
                    };
 | 
			
		||||
                    ::fayalite::__std::iter::once(::fayalite::ty::MatchVariantWithoutScope(__retval))
 | 
			
		||||
                }
 | 
			
		||||
                fn mask_type(&self) -> <Self as ::fayalite::ty::Type>::MaskType {
 | 
			
		||||
                    *self
 | 
			
		||||
                }
 | 
			
		||||
                fn canonical(&self) -> ::fayalite::ty::CanonicalType {
 | 
			
		||||
                    ::fayalite::ty::Type::canonical(&::fayalite::bundle::Bundle::new(::fayalite::bundle::BundleType::fields(self)))
 | 
			
		||||
                }
 | 
			
		||||
                #[track_caller]
 | 
			
		||||
                fn from_canonical(__canonical_type: ::fayalite::ty::CanonicalType) -> Self {
 | 
			
		||||
                    let ::fayalite::ty::CanonicalType::Bundle(__bundle) = __canonical_type else {
 | 
			
		||||
                        ::fayalite::__std::panic!("expected bundle");
 | 
			
		||||
                    };
 | 
			
		||||
                    let __fields = ::fayalite::bundle::BundleType::fields(&__bundle);
 | 
			
		||||
                    ::fayalite::__std::assert_eq!(__fields.len(), #fields_len, "bundle has wrong number of fields");
 | 
			
		||||
                    Self {
 | 
			
		||||
                        #(#from_canonical_body_fields)*
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                fn source_location() -> ::fayalite::source_location::SourceLocation {
 | 
			
		||||
                    ::fayalite::source_location::SourceLocation::caller()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            #[automatically_derived]
 | 
			
		||||
            impl #impl_generics ::fayalite::bundle::BundleType for #mask_type_ident #type_generics
 | 
			
		||||
            #where_clause
 | 
			
		||||
            {
 | 
			
		||||
                type Builder = #unfilled_mask_type_builder_ty;
 | 
			
		||||
                type FilledBuilder = #filled_mask_type_builder_ty;
 | 
			
		||||
                fn fields(&self) -> ::fayalite::intern::Interned<[::fayalite::bundle::BundleField]> {
 | 
			
		||||
                    ::fayalite::intern::Intern::intern(&[#(#fields_body_fields)*][..])
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            #[automatically_derived]
 | 
			
		||||
            impl #impl_generics ::fayalite::ty::TypeWithDeref for #mask_type_ident #type_generics
 | 
			
		||||
            #where_clause
 | 
			
		||||
            {
 | 
			
		||||
                fn expr_deref(__this: &::fayalite::expr::Expr<Self>) -> &<Self as ::fayalite::ty::Type>::MatchVariant {
 | 
			
		||||
                    let __this = *__this;
 | 
			
		||||
                    let __retval = #mask_type_match_variant_ident {
 | 
			
		||||
                        #(#match_variant_body_fields)*
 | 
			
		||||
                    };
 | 
			
		||||
                    ::fayalite::intern::Interned::<_>::into_inner(::fayalite::intern::Intern::intern_sized(__retval))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            #[automatically_derived]
 | 
			
		||||
            impl #impl_generics ::fayalite::ty::Type for #target #type_generics
 | 
			
		||||
            #where_clause
 | 
			
		||||
            {
 | 
			
		||||
                type MaskType = #mask_type_ident #type_generics;
 | 
			
		||||
                type MatchVariant = #match_variant_ident #type_generics;
 | 
			
		||||
                type MatchActiveScope = ();
 | 
			
		||||
                type MatchVariantAndInactiveScope = ::fayalite::ty::MatchVariantWithoutScope<
 | 
			
		||||
                    <Self as ::fayalite::ty::Type>::MatchVariant,
 | 
			
		||||
                >;
 | 
			
		||||
                type MatchVariantsIter = ::fayalite::__std::iter::Once<
 | 
			
		||||
                    <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope,
 | 
			
		||||
                >;
 | 
			
		||||
                fn match_variants(
 | 
			
		||||
                    __this: ::fayalite::expr::Expr<Self>,
 | 
			
		||||
                    __module_builder: &mut ::fayalite::module::ModuleBuilder<
 | 
			
		||||
                        ::fayalite::module::NormalModule,
 | 
			
		||||
                    >,
 | 
			
		||||
                    __source_location: ::fayalite::source_location::SourceLocation,
 | 
			
		||||
                ) -> <Self as ::fayalite::ty::Type>::MatchVariantsIter {
 | 
			
		||||
                    let __retval = #match_variant_ident {
 | 
			
		||||
                        #(#match_variant_body_fields)*
 | 
			
		||||
                    };
 | 
			
		||||
                    ::fayalite::__std::iter::once(::fayalite::ty::MatchVariantWithoutScope(__retval))
 | 
			
		||||
                }
 | 
			
		||||
                fn mask_type(&self) -> <Self as ::fayalite::ty::Type>::MaskType {
 | 
			
		||||
                    #mask_type_ident {
 | 
			
		||||
                        #(#mask_type_body_fields)*
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                fn canonical(&self) -> ::fayalite::ty::CanonicalType {
 | 
			
		||||
                    ::fayalite::ty::Type::canonical(&::fayalite::bundle::Bundle::new(::fayalite::bundle::BundleType::fields(self)))
 | 
			
		||||
                }
 | 
			
		||||
                #[track_caller]
 | 
			
		||||
                fn from_canonical(__canonical_type: ::fayalite::ty::CanonicalType) -> Self {
 | 
			
		||||
                    let ::fayalite::ty::CanonicalType::Bundle(__bundle) = __canonical_type else {
 | 
			
		||||
                        ::fayalite::__std::panic!("expected bundle");
 | 
			
		||||
                    };
 | 
			
		||||
                    let __fields = ::fayalite::bundle::BundleType::fields(&__bundle);
 | 
			
		||||
                    ::fayalite::__std::assert_eq!(__fields.len(), #fields_len, "bundle has wrong number of fields");
 | 
			
		||||
                    Self {
 | 
			
		||||
                        #(#from_canonical_body_fields)*
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                fn source_location() -> ::fayalite::source_location::SourceLocation {
 | 
			
		||||
                    ::fayalite::source_location::SourceLocation::caller()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            #[automatically_derived]
 | 
			
		||||
            impl #impl_generics ::fayalite::bundle::BundleType for #target #type_generics
 | 
			
		||||
            #where_clause
 | 
			
		||||
            {
 | 
			
		||||
                type Builder = #unfilled_builder_ty;
 | 
			
		||||
                type FilledBuilder = #filled_builder_ty;
 | 
			
		||||
                fn fields(&self) -> ::fayalite::intern::Interned<[::fayalite::bundle::BundleField]> {
 | 
			
		||||
                    ::fayalite::intern::Intern::intern(&[#(#fields_body_fields)*][..])
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            #[automatically_derived]
 | 
			
		||||
            impl #impl_generics ::fayalite::ty::TypeWithDeref for #target #type_generics
 | 
			
		||||
            #where_clause
 | 
			
		||||
            {
 | 
			
		||||
                fn expr_deref(__this: &::fayalite::expr::Expr<Self>) -> &<Self as ::fayalite::ty::Type>::MatchVariant {
 | 
			
		||||
                    let __this = *__this;
 | 
			
		||||
                    let __retval = #match_variant_ident {
 | 
			
		||||
                        #(#match_variant_body_fields)*
 | 
			
		||||
                    };
 | 
			
		||||
                    ::fayalite::intern::Interned::<_>::into_inner(::fayalite::intern::Intern::intern_sized(__retval))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        .to_tokens(tokens);
 | 
			
		||||
        if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) {
 | 
			
		||||
            let static_generics = generics.clone().for_static_type();
 | 
			
		||||
            let (static_impl_generics, static_type_generics, static_where_clause) =
 | 
			
		||||
                static_generics.split_for_impl();
 | 
			
		||||
            let static_type_body_fields = Vec::from_iter(fields.named().into_iter().map(|field| {
 | 
			
		||||
                let ident: &Ident = field.ident().as_ref().unwrap();
 | 
			
		||||
                quote_spanned! {ident.span()=>
 | 
			
		||||
                    #ident: ::fayalite::ty::StaticType::static_type(),
 | 
			
		||||
                }
 | 
			
		||||
            }));
 | 
			
		||||
            quote_spanned! {ident.span()=>
 | 
			
		||||
                #[automatically_derived]
 | 
			
		||||
                impl #static_impl_generics ::fayalite::ty::StaticType for #mask_type_ident #static_type_generics
 | 
			
		||||
                #static_where_clause
 | 
			
		||||
                {
 | 
			
		||||
                    fn static_type() -> Self {
 | 
			
		||||
                        ::fayalite::ty::Type::mask_type(
 | 
			
		||||
                            &<#target #static_type_generics as ::fayalite::ty::StaticType>::static_type(),
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                #[automatically_derived]
 | 
			
		||||
                impl #static_impl_generics ::fayalite::ty::StaticType for #target #static_type_generics
 | 
			
		||||
                #static_where_clause
 | 
			
		||||
                {
 | 
			
		||||
                    fn static_type() -> Self {
 | 
			
		||||
                        Self {
 | 
			
		||||
                            #(#static_type_body_fields)*
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .to_tokens(tokens);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) fn hdl_bundle(item: ItemStruct) -> syn::Result<TokenStream> {
 | 
			
		||||
    let item = ParsedBundle::parse(item)?;
 | 
			
		||||
    let outline_generated = item.options.body.outline_generated;
 | 
			
		||||
    let mut contents = item.to_token_stream();
 | 
			
		||||
    if outline_generated.is_some() {
 | 
			
		||||
        contents = crate::outline_generated(contents, "hdl-bundle-");
 | 
			
		||||
    }
 | 
			
		||||
    Ok(contents)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										602
									
								
								crates/fayalite-proc-macros-impl/src/hdl_enum.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										602
									
								
								crates/fayalite-proc-macros-impl/src/hdl_enum.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,602 @@
 | 
			
		|||
use crate::{
 | 
			
		||||
    hdl_type_common::{
 | 
			
		||||
        common_derives, get_target, ItemOptions, MaybeParsed, ParsedGenerics, ParsedType,
 | 
			
		||||
        SplitForImpl, TypesParser, WrappedInConst,
 | 
			
		||||
    },
 | 
			
		||||
    Errors, HdlAttr, PairsIterExt,
 | 
			
		||||
};
 | 
			
		||||
use proc_macro2::TokenStream;
 | 
			
		||||
use quote::{format_ident, quote_spanned, ToTokens};
 | 
			
		||||
use syn::{
 | 
			
		||||
    parse_quote_spanned,
 | 
			
		||||
    punctuated::{Pair, Punctuated},
 | 
			
		||||
    token::{Brace, Paren},
 | 
			
		||||
    Attribute, Field, FieldMutability, Fields, FieldsNamed, FieldsUnnamed, Generics, Ident,
 | 
			
		||||
    ItemEnum, ItemStruct, Token, Type, Variant, Visibility,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
crate::options! {
 | 
			
		||||
    #[options = VariantOptions]
 | 
			
		||||
    pub(crate) enum VariantOption {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
crate::options! {
 | 
			
		||||
    #[options = FieldOptions]
 | 
			
		||||
    pub(crate) enum FieldOption {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub(crate) struct ParsedVariantField {
 | 
			
		||||
    pub(crate) paren_token: Paren,
 | 
			
		||||
    pub(crate) attrs: Vec<Attribute>,
 | 
			
		||||
    pub(crate) options: HdlAttr<FieldOptions>,
 | 
			
		||||
    pub(crate) ty: MaybeParsed<ParsedType, Type>,
 | 
			
		||||
    pub(crate) comma_token: Option<Token![,]>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub(crate) struct ParsedVariant {
 | 
			
		||||
    pub(crate) attrs: Vec<Attribute>,
 | 
			
		||||
    pub(crate) options: HdlAttr<VariantOptions>,
 | 
			
		||||
    pub(crate) ident: Ident,
 | 
			
		||||
    pub(crate) field: Option<ParsedVariantField>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ParsedVariant {
 | 
			
		||||
    fn parse(
 | 
			
		||||
        errors: &mut Errors,
 | 
			
		||||
        variant: Variant,
 | 
			
		||||
        generics: &MaybeParsed<ParsedGenerics, Generics>,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        let Variant {
 | 
			
		||||
            mut attrs,
 | 
			
		||||
            ident,
 | 
			
		||||
            fields,
 | 
			
		||||
            discriminant,
 | 
			
		||||
        } = variant;
 | 
			
		||||
        let options = errors
 | 
			
		||||
            .unwrap_or_default(HdlAttr::parse_and_take_attr(&mut attrs))
 | 
			
		||||
            .unwrap_or_default();
 | 
			
		||||
        let field = match fields {
 | 
			
		||||
            Fields::Unnamed(FieldsUnnamed {
 | 
			
		||||
                paren_token,
 | 
			
		||||
                unnamed,
 | 
			
		||||
            }) if unnamed.len() == 1 => {
 | 
			
		||||
                let (field, comma_token) = unnamed.into_pairs().next().unwrap().into_tuple();
 | 
			
		||||
                let Field {
 | 
			
		||||
                    mut attrs,
 | 
			
		||||
                    vis,
 | 
			
		||||
                    mutability,
 | 
			
		||||
                    ident: _,
 | 
			
		||||
                    colon_token: _,
 | 
			
		||||
                    ty,
 | 
			
		||||
                } = field;
 | 
			
		||||
                let options = errors
 | 
			
		||||
                    .unwrap_or_default(HdlAttr::parse_and_take_attr(&mut attrs))
 | 
			
		||||
                    .unwrap_or_default();
 | 
			
		||||
                if !matches!(vis, Visibility::Inherited) {
 | 
			
		||||
                    errors.error(
 | 
			
		||||
                        &vis,
 | 
			
		||||
                        "enum variant fields must not have a visibility specifier",
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
                if !matches!(mutability, FieldMutability::None) {
 | 
			
		||||
                    // FIXME: use mutability as the spanned tokens,
 | 
			
		||||
                    // blocked on https://github.com/dtolnay/syn/issues/1717
 | 
			
		||||
                    errors.error(&ty, "field mutability is not supported");
 | 
			
		||||
                }
 | 
			
		||||
                Some(ParsedVariantField {
 | 
			
		||||
                    paren_token,
 | 
			
		||||
                    attrs,
 | 
			
		||||
                    options,
 | 
			
		||||
                    ty: TypesParser::maybe_run(generics.as_ref(), ty, errors),
 | 
			
		||||
                    comma_token,
 | 
			
		||||
                })
 | 
			
		||||
            }
 | 
			
		||||
            Fields::Unit => None,
 | 
			
		||||
            Fields::Unnamed(fields) if fields.unnamed.is_empty() => None,
 | 
			
		||||
            Fields::Named(fields) if fields.named.is_empty() => None,
 | 
			
		||||
            Fields::Unnamed(_) | Fields::Named(_) => {
 | 
			
		||||
                errors.error(
 | 
			
		||||
                    fields,
 | 
			
		||||
                    "enum variant must either have no fields or a single parenthesized field",
 | 
			
		||||
                );
 | 
			
		||||
                None
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        if let Some((eq, _)) = discriminant {
 | 
			
		||||
            errors.error(eq, "custom enum discriminants are not allowed");
 | 
			
		||||
        }
 | 
			
		||||
        Self {
 | 
			
		||||
            attrs,
 | 
			
		||||
            options,
 | 
			
		||||
            ident,
 | 
			
		||||
            field,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub(crate) struct ParsedEnum {
 | 
			
		||||
    pub(crate) attrs: Vec<Attribute>,
 | 
			
		||||
    pub(crate) options: HdlAttr<ItemOptions>,
 | 
			
		||||
    pub(crate) vis: Visibility,
 | 
			
		||||
    pub(crate) enum_token: Token![enum],
 | 
			
		||||
    pub(crate) ident: Ident,
 | 
			
		||||
    pub(crate) generics: MaybeParsed<ParsedGenerics, Generics>,
 | 
			
		||||
    pub(crate) brace_token: Brace,
 | 
			
		||||
    pub(crate) variants: Punctuated<ParsedVariant, Token![,]>,
 | 
			
		||||
    pub(crate) match_variant_ident: Ident,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ParsedEnum {
 | 
			
		||||
    fn parse(item: ItemEnum) -> syn::Result<Self> {
 | 
			
		||||
        let ItemEnum {
 | 
			
		||||
            mut attrs,
 | 
			
		||||
            vis,
 | 
			
		||||
            enum_token,
 | 
			
		||||
            ident,
 | 
			
		||||
            mut generics,
 | 
			
		||||
            brace_token,
 | 
			
		||||
            variants,
 | 
			
		||||
        } = item;
 | 
			
		||||
        let mut errors = Errors::new();
 | 
			
		||||
        let mut options = errors
 | 
			
		||||
            .unwrap_or_default(HdlAttr::<ItemOptions>::parse_and_take_attr(&mut attrs))
 | 
			
		||||
            .unwrap_or_default();
 | 
			
		||||
        errors.ok(options.body.validate());
 | 
			
		||||
        let ItemOptions {
 | 
			
		||||
            outline_generated: _,
 | 
			
		||||
            connect_inexact: _,
 | 
			
		||||
            target: _,
 | 
			
		||||
            custom_bounds,
 | 
			
		||||
            no_static: _,
 | 
			
		||||
        } = options.body;
 | 
			
		||||
        attrs.retain(|attr| {
 | 
			
		||||
            if attr.path().is_ident("repr") {
 | 
			
		||||
                errors.error(attr, "#[repr] is not supported on #[hdl] enums");
 | 
			
		||||
                false
 | 
			
		||||
            } else {
 | 
			
		||||
                true
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        let generics = if custom_bounds.is_some() {
 | 
			
		||||
            MaybeParsed::Unrecognized(generics)
 | 
			
		||||
        } else if let Some(generics) = errors.ok(ParsedGenerics::parse(&mut generics)) {
 | 
			
		||||
            MaybeParsed::Parsed(generics)
 | 
			
		||||
        } else {
 | 
			
		||||
            MaybeParsed::Unrecognized(generics)
 | 
			
		||||
        };
 | 
			
		||||
        let variants = Punctuated::from_iter(
 | 
			
		||||
            variants
 | 
			
		||||
                .into_pairs()
 | 
			
		||||
                .map_pair_value(|v| ParsedVariant::parse(&mut errors, v, &generics)),
 | 
			
		||||
        );
 | 
			
		||||
        errors.finish()?;
 | 
			
		||||
        Ok(Self {
 | 
			
		||||
            attrs,
 | 
			
		||||
            options,
 | 
			
		||||
            vis,
 | 
			
		||||
            enum_token,
 | 
			
		||||
            generics,
 | 
			
		||||
            brace_token,
 | 
			
		||||
            variants,
 | 
			
		||||
            match_variant_ident: format_ident!("__{}__MatchVariant", ident),
 | 
			
		||||
            ident,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ToTokens for ParsedEnum {
 | 
			
		||||
    fn to_tokens(&self, tokens: &mut TokenStream) {
 | 
			
		||||
        let Self {
 | 
			
		||||
            attrs,
 | 
			
		||||
            options,
 | 
			
		||||
            vis,
 | 
			
		||||
            enum_token,
 | 
			
		||||
            ident,
 | 
			
		||||
            generics,
 | 
			
		||||
            brace_token,
 | 
			
		||||
            variants,
 | 
			
		||||
            match_variant_ident,
 | 
			
		||||
        } = self;
 | 
			
		||||
        let ItemOptions {
 | 
			
		||||
            outline_generated: _,
 | 
			
		||||
            connect_inexact,
 | 
			
		||||
            target,
 | 
			
		||||
            custom_bounds: _,
 | 
			
		||||
            no_static,
 | 
			
		||||
        } = &options.body;
 | 
			
		||||
        let target = get_target(target, ident);
 | 
			
		||||
        let mut struct_attrs = attrs.clone();
 | 
			
		||||
        struct_attrs.push(common_derives(ident.span()));
 | 
			
		||||
        struct_attrs.push(parse_quote_spanned! {ident.span()=>
 | 
			
		||||
            #[allow(non_snake_case)]
 | 
			
		||||
        });
 | 
			
		||||
        let struct_fields = Punctuated::from_iter(variants.pairs().map_pair_value_ref(
 | 
			
		||||
            |ParsedVariant {
 | 
			
		||||
                 attrs: _,
 | 
			
		||||
                 options,
 | 
			
		||||
                 ident,
 | 
			
		||||
                 field,
 | 
			
		||||
             }| {
 | 
			
		||||
                let VariantOptions {} = options.body;
 | 
			
		||||
                let colon_token;
 | 
			
		||||
                let ty = if let Some(ParsedVariantField {
 | 
			
		||||
                    paren_token,
 | 
			
		||||
                    attrs: _,
 | 
			
		||||
                    options,
 | 
			
		||||
                    ty,
 | 
			
		||||
                    comma_token: _,
 | 
			
		||||
                }) = field
 | 
			
		||||
                {
 | 
			
		||||
                    let FieldOptions {} = options.body;
 | 
			
		||||
                    colon_token = Token);
 | 
			
		||||
                    ty.clone().into()
 | 
			
		||||
                } else {
 | 
			
		||||
                    colon_token = Token);
 | 
			
		||||
                    parse_quote_spanned! {ident.span()=>
 | 
			
		||||
                        ()
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                Field {
 | 
			
		||||
                    attrs: vec![],
 | 
			
		||||
                    vis: vis.clone(),
 | 
			
		||||
                    mutability: FieldMutability::None,
 | 
			
		||||
                    ident: Some(ident.clone()),
 | 
			
		||||
                    colon_token: Some(colon_token),
 | 
			
		||||
                    ty,
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
        ));
 | 
			
		||||
        ItemStruct {
 | 
			
		||||
            attrs: struct_attrs,
 | 
			
		||||
            vis: vis.clone(),
 | 
			
		||||
            struct_token: Token,
 | 
			
		||||
            ident: ident.clone(),
 | 
			
		||||
            generics: generics.into(),
 | 
			
		||||
            fields: if struct_fields.is_empty() {
 | 
			
		||||
                Fields::Unit
 | 
			
		||||
            } else {
 | 
			
		||||
                Fields::Named(FieldsNamed {
 | 
			
		||||
                    brace_token: *brace_token,
 | 
			
		||||
                    named: struct_fields,
 | 
			
		||||
                })
 | 
			
		||||
            },
 | 
			
		||||
            semi_token: None,
 | 
			
		||||
        }
 | 
			
		||||
        .to_tokens(tokens);
 | 
			
		||||
        let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
 | 
			
		||||
        let mut wrapped_in_const = WrappedInConst::new(tokens, ident.span());
 | 
			
		||||
        let tokens = wrapped_in_const.inner();
 | 
			
		||||
        {
 | 
			
		||||
            let mut wrapped_in_const = WrappedInConst::new(tokens, ident.span());
 | 
			
		||||
            let tokens = wrapped_in_const.inner();
 | 
			
		||||
            let mut enum_attrs = attrs.clone();
 | 
			
		||||
            enum_attrs.push(parse_quote_spanned! {ident.span()=>
 | 
			
		||||
                #[allow(dead_code)]
 | 
			
		||||
            });
 | 
			
		||||
            ItemEnum {
 | 
			
		||||
                attrs: enum_attrs,
 | 
			
		||||
                vis: vis.clone(),
 | 
			
		||||
                enum_token: *enum_token,
 | 
			
		||||
                ident: ident.clone(),
 | 
			
		||||
                generics: generics.into(),
 | 
			
		||||
                brace_token: *brace_token,
 | 
			
		||||
                variants: Punctuated::from_iter(variants.pairs().map_pair_value_ref(
 | 
			
		||||
                    |ParsedVariant {
 | 
			
		||||
                         attrs,
 | 
			
		||||
                         options: _,
 | 
			
		||||
                         ident,
 | 
			
		||||
                         field,
 | 
			
		||||
                     }| Variant {
 | 
			
		||||
                        attrs: attrs.clone(),
 | 
			
		||||
                        ident: ident.clone(),
 | 
			
		||||
                        fields: match field {
 | 
			
		||||
                            Some(ParsedVariantField {
 | 
			
		||||
                                paren_token,
 | 
			
		||||
                                attrs,
 | 
			
		||||
                                options: _,
 | 
			
		||||
                                ty,
 | 
			
		||||
                                comma_token,
 | 
			
		||||
                            }) => Fields::Unnamed(FieldsUnnamed {
 | 
			
		||||
                                paren_token: *paren_token,
 | 
			
		||||
                                unnamed: Punctuated::from_iter([Pair::new(
 | 
			
		||||
                                    Field {
 | 
			
		||||
                                        attrs: attrs.clone(),
 | 
			
		||||
                                        vis: Visibility::Inherited,
 | 
			
		||||
                                        mutability: FieldMutability::None,
 | 
			
		||||
                                        ident: None,
 | 
			
		||||
                                        colon_token: None,
 | 
			
		||||
                                        ty: ty.clone().into(),
 | 
			
		||||
                                    },
 | 
			
		||||
                                    *comma_token,
 | 
			
		||||
                                )]),
 | 
			
		||||
                            }),
 | 
			
		||||
                            None => Fields::Unit,
 | 
			
		||||
                        },
 | 
			
		||||
                        discriminant: None,
 | 
			
		||||
                    },
 | 
			
		||||
                )),
 | 
			
		||||
            }
 | 
			
		||||
            .to_tokens(tokens);
 | 
			
		||||
        }
 | 
			
		||||
        let mut enum_attrs = attrs.clone();
 | 
			
		||||
        enum_attrs.push(parse_quote_spanned! {ident.span()=>
 | 
			
		||||
            #[allow(dead_code, non_camel_case_types)]
 | 
			
		||||
        });
 | 
			
		||||
        ItemEnum {
 | 
			
		||||
            attrs: enum_attrs,
 | 
			
		||||
            vis: vis.clone(),
 | 
			
		||||
            enum_token: *enum_token,
 | 
			
		||||
            ident: match_variant_ident.clone(),
 | 
			
		||||
            generics: generics.into(),
 | 
			
		||||
            brace_token: *brace_token,
 | 
			
		||||
            variants: Punctuated::from_iter(variants.pairs().map_pair_value_ref(
 | 
			
		||||
                |ParsedVariant {
 | 
			
		||||
                     attrs,
 | 
			
		||||
                     options: _,
 | 
			
		||||
                     ident,
 | 
			
		||||
                     field,
 | 
			
		||||
                 }| Variant {
 | 
			
		||||
                    attrs: attrs.clone(),
 | 
			
		||||
                    ident: ident.clone(),
 | 
			
		||||
                    fields: match field {
 | 
			
		||||
                        Some(ParsedVariantField {
 | 
			
		||||
                            paren_token,
 | 
			
		||||
                            attrs,
 | 
			
		||||
                            options: _,
 | 
			
		||||
                            ty,
 | 
			
		||||
                            comma_token,
 | 
			
		||||
                        }) => Fields::Unnamed(FieldsUnnamed {
 | 
			
		||||
                            paren_token: *paren_token,
 | 
			
		||||
                            unnamed: Punctuated::from_iter([Pair::new(
 | 
			
		||||
                                Field {
 | 
			
		||||
                                    attrs: attrs.clone(),
 | 
			
		||||
                                    vis: Visibility::Inherited,
 | 
			
		||||
                                    mutability: FieldMutability::None,
 | 
			
		||||
                                    ident: None,
 | 
			
		||||
                                    colon_token: None,
 | 
			
		||||
                                    ty: parse_quote_spanned! {ident.span()=>
 | 
			
		||||
                                        ::fayalite::expr::Expr<#ty>
 | 
			
		||||
                                    },
 | 
			
		||||
                                },
 | 
			
		||||
                                *comma_token,
 | 
			
		||||
                            )]),
 | 
			
		||||
                        }),
 | 
			
		||||
                        None => Fields::Unit,
 | 
			
		||||
                    },
 | 
			
		||||
                    discriminant: None,
 | 
			
		||||
                },
 | 
			
		||||
            )),
 | 
			
		||||
        }
 | 
			
		||||
        .to_tokens(tokens);
 | 
			
		||||
        for (index, ParsedVariant { ident, field, .. }) in variants.iter().enumerate() {
 | 
			
		||||
            if let Some(ParsedVariantField { ty, .. }) = field {
 | 
			
		||||
                quote_spanned! {ident.span()=>
 | 
			
		||||
                    #[automatically_derived]
 | 
			
		||||
                    impl #impl_generics #target #type_generics
 | 
			
		||||
                    #where_clause
 | 
			
		||||
                    {
 | 
			
		||||
                        #[allow(non_snake_case, dead_code)]
 | 
			
		||||
                        #vis fn #ident<__V: ::fayalite::expr::ToExpr<Type = #ty>>(
 | 
			
		||||
                            self,
 | 
			
		||||
                            v: __V,
 | 
			
		||||
                        ) -> ::fayalite::expr::Expr<Self> {
 | 
			
		||||
                            ::fayalite::expr::ToExpr::to_expr(
 | 
			
		||||
                                &::fayalite::expr::ops::EnumLiteral::new(
 | 
			
		||||
                                    self,
 | 
			
		||||
                                    #index,
 | 
			
		||||
                                    ::fayalite::__std::option::Option::Some(
 | 
			
		||||
                                        ::fayalite::expr::Expr::canonical(
 | 
			
		||||
                                            ::fayalite::expr::ToExpr::to_expr(&v),
 | 
			
		||||
                                        ),
 | 
			
		||||
                                    ),
 | 
			
		||||
                                ),
 | 
			
		||||
                            )
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                quote_spanned! {ident.span()=>
 | 
			
		||||
                    #[automatically_derived]
 | 
			
		||||
                    impl #impl_generics #target #type_generics
 | 
			
		||||
                    #where_clause
 | 
			
		||||
                    {
 | 
			
		||||
                        #[allow(non_snake_case, dead_code)]
 | 
			
		||||
                        #vis fn #ident(self) -> ::fayalite::expr::Expr<Self> {
 | 
			
		||||
                            ::fayalite::expr::ToExpr::to_expr(
 | 
			
		||||
                                &::fayalite::expr::ops::EnumLiteral::new(
 | 
			
		||||
                                    self,
 | 
			
		||||
                                    #index,
 | 
			
		||||
                                    ::fayalite::__std::option::Option::None,
 | 
			
		||||
                                ),
 | 
			
		||||
                            )
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .to_tokens(tokens);
 | 
			
		||||
        }
 | 
			
		||||
        let from_canonical_body_fields = Vec::from_iter(variants.iter().enumerate().map(
 | 
			
		||||
            |(index, ParsedVariant { ident, field, .. })| {
 | 
			
		||||
                let ident_str = ident.to_string();
 | 
			
		||||
                let val = if field.is_some() {
 | 
			
		||||
                    let missing_value_msg = format!("expected variant {ident} to have a field");
 | 
			
		||||
                    quote_spanned! {ident.span()=>
 | 
			
		||||
                        ::fayalite::ty::Type::from_canonical(ty.expect(#missing_value_msg))
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    quote_spanned! {ident.span()=>
 | 
			
		||||
                        ::fayalite::__std::assert!(ty.is_none());
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
                quote_spanned! {ident.span()=>
 | 
			
		||||
                    #ident: {
 | 
			
		||||
                        let ::fayalite::enum_::EnumVariant {
 | 
			
		||||
                            name,
 | 
			
		||||
                            ty,
 | 
			
		||||
                        } = variants[#index];
 | 
			
		||||
                        ::fayalite::__std::assert_eq!(&*name, #ident_str);
 | 
			
		||||
                        #val
 | 
			
		||||
                    },
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
        ));
 | 
			
		||||
        let match_active_scope_match_arms = Vec::from_iter(variants.iter().enumerate().map(
 | 
			
		||||
            |(index, ParsedVariant { ident, field, .. })| {
 | 
			
		||||
                if field.is_some() {
 | 
			
		||||
                    quote_spanned! {ident.span()=>
 | 
			
		||||
                        #index => #match_variant_ident::#ident(
 | 
			
		||||
                            ::fayalite::expr::ToExpr::to_expr(
 | 
			
		||||
                                &::fayalite::expr::ops::VariantAccess::new_unchecked(
 | 
			
		||||
                                    variant_access.base(),
 | 
			
		||||
                                    variant_access.variant_index(),
 | 
			
		||||
                                ),
 | 
			
		||||
                            ),
 | 
			
		||||
                        ),
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    quote_spanned! {ident.span()=>
 | 
			
		||||
                        #index => #match_variant_ident::#ident,
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
        ));
 | 
			
		||||
        let variants_body_variants = Vec::from_iter(variants.iter().map(
 | 
			
		||||
            |ParsedVariant {
 | 
			
		||||
                 attrs: _,
 | 
			
		||||
                 options,
 | 
			
		||||
                 ident,
 | 
			
		||||
                 field,
 | 
			
		||||
             }| {
 | 
			
		||||
                let VariantOptions {} = options.body;
 | 
			
		||||
                let ident_str = ident.to_string();
 | 
			
		||||
                match field {
 | 
			
		||||
                    Some(ParsedVariantField { options, .. }) => {
 | 
			
		||||
                        let FieldOptions {} = options.body;
 | 
			
		||||
                        quote_spanned! {ident.span()=>
 | 
			
		||||
                            ::fayalite::enum_::EnumVariant {
 | 
			
		||||
                                name: ::fayalite::intern::Intern::intern(#ident_str),
 | 
			
		||||
                                ty: ::fayalite::__std::option::Option::Some(
 | 
			
		||||
                                    ::fayalite::ty::Type::canonical(&self.#ident),
 | 
			
		||||
                                ),
 | 
			
		||||
                            },
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    None => quote_spanned! {ident.span()=>
 | 
			
		||||
                        ::fayalite::enum_::EnumVariant {
 | 
			
		||||
                            name: ::fayalite::intern::Intern::intern(#ident_str),
 | 
			
		||||
                            ty: ::fayalite::__std::option::Option::None,
 | 
			
		||||
                        },
 | 
			
		||||
                    },
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
        ));
 | 
			
		||||
        let variants_len = variants.len();
 | 
			
		||||
        quote_spanned! {ident.span()=>
 | 
			
		||||
            #[automatically_derived]
 | 
			
		||||
            impl #impl_generics ::fayalite::ty::Type for #target #type_generics
 | 
			
		||||
            #where_clause
 | 
			
		||||
            {
 | 
			
		||||
                type MaskType = ::fayalite::int::Bool;
 | 
			
		||||
                type MatchVariant = #match_variant_ident #type_generics;
 | 
			
		||||
                type MatchActiveScope = ::fayalite::module::Scope;
 | 
			
		||||
                type MatchVariantAndInactiveScope = ::fayalite::enum_::EnumMatchVariantAndInactiveScope<Self>;
 | 
			
		||||
                type MatchVariantsIter = ::fayalite::enum_::EnumMatchVariantsIter<Self>;
 | 
			
		||||
 | 
			
		||||
                fn match_variants(
 | 
			
		||||
                    this: ::fayalite::expr::Expr<Self>,
 | 
			
		||||
                    module_builder: &mut ::fayalite::module::ModuleBuilder<::fayalite::module::NormalModule>,
 | 
			
		||||
                    source_location: ::fayalite::source_location::SourceLocation,
 | 
			
		||||
                ) -> <Self as ::fayalite::ty::Type>::MatchVariantsIter {
 | 
			
		||||
                    module_builder.enum_match_variants_helper(this, source_location)
 | 
			
		||||
                }
 | 
			
		||||
                fn mask_type(&self) -> <Self as ::fayalite::ty::Type>::MaskType {
 | 
			
		||||
                    ::fayalite::int::Bool
 | 
			
		||||
                }
 | 
			
		||||
                fn canonical(&self) -> ::fayalite::ty::CanonicalType {
 | 
			
		||||
                    ::fayalite::ty::CanonicalType::Enum(::fayalite::enum_::Enum::new(::fayalite::enum_::EnumType::variants(self)))
 | 
			
		||||
                }
 | 
			
		||||
                #[track_caller]
 | 
			
		||||
                #[allow(non_snake_case)]
 | 
			
		||||
                fn from_canonical(canonical_type: ::fayalite::ty::CanonicalType) -> Self {
 | 
			
		||||
                    let ::fayalite::ty::CanonicalType::Enum(enum_) = canonical_type else {
 | 
			
		||||
                        ::fayalite::__std::panic!("expected enum");
 | 
			
		||||
                    };
 | 
			
		||||
                    let variants = ::fayalite::enum_::EnumType::variants(&enum_);
 | 
			
		||||
                    ::fayalite::__std::assert_eq!(variants.len(), #variants_len, "enum has wrong number of variants");
 | 
			
		||||
                    Self {
 | 
			
		||||
                        #(#from_canonical_body_fields)*
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                fn source_location() -> ::fayalite::source_location::SourceLocation {
 | 
			
		||||
                    ::fayalite::source_location::SourceLocation::caller()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            #[automatically_derived]
 | 
			
		||||
            impl #impl_generics ::fayalite::enum_::EnumType for #target #type_generics
 | 
			
		||||
            #where_clause
 | 
			
		||||
            {
 | 
			
		||||
                fn match_activate_scope(
 | 
			
		||||
                    v: <Self as ::fayalite::ty::Type>::MatchVariantAndInactiveScope,
 | 
			
		||||
                ) -> (<Self as ::fayalite::ty::Type>::MatchVariant, <Self as ::fayalite::ty::Type>::MatchActiveScope) {
 | 
			
		||||
                    let (variant_access, scope) = v.activate();
 | 
			
		||||
                    (
 | 
			
		||||
                        match variant_access.variant_index() {
 | 
			
		||||
                            #(#match_active_scope_match_arms)*
 | 
			
		||||
                            #variants_len.. => ::fayalite::__std::panic!("invalid variant index"),
 | 
			
		||||
                        },
 | 
			
		||||
                        scope,
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
                fn variants(&self) -> ::fayalite::intern::Interned<[::fayalite::enum_::EnumVariant]> {
 | 
			
		||||
                    ::fayalite::intern::Intern::intern(&[
 | 
			
		||||
                        #(#variants_body_variants)*
 | 
			
		||||
                    ][..])
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        .to_tokens(tokens);
 | 
			
		||||
        if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) {
 | 
			
		||||
            let static_generics = generics.clone().for_static_type();
 | 
			
		||||
            let (static_impl_generics, static_type_generics, static_where_clause) =
 | 
			
		||||
                static_generics.split_for_impl();
 | 
			
		||||
            let static_type_body_variants =
 | 
			
		||||
                Vec::from_iter(variants.iter().map(|ParsedVariant { ident, field, .. }| {
 | 
			
		||||
                    if let Some(_) = field {
 | 
			
		||||
                        quote_spanned! {ident.span()=>
 | 
			
		||||
                            #ident: ::fayalite::ty::StaticType::static_type(),
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        quote_spanned! {ident.span()=>
 | 
			
		||||
                            #ident: (),
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }));
 | 
			
		||||
            quote_spanned! {ident.span()=>
 | 
			
		||||
                #[automatically_derived]
 | 
			
		||||
                impl #static_impl_generics ::fayalite::ty::StaticType for #target #static_type_generics
 | 
			
		||||
                #static_where_clause
 | 
			
		||||
                {
 | 
			
		||||
                    fn static_type() -> Self {
 | 
			
		||||
                        Self {
 | 
			
		||||
                            #(#static_type_body_variants)*
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .to_tokens(tokens);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) fn hdl_enum(item: ItemEnum) -> syn::Result<TokenStream> {
 | 
			
		||||
    let item = ParsedEnum::parse(item)?;
 | 
			
		||||
    let outline_generated = item.options.body.outline_generated;
 | 
			
		||||
    let mut contents = item.to_token_stream();
 | 
			
		||||
    if outline_generated.is_some() {
 | 
			
		||||
        contents = crate::outline_generated(contents, "hdl-enum-");
 | 
			
		||||
    }
 | 
			
		||||
    Ok(contents)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2055
									
								
								crates/fayalite-proc-macros-impl/src/hdl_type_common.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2055
									
								
								crates/fayalite-proc-macros-impl/src/hdl_type_common.rs
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -3,7 +3,10 @@
 | 
			
		|||
#![cfg_attr(test, recursion_limit = "512")]
 | 
			
		||||
use proc_macro2::{Span, TokenStream};
 | 
			
		||||
use quote::{quote, ToTokens};
 | 
			
		||||
use std::io::{ErrorKind, Write};
 | 
			
		||||
use std::{
 | 
			
		||||
    convert::Infallible,
 | 
			
		||||
    io::{ErrorKind, Write},
 | 
			
		||||
};
 | 
			
		||||
use syn::{
 | 
			
		||||
    bracketed, parenthesized,
 | 
			
		||||
    parse::{Parse, ParseStream, Parser},
 | 
			
		||||
| 
						 | 
				
			
			@ -13,6 +16,9 @@ use syn::{
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
mod fold;
 | 
			
		||||
mod hdl_bundle;
 | 
			
		||||
mod hdl_enum;
 | 
			
		||||
mod hdl_type_common;
 | 
			
		||||
mod module;
 | 
			
		||||
mod value_derive_common;
 | 
			
		||||
mod value_derive_enum;
 | 
			
		||||
| 
						 | 
				
			
			@ -43,6 +49,7 @@ mod kw {
 | 
			
		|||
 | 
			
		||||
    custom_keyword!(clock_domain);
 | 
			
		||||
    custom_keyword!(connect_inexact);
 | 
			
		||||
    custom_keyword!(custom_bounds);
 | 
			
		||||
    custom_keyword!(flip);
 | 
			
		||||
    custom_keyword!(hdl);
 | 
			
		||||
    custom_keyword!(input);
 | 
			
		||||
| 
						 | 
				
			
			@ -52,6 +59,7 @@ mod kw {
 | 
			
		|||
    custom_keyword!(memory_array);
 | 
			
		||||
    custom_keyword!(memory_with_init);
 | 
			
		||||
    custom_keyword!(no_reset);
 | 
			
		||||
    custom_keyword!(no_static);
 | 
			
		||||
    custom_keyword!(outline_generated);
 | 
			
		||||
    custom_keyword!(output);
 | 
			
		||||
    custom_keyword!(reg_builder);
 | 
			
		||||
| 
						 | 
				
			
			@ -460,6 +468,15 @@ impl Errors {
 | 
			
		|||
        self.push(Error::new_spanned(tokens, message));
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
    pub(crate) fn fatal_error(
 | 
			
		||||
        mut self,
 | 
			
		||||
        tokens: impl ToTokens,
 | 
			
		||||
        message: impl std::fmt::Display,
 | 
			
		||||
    ) -> syn::Result<Infallible> {
 | 
			
		||||
        self.push(Error::new_spanned(tokens, message));
 | 
			
		||||
        self.finish()?;
 | 
			
		||||
        unreachable!()
 | 
			
		||||
    }
 | 
			
		||||
    pub(crate) fn ok<T>(&mut self, v: syn::Result<T>) -> Option<T> {
 | 
			
		||||
        match v {
 | 
			
		||||
            Ok(v) => Some(v),
 | 
			
		||||
| 
						 | 
				
			
			@ -519,6 +536,26 @@ macro_rules! impl_extra_traits_for_options {
 | 
			
		|||
    ) => {
 | 
			
		||||
        impl Copy for $option_enum_name {}
 | 
			
		||||
 | 
			
		||||
        impl PartialEq for $option_enum_name {
 | 
			
		||||
            fn eq(&self, other: &Self) -> bool {
 | 
			
		||||
                self.cmp(other).is_eq()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        impl Eq for $option_enum_name {}
 | 
			
		||||
 | 
			
		||||
        impl PartialOrd for $option_enum_name {
 | 
			
		||||
            fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
 | 
			
		||||
                Some(self.cmp(other))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        impl Ord for $option_enum_name {
 | 
			
		||||
            fn cmp(&self, other: &Self) -> std::cmp::Ordering {
 | 
			
		||||
                self.variant().cmp(&other.variant())
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        impl quote::IdentFragment for $option_enum_name {
 | 
			
		||||
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
 | 
			
		||||
                let _ = f;
 | 
			
		||||
| 
						 | 
				
			
			@ -554,6 +591,66 @@ pub(crate) use impl_extra_traits_for_options;
 | 
			
		|||
macro_rules! options {
 | 
			
		||||
    (
 | 
			
		||||
        #[options = $options_name:ident]
 | 
			
		||||
        $($tt:tt)*
 | 
			
		||||
    ) => {
 | 
			
		||||
        crate::options! {
 | 
			
		||||
            #[options = $options_name, punct = syn::Token![,], allow_duplicates = false]
 | 
			
		||||
            $($tt)*
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    (
 | 
			
		||||
        #[options = $options_name:ident, punct = $Punct:ty, allow_duplicates = true]
 | 
			
		||||
        $(#[$($enum_meta:tt)*])*
 | 
			
		||||
        $enum_vis:vis enum $option_enum_name:ident {
 | 
			
		||||
            $($Variant:ident($key:ident $(, $value:ty)?),)*
 | 
			
		||||
        }
 | 
			
		||||
    ) => {
 | 
			
		||||
        crate::options! {
 | 
			
		||||
            #[options = $options_name, punct = $Punct, allow_duplicates = (true)]
 | 
			
		||||
            $(#[$($enum_meta)*])*
 | 
			
		||||
            $enum_vis enum $option_enum_name {
 | 
			
		||||
                $($Variant($key $(, $value)?),)*
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        impl Extend<$option_enum_name> for $options_name {
 | 
			
		||||
            fn extend<T: IntoIterator<Item = $option_enum_name>>(&mut self, iter: T) {
 | 
			
		||||
                iter.into_iter().for_each(|v| match v {
 | 
			
		||||
                    $($option_enum_name::$Variant(v) => {
 | 
			
		||||
                        self.$key = Some(v);
 | 
			
		||||
                    })*
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        impl FromIterator<$option_enum_name> for $options_name {
 | 
			
		||||
            fn from_iter<T: IntoIterator<Item = $option_enum_name>>(iter: T) -> Self {
 | 
			
		||||
                let mut retval = Self::default();
 | 
			
		||||
                retval.extend(iter);
 | 
			
		||||
                retval
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        impl Extend<$options_name> for $options_name {
 | 
			
		||||
            fn extend<T: IntoIterator<Item = $options_name>>(&mut self, iter: T) {
 | 
			
		||||
                iter.into_iter().for_each(|v| {
 | 
			
		||||
                    $(if let Some(v) = v.$key {
 | 
			
		||||
                        self.$key = Some(v);
 | 
			
		||||
                    })*
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        impl FromIterator<$options_name> for $options_name {
 | 
			
		||||
            fn from_iter<T: IntoIterator<Item = $options_name>>(iter: T) -> Self {
 | 
			
		||||
                let mut retval = Self::default();
 | 
			
		||||
                retval.extend(iter);
 | 
			
		||||
                retval
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    (
 | 
			
		||||
        #[options = $options_name:ident, punct = $Punct:ty, allow_duplicates = $allow_duplicates:expr]
 | 
			
		||||
        $(#[$($enum_meta:tt)*])*
 | 
			
		||||
        $enum_vis:vis enum $option_enum_name:ident {
 | 
			
		||||
            $($Variant:ident($key:ident $(, $value:ty)?),)*
 | 
			
		||||
| 
						 | 
				
			
			@ -567,8 +664,11 @@ macro_rules! options {
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        #[derive(Clone, Debug, Default)]
 | 
			
		||||
        #[allow(non_snake_case)]
 | 
			
		||||
        $enum_vis struct $options_name {
 | 
			
		||||
            $($enum_vis $key: Option<(crate::kw::$key, $(syn::token::Paren, $value)?)>,)*
 | 
			
		||||
            $(
 | 
			
		||||
                $enum_vis $key: Option<(crate::kw::$key, $(syn::token::Paren, $value)?)>,
 | 
			
		||||
            )*
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        crate::fold::impl_fold! {
 | 
			
		||||
| 
						 | 
				
			
			@ -577,6 +677,43 @@ macro_rules! options {
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const _: () = {
 | 
			
		||||
            #[derive(Clone, Debug)]
 | 
			
		||||
            $enum_vis struct Iter($enum_vis $options_name);
 | 
			
		||||
 | 
			
		||||
            impl IntoIterator for $options_name {
 | 
			
		||||
                type Item = $option_enum_name;
 | 
			
		||||
                type IntoIter = Iter;
 | 
			
		||||
 | 
			
		||||
                fn into_iter(self) -> Self::IntoIter {
 | 
			
		||||
                    Iter(self)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            impl Iterator for Iter {
 | 
			
		||||
                type Item = $option_enum_name;
 | 
			
		||||
 | 
			
		||||
                fn next(&mut self) -> Option<Self::Item> {
 | 
			
		||||
                    $(
 | 
			
		||||
                        if let Some(value) = self.0.$key.take() {
 | 
			
		||||
                            return Some($option_enum_name::$Variant(value));
 | 
			
		||||
                        }
 | 
			
		||||
                    )*
 | 
			
		||||
                    None
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                #[allow(unused_mut, unused_variables)]
 | 
			
		||||
                fn fold<B, F: FnMut(B, Self::Item) -> B>(mut self, mut init: B, mut f: F) -> B {
 | 
			
		||||
                    $(
 | 
			
		||||
                        if let Some(value) = self.0.$key.take() {
 | 
			
		||||
                            init = f(init, $option_enum_name::$Variant(value));
 | 
			
		||||
                        }
 | 
			
		||||
                    )*
 | 
			
		||||
                    init
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        impl syn::parse::Parse for $options_name {
 | 
			
		||||
            fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
 | 
			
		||||
                #![allow(unused_mut, unused_variables, unreachable_code)]
 | 
			
		||||
| 
						 | 
				
			
			@ -585,7 +722,7 @@ macro_rules! options {
 | 
			
		|||
                    let old_input = input.fork();
 | 
			
		||||
                    match input.parse::<$option_enum_name>()? {
 | 
			
		||||
                        $($option_enum_name::$Variant(v) => {
 | 
			
		||||
                            if retval.$key.replace(v).is_some() {
 | 
			
		||||
                            if retval.$key.replace(v).is_some() && !$allow_duplicates {
 | 
			
		||||
                                return Err(old_input.error(concat!("duplicate ", stringify!($key), " option")));
 | 
			
		||||
                            }
 | 
			
		||||
                        })*
 | 
			
		||||
| 
						 | 
				
			
			@ -593,7 +730,7 @@ macro_rules! options {
 | 
			
		|||
                    if input.is_empty() {
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    input.parse::<syn::Token![,]>()?;
 | 
			
		||||
                    input.parse::<$Punct>()?;
 | 
			
		||||
                }
 | 
			
		||||
                Ok(retval)
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -602,7 +739,7 @@ macro_rules! options {
 | 
			
		|||
        impl quote::ToTokens for $options_name {
 | 
			
		||||
            #[allow(unused_mut, unused_variables, unused_assignments)]
 | 
			
		||||
            fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
 | 
			
		||||
                let mut separator: Option<syn::Token![,]> = None;
 | 
			
		||||
                let mut separator: Option<$Punct> = None;
 | 
			
		||||
                $(if let Some(v) = &self.$key {
 | 
			
		||||
                    separator.to_tokens(tokens);
 | 
			
		||||
                    separator = Some(Default::default());
 | 
			
		||||
| 
						 | 
				
			
			@ -673,6 +810,20 @@ macro_rules! options {
 | 
			
		|||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        impl $option_enum_name {
 | 
			
		||||
            #[allow(dead_code)]
 | 
			
		||||
            fn variant(&self) -> usize {
 | 
			
		||||
                #[repr(usize)]
 | 
			
		||||
                enum Variant {
 | 
			
		||||
                    $($Variant,)*
 | 
			
		||||
                    __Last, // so it doesn't complain about zero-variant enums
 | 
			
		||||
                }
 | 
			
		||||
                match *self {
 | 
			
		||||
                    $(Self::$Variant(..) => Variant::$Variant as usize,)*
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -728,3 +879,15 @@ pub fn value_derive(item: TokenStream) -> syn::Result<TokenStream> {
 | 
			
		|||
        )),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn hdl_attr(attr: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
 | 
			
		||||
    let item = syn::parse2::<Item>(quote! { #[hdl(#attr)] #item })?;
 | 
			
		||||
    match item {
 | 
			
		||||
        Item::Enum(item) => hdl_enum::hdl_enum(item),
 | 
			
		||||
        Item::Struct(item) => hdl_bundle::hdl_bundle(item),
 | 
			
		||||
        _ => Err(syn::Error::new(
 | 
			
		||||
            Span::call_site(),
 | 
			
		||||
            "top-level #[hdl] can only be used on structs or enums",
 | 
			
		||||
        )),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1290,7 +1290,10 @@ impl Visitor {
 | 
			
		|||
                memory,
 | 
			
		||||
                paren,
 | 
			
		||||
                ty_expr,
 | 
			
		||||
            } => (paren, unwrap_or_static_type(ty_expr.as_ref(), memory.span())),
 | 
			
		||||
            } => (
 | 
			
		||||
                paren,
 | 
			
		||||
                unwrap_or_static_type(ty_expr.as_ref(), memory.span()),
 | 
			
		||||
            ),
 | 
			
		||||
            MemoryFn::MemoryArray {
 | 
			
		||||
                memory_array,
 | 
			
		||||
                paren,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,3 +24,15 @@ pub fn value_derive(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
 | 
			
		|||
        Err(err) => err.into_compile_error().into(),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// intentionally not documented here, see `fayalite::hdl` for docs
 | 
			
		||||
#[proc_macro_attribute]
 | 
			
		||||
pub fn hdl(
 | 
			
		||||
    attr: proc_macro::TokenStream,
 | 
			
		||||
    item: proc_macro::TokenStream,
 | 
			
		||||
) -> proc_macro::TokenStream {
 | 
			
		||||
    match fayalite_proc_macros_impl::hdl_attr(attr.into(), item.into()) {
 | 
			
		||||
        Ok(retval) => retval.into(),
 | 
			
		||||
        Err(err) => err.into_compile_error().into(),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,671 +1,185 @@
 | 
			
		|||
// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
			
		||||
// See Notices.txt for copyright information
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    bundle::{BundleType, BundleValue},
 | 
			
		||||
    expr::{
 | 
			
		||||
        ops::{ArrayIndex, ArrayLiteral, ExprIndex},
 | 
			
		||||
        Expr, ToExpr,
 | 
			
		||||
    },
 | 
			
		||||
    intern::{Intern, Interned, InternedCompare, Memoize},
 | 
			
		||||
    module::{
 | 
			
		||||
        transform::visit::{Fold, Folder, Visit, Visitor},
 | 
			
		||||
        ModuleBuilder, NormalModule,
 | 
			
		||||
    },
 | 
			
		||||
    expr::{ops::ArrayIndex, Expr, ToExpr},
 | 
			
		||||
    int::{DynSize, KnownSize, Size},
 | 
			
		||||
    intern::{Intern, Interned},
 | 
			
		||||
    module::{ModuleBuilder, NormalModule},
 | 
			
		||||
    source_location::SourceLocation,
 | 
			
		||||
    ty::{
 | 
			
		||||
        CanonicalType, CanonicalTypeKind, CanonicalValue, Connect, DynCanonicalType,
 | 
			
		||||
        DynCanonicalValue, DynType, DynValueTrait, MatchVariantWithoutScope, StaticType,
 | 
			
		||||
        StaticValue, Type, TypeEnum, Value, ValueEnum,
 | 
			
		||||
        CanonicalType, MatchVariantWithoutScope, StaticType, Type, TypeProperties, TypeWithDeref,
 | 
			
		||||
    },
 | 
			
		||||
    util::{ConstBool, GenericConstBool, MakeMutSlice},
 | 
			
		||||
};
 | 
			
		||||
use bitvec::{slice::BitSlice, vec::BitVec};
 | 
			
		||||
use std::{
 | 
			
		||||
    any::Any,
 | 
			
		||||
    borrow::{Borrow, BorrowMut},
 | 
			
		||||
    fmt,
 | 
			
		||||
    hash::Hash,
 | 
			
		||||
    marker::PhantomData,
 | 
			
		||||
    ops::IndexMut,
 | 
			
		||||
    sync::Arc,
 | 
			
		||||
    util::ConstUsize,
 | 
			
		||||
};
 | 
			
		||||
use std::ops::Index;
 | 
			
		||||
 | 
			
		||||
mod sealed {
 | 
			
		||||
    pub trait Sealed {}
 | 
			
		||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 | 
			
		||||
struct ArrayImpl<T: Type, Len: Size> {
 | 
			
		||||
    element: T,
 | 
			
		||||
    len: Len::SizeType,
 | 
			
		||||
    type_properties: TypeProperties,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait ValueArrayOrSlice:
 | 
			
		||||
    sealed::Sealed
 | 
			
		||||
    + BorrowMut<[<Self as ValueArrayOrSlice>::Element]>
 | 
			
		||||
    + AsRef<[<Self as ValueArrayOrSlice>::Element]>
 | 
			
		||||
    + AsMut<[<Self as ValueArrayOrSlice>::Element]>
 | 
			
		||||
    + Hash
 | 
			
		||||
    + fmt::Debug
 | 
			
		||||
    + Eq
 | 
			
		||||
    + Send
 | 
			
		||||
    + Sync
 | 
			
		||||
    + 'static
 | 
			
		||||
    + IndexMut<usize, Output = <Self as ValueArrayOrSlice>::Element>
 | 
			
		||||
    + ToOwned
 | 
			
		||||
    + InternedCompare
 | 
			
		||||
{
 | 
			
		||||
    type Element: Value<Type = <Self as ValueArrayOrSlice>::ElementType>;
 | 
			
		||||
    type ElementType: Type<Value = <Self as ValueArrayOrSlice>::Element>;
 | 
			
		||||
    type LenType: 'static + Copy + Ord + fmt::Debug + Hash + Send + Sync;
 | 
			
		||||
    type Match: 'static
 | 
			
		||||
        + Clone
 | 
			
		||||
        + Eq
 | 
			
		||||
        + fmt::Debug
 | 
			
		||||
        + Hash
 | 
			
		||||
        + Send
 | 
			
		||||
        + Sync
 | 
			
		||||
        + BorrowMut<[Expr<Self::Element>]>;
 | 
			
		||||
    type MaskVA: ValueArrayOrSlice<
 | 
			
		||||
            Element = <Self::ElementType as Type>::MaskValue,
 | 
			
		||||
            ElementType = <Self::ElementType as Type>::MaskType,
 | 
			
		||||
            LenType = Self::LenType,
 | 
			
		||||
            MaskVA = Self::MaskVA,
 | 
			
		||||
        > + ?Sized;
 | 
			
		||||
    type IsStaticLen: GenericConstBool;
 | 
			
		||||
    const FIXED_LEN_TYPE: Option<Self::LenType>;
 | 
			
		||||
    fn make_match(array: Expr<Array<Self>>) -> Self::Match;
 | 
			
		||||
    fn len_from_len_type(v: Self::LenType) -> usize;
 | 
			
		||||
    #[allow(clippy::result_unit_err)]
 | 
			
		||||
    fn try_len_type_from_len(v: usize) -> Result<Self::LenType, ()>;
 | 
			
		||||
    fn len_type(&self) -> Self::LenType;
 | 
			
		||||
    fn len(&self) -> usize;
 | 
			
		||||
    fn is_empty(&self) -> bool;
 | 
			
		||||
    fn iter(&self) -> std::slice::Iter<Self::Element> {
 | 
			
		||||
        Borrow::<[_]>::borrow(self).iter()
 | 
			
		||||
    }
 | 
			
		||||
    fn clone_to_arc(&self) -> Arc<Self>;
 | 
			
		||||
    fn arc_make_mut(v: &mut Arc<Self>) -> &mut Self;
 | 
			
		||||
    fn arc_to_arc_slice(self: Arc<Self>) -> Arc<[Self::Element]>;
 | 
			
		||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
 | 
			
		||||
pub struct ArrayType<T: Type = CanonicalType, Len: Size = DynSize> {
 | 
			
		||||
    impl_: Interned<ArrayImpl<T, Len>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T> sealed::Sealed for [T] {}
 | 
			
		||||
 | 
			
		||||
impl<V: Value> ValueArrayOrSlice for [V]
 | 
			
		||||
where
 | 
			
		||||
    V::Type: Type<Value = V>,
 | 
			
		||||
{
 | 
			
		||||
    type Element = V;
 | 
			
		||||
    type ElementType = V::Type;
 | 
			
		||||
    type LenType = usize;
 | 
			
		||||
    type Match = Box<[Expr<V>]>;
 | 
			
		||||
    type MaskVA = [<Self::ElementType as Type>::MaskValue];
 | 
			
		||||
    type IsStaticLen = ConstBool<false>;
 | 
			
		||||
    const FIXED_LEN_TYPE: Option<Self::LenType> = None;
 | 
			
		||||
 | 
			
		||||
    fn make_match(array: Expr<Array<Self>>) -> Self::Match {
 | 
			
		||||
        (0..array.canonical_type().len())
 | 
			
		||||
            .map(|index| ArrayIndex::<V::Type>::new_unchecked(array.canonical(), index).to_expr())
 | 
			
		||||
            .collect()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn len_from_len_type(v: Self::LenType) -> usize {
 | 
			
		||||
        v
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn try_len_type_from_len(v: usize) -> Result<Self::LenType, ()> {
 | 
			
		||||
        Ok(v)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn len_type(&self) -> Self::LenType {
 | 
			
		||||
        self.len()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn len(&self) -> usize {
 | 
			
		||||
        <[_]>::len(self)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn is_empty(&self) -> bool {
 | 
			
		||||
        <[_]>::is_empty(self)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn clone_to_arc(&self) -> Arc<Self> {
 | 
			
		||||
        Arc::from(self)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn arc_make_mut(v: &mut Arc<Self>) -> &mut Self {
 | 
			
		||||
        MakeMutSlice::make_mut_slice(v)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn arc_to_arc_slice(self: Arc<Self>) -> Arc<[Self::Element]> {
 | 
			
		||||
        self
 | 
			
		||||
impl<T: Type, Len: Size> std::fmt::Debug for ArrayType<T, Len> {
 | 
			
		||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
			
		||||
        let ArrayImpl {
 | 
			
		||||
            element, len: _, ..
 | 
			
		||||
        } = *self.impl_;
 | 
			
		||||
        write!(f, "Array<{element:?}, {}>", self.len())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T, const N: usize> sealed::Sealed for [T; N] {}
 | 
			
		||||
pub type Array<
 | 
			
		||||
    T = CanonicalType,
 | 
			
		||||
    const LEN: usize = { <DynSize as crate::util::GenericConstUsize>::VALUE },
 | 
			
		||||
> = ArrayType<T, ConstUsize<LEN>>;
 | 
			
		||||
 | 
			
		||||
impl<V: Value, const N: usize> ValueArrayOrSlice for [V; N]
 | 
			
		||||
where
 | 
			
		||||
    V::Type: Type<Value = V>,
 | 
			
		||||
{
 | 
			
		||||
    type Element = V;
 | 
			
		||||
    type ElementType = V::Type;
 | 
			
		||||
    type LenType = ();
 | 
			
		||||
    type Match = [Expr<V>; N];
 | 
			
		||||
    type MaskVA = [<Self::ElementType as Type>::MaskValue; N];
 | 
			
		||||
    type IsStaticLen = ConstBool<true>;
 | 
			
		||||
    const FIXED_LEN_TYPE: Option<Self::LenType> = Some(());
 | 
			
		||||
#[allow(non_upper_case_globals)]
 | 
			
		||||
pub const Array: ArrayWithoutGenerics = ArrayWithoutGenerics;
 | 
			
		||||
 | 
			
		||||
    fn make_match(array: Expr<Array<Self>>) -> Self::Match {
 | 
			
		||||
        std::array::from_fn(|index| {
 | 
			
		||||
            ArrayIndex::<V::Type>::new_unchecked(array.canonical(), index).to_expr()
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn len_from_len_type(_v: Self::LenType) -> usize {
 | 
			
		||||
        N
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn try_len_type_from_len(v: usize) -> Result<Self::LenType, ()> {
 | 
			
		||||
        if v == N {
 | 
			
		||||
            Ok(())
 | 
			
		||||
        } else {
 | 
			
		||||
            Err(())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn len_type(&self) -> Self::LenType {}
 | 
			
		||||
 | 
			
		||||
    fn len(&self) -> usize {
 | 
			
		||||
        N
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn is_empty(&self) -> bool {
 | 
			
		||||
        N == 0
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn clone_to_arc(&self) -> Arc<Self> {
 | 
			
		||||
        Arc::new(self.clone())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn arc_make_mut(v: &mut Arc<Self>) -> &mut Self {
 | 
			
		||||
        Arc::make_mut(v)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn arc_to_arc_slice(self: Arc<Self>) -> Arc<[Self::Element]> {
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, PartialEq, Eq, Hash)]
 | 
			
		||||
pub struct ArrayType<VA: ValueArrayOrSlice + ?Sized> {
 | 
			
		||||
    element: VA::ElementType,
 | 
			
		||||
    len: VA::LenType,
 | 
			
		||||
    bit_width: usize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait ArrayTypeTrait:
 | 
			
		||||
    Type<
 | 
			
		||||
        CanonicalType = ArrayType<[DynCanonicalValue]>,
 | 
			
		||||
        Value = Array<<Self as ArrayTypeTrait>::ValueArrayOrSlice>,
 | 
			
		||||
        CanonicalValue = Array<[DynCanonicalValue]>,
 | 
			
		||||
        MaskType = ArrayType<
 | 
			
		||||
            <<Self as ArrayTypeTrait>::ValueArrayOrSlice as ValueArrayOrSlice>::MaskVA,
 | 
			
		||||
        >,
 | 
			
		||||
    > + From<ArrayType<<Self as ArrayTypeTrait>::ValueArrayOrSlice>>
 | 
			
		||||
    + Into<ArrayType<<Self as ArrayTypeTrait>::ValueArrayOrSlice>>
 | 
			
		||||
    + BorrowMut<ArrayType<<Self as ArrayTypeTrait>::ValueArrayOrSlice>>
 | 
			
		||||
    + sealed::Sealed
 | 
			
		||||
    + Connect<Self>
 | 
			
		||||
{
 | 
			
		||||
    type ValueArrayOrSlice: ValueArrayOrSlice<Element = Self::Element, ElementType = Self::ElementType>
 | 
			
		||||
        + ?Sized;
 | 
			
		||||
    type Element: Value<Type = Self::ElementType>;
 | 
			
		||||
    type ElementType: Type<Value = Self::Element>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice + ?Sized> sealed::Sealed for ArrayType<VA> {}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice + ?Sized> ArrayTypeTrait for ArrayType<VA> {
 | 
			
		||||
    type ValueArrayOrSlice = VA;
 | 
			
		||||
    type Element = VA::Element;
 | 
			
		||||
    type ElementType = VA::ElementType;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice + ?Sized> Clone for ArrayType<VA> {
 | 
			
		||||
    fn clone(&self) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            element: self.element.clone(),
 | 
			
		||||
            len: self.len,
 | 
			
		||||
            bit_width: self.bit_width,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice + ?Sized> Copy for ArrayType<VA> where VA::ElementType: Copy {}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice + ?Sized> ArrayType<VA> {
 | 
			
		||||
    pub fn element(&self) -> &VA::ElementType {
 | 
			
		||||
        &self.element
 | 
			
		||||
    }
 | 
			
		||||
    pub fn len(&self) -> usize {
 | 
			
		||||
        VA::len_from_len_type(self.len)
 | 
			
		||||
    }
 | 
			
		||||
    pub fn is_empty(&self) -> bool {
 | 
			
		||||
        self.len() == 0
 | 
			
		||||
    }
 | 
			
		||||
    pub fn bit_width(&self) -> usize {
 | 
			
		||||
        self.bit_width
 | 
			
		||||
    }
 | 
			
		||||
    pub fn into_slice_type(self) -> ArrayType<[VA::Element]> {
 | 
			
		||||
        ArrayType {
 | 
			
		||||
            len: self.len(),
 | 
			
		||||
            element: self.element,
 | 
			
		||||
            bit_width: self.bit_width,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    #[track_caller]
 | 
			
		||||
    pub fn new_with_len(element: VA::ElementType, len: usize) -> Self {
 | 
			
		||||
        Self::new_with_len_type(
 | 
			
		||||
            element,
 | 
			
		||||
            VA::try_len_type_from_len(len).expect("length should match"),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
    #[track_caller]
 | 
			
		||||
    pub fn new_with_len_type(element: VA::ElementType, len: VA::LenType) -> Self {
 | 
			
		||||
        let Some(bit_width) = VA::len_from_len_type(len).checked_mul(element.bit_width()) else {
 | 
			
		||||
            panic!("array is too big: bit-width overflowed");
 | 
			
		||||
impl<T: Type, Len: Size> ArrayType<T, Len> {
 | 
			
		||||
    pub fn new(element: T, len: Len::SizeType) -> Self {
 | 
			
		||||
        let element_props = element.canonical().type_properties();
 | 
			
		||||
        let type_properties = TypeProperties {
 | 
			
		||||
            is_passive: element_props.is_passive,
 | 
			
		||||
            is_storable: element_props.is_storable,
 | 
			
		||||
            is_castable_from_bits: element_props.is_castable_from_bits,
 | 
			
		||||
            bit_width: element_props
 | 
			
		||||
                .bit_width
 | 
			
		||||
                .checked_mul(Len::as_usize(len))
 | 
			
		||||
                .expect("array too big"),
 | 
			
		||||
        };
 | 
			
		||||
        ArrayType {
 | 
			
		||||
            element,
 | 
			
		||||
            len,
 | 
			
		||||
            bit_width,
 | 
			
		||||
        Self {
 | 
			
		||||
            impl_: ArrayImpl {
 | 
			
		||||
                element,
 | 
			
		||||
                len,
 | 
			
		||||
                type_properties,
 | 
			
		||||
            }
 | 
			
		||||
            .intern_sized(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice + ?Sized, State: ?Sized + Folder> Fold<State> for ArrayType<VA>
 | 
			
		||||
where
 | 
			
		||||
    VA::ElementType: Fold<State>,
 | 
			
		||||
{
 | 
			
		||||
    fn fold(self, state: &mut State) -> Result<Self, State::Error> {
 | 
			
		||||
        state.fold_array_type(self)
 | 
			
		||||
    pub fn element(&self) -> &T {
 | 
			
		||||
        &self.impl_.element
 | 
			
		||||
    }
 | 
			
		||||
    fn default_fold(self, state: &mut State) -> Result<Self, State::Error> {
 | 
			
		||||
        Ok(Self::new_with_len_type(self.element.fold(state)?, self.len))
 | 
			
		||||
    pub fn len(self) -> usize {
 | 
			
		||||
        Len::as_usize(self.impl_.len)
 | 
			
		||||
    }
 | 
			
		||||
    pub fn type_properties(self) -> TypeProperties {
 | 
			
		||||
        self.impl_.type_properties
 | 
			
		||||
    }
 | 
			
		||||
    pub fn as_dyn_array(self) -> Array {
 | 
			
		||||
        Array::new_dyn(self.element().canonical(), self.len())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice + ?Sized, State: ?Sized + Visitor> Visit<State> for ArrayType<VA>
 | 
			
		||||
where
 | 
			
		||||
    VA::ElementType: Visit<State>,
 | 
			
		||||
{
 | 
			
		||||
    fn visit(&self, state: &mut State) -> Result<(), State::Error> {
 | 
			
		||||
        state.visit_array_type(self)
 | 
			
		||||
    }
 | 
			
		||||
    fn default_visit(&self, state: &mut State) -> Result<(), State::Error> {
 | 
			
		||||
        self.element.visit(state)
 | 
			
		||||
impl<T: Type, Len: KnownSize> ArrayType<T, Len> {
 | 
			
		||||
    pub fn new_static(element: T) -> Self {
 | 
			
		||||
        Self::new(element, Len::SizeType::default())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<V: Value<Type: Type<Value = V>>, const N: usize> ArrayType<[V; N]> {
 | 
			
		||||
    pub fn new_array(element: V::Type) -> Self {
 | 
			
		||||
        ArrayType::new_with_len_type(element, ())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<V: StaticValue, const N: usize> StaticType for ArrayType<[V; N]> {
 | 
			
		||||
impl<T: StaticType, Len: KnownSize> StaticType for ArrayType<T, Len> {
 | 
			
		||||
    fn static_type() -> Self {
 | 
			
		||||
        Self::new_array(StaticType::static_type())
 | 
			
		||||
        Self::new_static(T::static_type())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<V: Value<Type: Type<Value = V>>> ArrayType<[V]> {
 | 
			
		||||
    pub fn new_slice(element: V::Type, len: usize) -> Self {
 | 
			
		||||
        ArrayType::new_with_len_type(element, len)
 | 
			
		||||
impl<T: Type> Array<T> {
 | 
			
		||||
    pub fn new_dyn(element: T, len: usize) -> Self {
 | 
			
		||||
        Self::new(element, len)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice + ?Sized> Type for ArrayType<VA> {
 | 
			
		||||
    type CanonicalType = ArrayType<[DynCanonicalValue]>;
 | 
			
		||||
    type Value = Array<VA>;
 | 
			
		||||
    type CanonicalValue = Array<[DynCanonicalValue]>;
 | 
			
		||||
    type MaskType = ArrayType<VA::MaskVA>;
 | 
			
		||||
    type MaskValue = Array<VA::MaskVA>;
 | 
			
		||||
    type MatchVariant = VA::Match;
 | 
			
		||||
impl<T: Type, Len: Size> Type for ArrayType<T, Len> {
 | 
			
		||||
    type MaskType = ArrayType<T::MaskType, Len>;
 | 
			
		||||
    type MatchVariant = Len::ArrayMatch<T>;
 | 
			
		||||
    type MatchActiveScope = ();
 | 
			
		||||
    type MatchVariantAndInactiveScope = MatchVariantWithoutScope<VA::Match>;
 | 
			
		||||
    type MatchVariantAndInactiveScope = MatchVariantWithoutScope<Len::ArrayMatch<T>>;
 | 
			
		||||
    type MatchVariantsIter = std::iter::Once<Self::MatchVariantAndInactiveScope>;
 | 
			
		||||
 | 
			
		||||
    fn match_variants<IO: BundleValue>(
 | 
			
		||||
        this: Expr<Self::Value>,
 | 
			
		||||
        module_builder: &mut ModuleBuilder<IO, NormalModule>,
 | 
			
		||||
    fn match_variants(
 | 
			
		||||
        this: Expr<Self>,
 | 
			
		||||
        module_builder: &mut ModuleBuilder<NormalModule>,
 | 
			
		||||
        source_location: SourceLocation,
 | 
			
		||||
    ) -> Self::MatchVariantsIter
 | 
			
		||||
    where
 | 
			
		||||
        IO::Type: BundleType<Value = IO>,
 | 
			
		||||
    {
 | 
			
		||||
    ) -> Self::MatchVariantsIter {
 | 
			
		||||
        let base = Expr::as_dyn_array(this);
 | 
			
		||||
        let base_ty = Expr::ty(base);
 | 
			
		||||
        let _ = module_builder;
 | 
			
		||||
        let _ = source_location;
 | 
			
		||||
        std::iter::once(MatchVariantWithoutScope(VA::make_match(this)))
 | 
			
		||||
        let retval = Vec::from_iter(
 | 
			
		||||
            (0..base_ty.len()).map(|i| ArrayIndex::new_unchecked(base, i).to_expr()),
 | 
			
		||||
        );
 | 
			
		||||
        std::iter::once(MatchVariantWithoutScope(
 | 
			
		||||
            Len::ArrayMatch::<T>::try_from(retval)
 | 
			
		||||
                .ok()
 | 
			
		||||
                .expect("unreachable"),
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn mask_type(&self) -> Self::MaskType {
 | 
			
		||||
        #[derive(Clone, Hash, Eq, PartialEq)]
 | 
			
		||||
        struct ArrayMaskTypeMemoize<T: ArrayTypeTrait>(PhantomData<T>);
 | 
			
		||||
        impl<T: ArrayTypeTrait> Copy for ArrayMaskTypeMemoize<T> {}
 | 
			
		||||
        impl<T: ArrayTypeTrait> Memoize for ArrayMaskTypeMemoize<T> {
 | 
			
		||||
            type Input = ArrayType<T::ValueArrayOrSlice>;
 | 
			
		||||
            type InputOwned = ArrayType<T::ValueArrayOrSlice>;
 | 
			
		||||
            type Output = <ArrayType<T::ValueArrayOrSlice> as Type>::MaskType;
 | 
			
		||||
 | 
			
		||||
            fn inner(self, input: &Self::Input) -> Self::Output {
 | 
			
		||||
                ArrayType::new_with_len_type(input.element.mask_type(), input.len)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        ArrayMaskTypeMemoize::<Self>(PhantomData).get(self)
 | 
			
		||||
        ArrayType::new(self.element().mask_type(), self.impl_.len)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn canonical(&self) -> Self::CanonicalType {
 | 
			
		||||
        ArrayType {
 | 
			
		||||
            element: self.element.canonical_dyn(),
 | 
			
		||||
            len: self.len(),
 | 
			
		||||
            bit_width: self.bit_width,
 | 
			
		||||
        }
 | 
			
		||||
    fn canonical(&self) -> CanonicalType {
 | 
			
		||||
        CanonicalType::Array(Array::new_dyn(self.element().canonical(), self.len()))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn source_location(&self) -> SourceLocation {
 | 
			
		||||
    #[track_caller]
 | 
			
		||||
    fn from_canonical(canonical_type: CanonicalType) -> Self {
 | 
			
		||||
        let CanonicalType::Array(array) = canonical_type else {
 | 
			
		||||
            panic!("expected array");
 | 
			
		||||
        };
 | 
			
		||||
        Self::new(
 | 
			
		||||
            T::from_canonical(*array.element()),
 | 
			
		||||
            Len::from_usize(array.len()),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
    fn source_location() -> SourceLocation {
 | 
			
		||||
        SourceLocation::builtin()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    fn type_enum(&self) -> TypeEnum {
 | 
			
		||||
        TypeEnum::ArrayType(self.canonical())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn from_canonical_type(t: Self::CanonicalType) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            element: VA::ElementType::from_dyn_canonical_type(t.element),
 | 
			
		||||
            len: VA::try_len_type_from_len(t.len).expect("length should match"),
 | 
			
		||||
            bit_width: t.bit_width,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn as_dyn_canonical_type_impl(this: &Self) -> Option<&dyn DynCanonicalType> {
 | 
			
		||||
        Some(<dyn Any>::downcast_ref::<ArrayType<[DynCanonicalValue]>>(
 | 
			
		||||
            this,
 | 
			
		||||
        )?)
 | 
			
		||||
impl<T: Type, Len: Size> TypeWithDeref for ArrayType<T, Len> {
 | 
			
		||||
    fn expr_deref(this: &Expr<Self>) -> &Self::MatchVariant {
 | 
			
		||||
        let base = Expr::as_dyn_array(*this);
 | 
			
		||||
        let base_ty = Expr::ty(base);
 | 
			
		||||
        let retval = Vec::from_iter(
 | 
			
		||||
            (0..base_ty.len()).map(|i| ArrayIndex::new_unchecked(base, i).to_expr()),
 | 
			
		||||
        );
 | 
			
		||||
        Interned::<_>::into_inner(Intern::intern_sized(
 | 
			
		||||
            Len::ArrayMatch::<T>::try_from(retval)
 | 
			
		||||
                .ok()
 | 
			
		||||
                .expect("unreachable"),
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<Lhs: ValueArrayOrSlice + ?Sized, Rhs: ValueArrayOrSlice + ?Sized> Connect<ArrayType<Rhs>>
 | 
			
		||||
    for ArrayType<Lhs>
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
 | 
			
		||||
pub struct ArrayWithoutGenerics;
 | 
			
		||||
 | 
			
		||||
impl CanonicalType for ArrayType<[DynCanonicalValue]> {
 | 
			
		||||
    const CANONICAL_TYPE_KIND: CanonicalTypeKind = CanonicalTypeKind::ArrayType;
 | 
			
		||||
}
 | 
			
		||||
impl<T: Type> Index<T> for ArrayWithoutGenerics {
 | 
			
		||||
    type Output = ArrayWithoutLen<T>;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, PartialEq, Eq, Hash)]
 | 
			
		||||
pub struct Array<VA: ValueArrayOrSlice + ?Sized> {
 | 
			
		||||
    element_ty: VA::ElementType,
 | 
			
		||||
    value: Arc<VA>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice + ?Sized> Clone for Array<VA> {
 | 
			
		||||
    fn clone(&self) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            element_ty: self.element_ty.clone(),
 | 
			
		||||
            value: self.value.clone(),
 | 
			
		||||
        }
 | 
			
		||||
    fn index(&self, element: T) -> &Self::Output {
 | 
			
		||||
        Interned::<_>::into_inner(Intern::intern_sized(ArrayWithoutLen { element }))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice + ?Sized> ToExpr for Array<VA> {
 | 
			
		||||
    type Type = ArrayType<VA>;
 | 
			
		||||
 | 
			
		||||
    fn ty(&self) -> Self::Type {
 | 
			
		||||
        ArrayType::new_with_len_type(self.element_ty.clone(), self.value.len_type())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn to_expr(&self) -> Expr<<Self::Type as Type>::Value> {
 | 
			
		||||
        Expr::from_value(self)
 | 
			
		||||
    }
 | 
			
		||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 | 
			
		||||
pub struct ArrayWithoutLen<T: Type> {
 | 
			
		||||
    element: T,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice + ?Sized> Value for Array<VA> {
 | 
			
		||||
    fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
 | 
			
		||||
        Array {
 | 
			
		||||
            element_ty: self.element_ty.canonical_dyn(),
 | 
			
		||||
            value: AsRef::<[_]>::as_ref(&*self.value)
 | 
			
		||||
                .iter()
 | 
			
		||||
                .map(|v| v.to_canonical_dyn())
 | 
			
		||||
                .collect(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
			
		||||
        #[derive(Hash, Eq, PartialEq)]
 | 
			
		||||
        struct ArrayToBitsMemoize<VA: ValueArrayOrSlice + ?Sized>(PhantomData<VA>);
 | 
			
		||||
        impl<VA: ValueArrayOrSlice + ?Sized> Clone for ArrayToBitsMemoize<VA> {
 | 
			
		||||
            fn clone(&self) -> Self {
 | 
			
		||||
                *self
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        impl<VA: ValueArrayOrSlice + ?Sized> Copy for ArrayToBitsMemoize<VA> {}
 | 
			
		||||
        impl<VA: ValueArrayOrSlice + ?Sized> Memoize for ArrayToBitsMemoize<VA> {
 | 
			
		||||
            type Input = Array<VA>;
 | 
			
		||||
            type InputOwned = Array<VA>;
 | 
			
		||||
            type Output = Interned<BitSlice>;
 | 
			
		||||
impl<T: Type> Index<usize> for ArrayWithoutLen<T> {
 | 
			
		||||
    type Output = Array<T>;
 | 
			
		||||
 | 
			
		||||
            fn inner(self, input: &Self::Input) -> Self::Output {
 | 
			
		||||
                let mut bits = BitVec::with_capacity(input.ty().bit_width());
 | 
			
		||||
                for element in AsRef::<[_]>::as_ref(&*input.value).iter() {
 | 
			
		||||
                    bits.extend_from_bitslice(&element.to_bits());
 | 
			
		||||
                }
 | 
			
		||||
                Intern::intern_owned(bits)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        ArrayToBitsMemoize::<VA>(PhantomData).get(this)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl CanonicalValue for Array<[DynCanonicalValue]> {
 | 
			
		||||
    fn value_enum_impl(this: &Self) -> ValueEnum {
 | 
			
		||||
        ValueEnum::Array(this.clone())
 | 
			
		||||
    }
 | 
			
		||||
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
			
		||||
        Value::to_bits_impl(this)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice + ?Sized> Array<VA> {
 | 
			
		||||
    pub fn element_ty(&self) -> &VA::ElementType {
 | 
			
		||||
        &self.element_ty
 | 
			
		||||
    }
 | 
			
		||||
    pub fn len(&self) -> usize {
 | 
			
		||||
        VA::len_from_len_type(self.value.len_type())
 | 
			
		||||
    }
 | 
			
		||||
    pub fn is_empty(&self) -> bool {
 | 
			
		||||
        self.len() == 0
 | 
			
		||||
    }
 | 
			
		||||
    pub fn value(&self) -> &Arc<VA> {
 | 
			
		||||
        &self.value
 | 
			
		||||
    }
 | 
			
		||||
    pub fn set_element(&mut self, index: usize, element: VA::Element) {
 | 
			
		||||
        assert_eq!(self.element_ty, element.ty());
 | 
			
		||||
        VA::arc_make_mut(&mut self.value)[index] = element;
 | 
			
		||||
    }
 | 
			
		||||
    pub fn new(element_ty: VA::ElementType, value: Arc<VA>) -> Self {
 | 
			
		||||
        for element in value.iter() {
 | 
			
		||||
            assert_eq!(element_ty, element.ty());
 | 
			
		||||
        }
 | 
			
		||||
        Self { element_ty, value }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn into_slice(self) -> Array<[VA::Element]> {
 | 
			
		||||
        Array {
 | 
			
		||||
            element_ty: self.element_ty,
 | 
			
		||||
            value: self.value.arc_to_arc_slice(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice + ?Sized, T: Into<Arc<VA>>> From<T> for Array<VA>
 | 
			
		||||
where
 | 
			
		||||
    VA::Element: StaticValue,
 | 
			
		||||
{
 | 
			
		||||
    fn from(value: T) -> Self {
 | 
			
		||||
        Self::new(StaticType::static_type(), value.into())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<E: ToExpr<Type = T>, T: StaticType<MaskType: StaticType>> ToExpr for [E] {
 | 
			
		||||
    type Type = ArrayType<[T::Value]>;
 | 
			
		||||
 | 
			
		||||
    fn ty(&self) -> Self::Type {
 | 
			
		||||
        ArrayType::new_with_len_type(StaticType::static_type(), self.len())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn to_expr(&self) -> Expr<<Self::Type as Type>::Value> {
 | 
			
		||||
        let elements = Intern::intern_owned(Vec::from_iter(
 | 
			
		||||
            self.iter().map(|v| v.to_expr().to_canonical_dyn()),
 | 
			
		||||
        ));
 | 
			
		||||
        ArrayLiteral::new_unchecked(elements, self.ty()).to_expr()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<E: ToExpr<Type = T>, T: StaticType<MaskType: StaticType>> ToExpr for Vec<E> {
 | 
			
		||||
    type Type = ArrayType<[T::Value]>;
 | 
			
		||||
 | 
			
		||||
    fn ty(&self) -> Self::Type {
 | 
			
		||||
        <[E]>::ty(self)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn to_expr(&self) -> Expr<<Self::Type as Type>::Value> {
 | 
			
		||||
        <[E]>::to_expr(self)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<E: ToExpr<Type = T>, T: StaticType<MaskType: StaticType>, const N: usize> ToExpr for [E; N] {
 | 
			
		||||
    type Type = ArrayType<[T::Value; N]>;
 | 
			
		||||
 | 
			
		||||
    fn ty(&self) -> Self::Type {
 | 
			
		||||
        ArrayType::new_with_len_type(StaticType::static_type(), ())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn to_expr(&self) -> Expr<<Self::Type as Type>::Value> {
 | 
			
		||||
        let elements = Intern::intern_owned(Vec::from_iter(
 | 
			
		||||
            self.iter().map(|v| v.to_expr().to_canonical_dyn()),
 | 
			
		||||
        ));
 | 
			
		||||
        ArrayLiteral::new_unchecked(elements, self.ty()).to_expr()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub struct ArrayIntoIter<VA: ValueArrayOrSlice> {
 | 
			
		||||
    array: Arc<VA>,
 | 
			
		||||
    indexes: std::ops::Range<usize>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice> Iterator for ArrayIntoIter<VA> {
 | 
			
		||||
    type Item = VA::Element;
 | 
			
		||||
 | 
			
		||||
    fn next(&mut self) -> Option<Self::Item> {
 | 
			
		||||
        Some(self.array[self.indexes.next()?].clone())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn size_hint(&self) -> (usize, Option<usize>) {
 | 
			
		||||
        self.indexes.size_hint()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice> std::iter::FusedIterator for ArrayIntoIter<VA> {}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice> ExactSizeIterator for ArrayIntoIter<VA> {}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice> DoubleEndedIterator for ArrayIntoIter<VA> {
 | 
			
		||||
    fn next_back(&mut self) -> Option<Self::Item> {
 | 
			
		||||
        Some(self.array[self.indexes.next_back()?].clone())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice> Array<VA> {
 | 
			
		||||
    pub fn iter(&self) -> std::slice::Iter<'_, VA::Element> {
 | 
			
		||||
        self.value.iter()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a, VA: ValueArrayOrSlice> IntoIterator for &'a Array<VA> {
 | 
			
		||||
    type Item = &'a VA::Element;
 | 
			
		||||
    type IntoIter = std::slice::Iter<'a, VA::Element>;
 | 
			
		||||
 | 
			
		||||
    fn into_iter(self) -> Self::IntoIter {
 | 
			
		||||
        self.value.iter()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice> IntoIterator for Array<VA> {
 | 
			
		||||
    type Item = VA::Element;
 | 
			
		||||
    type IntoIter = ArrayIntoIter<VA>;
 | 
			
		||||
 | 
			
		||||
    fn into_iter(self) -> Self::IntoIter {
 | 
			
		||||
        ArrayIntoIter {
 | 
			
		||||
            indexes: 0..self.len(),
 | 
			
		||||
            array: self.value,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub struct ArrayExprIter<VA: ValueArrayOrSlice> {
 | 
			
		||||
    array: Expr<Array<VA>>,
 | 
			
		||||
    indexes: std::ops::Range<usize>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice> Iterator for ArrayExprIter<VA> {
 | 
			
		||||
    type Item = Expr<VA::Element>;
 | 
			
		||||
 | 
			
		||||
    fn next(&mut self) -> Option<Self::Item> {
 | 
			
		||||
        Some(ExprIndex::expr_index(self.array, self.indexes.next()?))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn size_hint(&self) -> (usize, Option<usize>) {
 | 
			
		||||
        self.indexes.size_hint()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice> std::iter::FusedIterator for ArrayExprIter<VA> {}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice> ExactSizeIterator for ArrayExprIter<VA> {}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice> DoubleEndedIterator for ArrayExprIter<VA> {
 | 
			
		||||
    fn next_back(&mut self) -> Option<Self::Item> {
 | 
			
		||||
        Some(ExprIndex::expr_index(self.array, self.indexes.next_back()?))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice> IntoIterator for Expr<Array<VA>> {
 | 
			
		||||
    type Item = Expr<VA::Element>;
 | 
			
		||||
    type IntoIter = ArrayExprIter<VA>;
 | 
			
		||||
 | 
			
		||||
    fn into_iter(self) -> Self::IntoIter {
 | 
			
		||||
        self.iter()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice> IntoIterator for &'_ Expr<Array<VA>> {
 | 
			
		||||
    type Item = Expr<VA::Element>;
 | 
			
		||||
    type IntoIter = ArrayExprIter<VA>;
 | 
			
		||||
 | 
			
		||||
    fn into_iter(self) -> Self::IntoIter {
 | 
			
		||||
        self.iter()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<VA: ValueArrayOrSlice> Expr<Array<VA>> {
 | 
			
		||||
    pub fn len(self) -> usize {
 | 
			
		||||
        self.canonical_type().len()
 | 
			
		||||
    }
 | 
			
		||||
    pub fn is_empty(self) -> bool {
 | 
			
		||||
        self.canonical_type().is_empty()
 | 
			
		||||
    }
 | 
			
		||||
    pub fn iter(self) -> ArrayExprIter<VA> {
 | 
			
		||||
        ArrayExprIter {
 | 
			
		||||
            indexes: 0..self.len(),
 | 
			
		||||
            array: self,
 | 
			
		||||
        }
 | 
			
		||||
    fn index(&self, len: usize) -> &Self::Output {
 | 
			
		||||
        Interned::<_>::into_inner(Intern::intern_sized(Array::new_dyn(self.element, len)))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -1,150 +1,58 @@
 | 
			
		|||
// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
			
		||||
// See Notices.txt for copyright information
 | 
			
		||||
#![allow(clippy::type_complexity)]
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    bundle::{BundleValue, TypeHintTrait},
 | 
			
		||||
    expr::{ops::VariantAccess, Expr, ToExpr},
 | 
			
		||||
    int::{UInt, UIntType},
 | 
			
		||||
    intern::{Intern, Interned, MemoizeGeneric},
 | 
			
		||||
    hdl,
 | 
			
		||||
    int::Bool,
 | 
			
		||||
    intern::{Intern, Interned},
 | 
			
		||||
    module::{
 | 
			
		||||
        EnumMatchVariantAndInactiveScopeImpl, EnumMatchVariantsIterImpl, ModuleBuilder,
 | 
			
		||||
        NormalModule, Scope,
 | 
			
		||||
    },
 | 
			
		||||
    source_location::SourceLocation,
 | 
			
		||||
    ty::{
 | 
			
		||||
        CanonicalType, CanonicalTypeKind, CanonicalValue, Connect, DynCanonicalType,
 | 
			
		||||
        DynCanonicalValue, DynType, MatchVariantAndInactiveScope, Type, TypeEnum, Value, ValueEnum,
 | 
			
		||||
    },
 | 
			
		||||
    ty::{CanonicalType, MatchVariantAndInactiveScope, Type, TypeProperties},
 | 
			
		||||
};
 | 
			
		||||
use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView};
 | 
			
		||||
use hashbrown::HashMap;
 | 
			
		||||
use std::{
 | 
			
		||||
    borrow::Cow,
 | 
			
		||||
    fmt,
 | 
			
		||||
    hash::{Hash, Hasher},
 | 
			
		||||
    iter::FusedIterator,
 | 
			
		||||
    marker::PhantomData,
 | 
			
		||||
};
 | 
			
		||||
use std::iter::FusedIterator;
 | 
			
		||||
 | 
			
		||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
 | 
			
		||||
pub struct VariantType<T> {
 | 
			
		||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 | 
			
		||||
pub struct EnumVariant {
 | 
			
		||||
    pub name: Interned<str>,
 | 
			
		||||
    pub ty: Option<T>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct FmtDebugInEnum<'a, T>(&'a VariantType<T>);
 | 
			
		||||
 | 
			
		||||
impl<T: fmt::Debug> fmt::Debug for FmtDebugInEnum<'_, T> {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        let VariantType { name, ref ty } = *self.0;
 | 
			
		||||
        if let Some(ty) = ty {
 | 
			
		||||
            write!(f, "{name}({ty:?})")
 | 
			
		||||
        } else {
 | 
			
		||||
            write!(f, "{name}")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: fmt::Debug> fmt::Display for FmtDebugInEnum<'_, T> {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        fmt::Debug::fmt(self, f)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T> VariantType<T> {
 | 
			
		||||
    pub fn map_opt_ty<U, F: FnOnce(Option<T>) -> Option<U>>(self, f: F) -> VariantType<U> {
 | 
			
		||||
        let Self { name, ty } = self;
 | 
			
		||||
        VariantType { name, ty: f(ty) }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn map_ty<U, F: FnOnce(T) -> U>(self, f: F) -> VariantType<U> {
 | 
			
		||||
        let Self { name, ty } = self;
 | 
			
		||||
        VariantType {
 | 
			
		||||
            name,
 | 
			
		||||
            ty: ty.map(f),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn as_ref_ty(&self) -> VariantType<&T> {
 | 
			
		||||
        VariantType {
 | 
			
		||||
            name: self.name,
 | 
			
		||||
            ty: self.ty.as_ref(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn fmt_debug_in_enum(&self) -> FmtDebugInEnum<T> {
 | 
			
		||||
        FmtDebugInEnum(self)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: Type> VariantType<T> {
 | 
			
		||||
    pub fn canonical(&self) -> VariantType<T::CanonicalType> {
 | 
			
		||||
        self.as_ref_ty().map_ty(T::canonical)
 | 
			
		||||
    }
 | 
			
		||||
    pub fn to_dyn(&self) -> VariantType<Interned<dyn DynType>> {
 | 
			
		||||
        self.as_ref_ty().map_ty(T::to_dyn)
 | 
			
		||||
    }
 | 
			
		||||
    pub fn canonical_dyn(&self) -> VariantType<Interned<dyn DynCanonicalType>> {
 | 
			
		||||
        self.as_ref_ty().map_ty(T::canonical_dyn)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl VariantType<Interned<dyn DynCanonicalType>> {
 | 
			
		||||
    pub fn from_canonical_type_helper_has_value<T: Type>(self, expected_name: &str) -> T {
 | 
			
		||||
        assert_eq!(&*self.name, expected_name, "variant name doesn't match");
 | 
			
		||||
        let Some(ty) = self.ty else {
 | 
			
		||||
            panic!("variant {expected_name} has no value but a value is expected");
 | 
			
		||||
        };
 | 
			
		||||
        T::from_dyn_canonical_type(ty)
 | 
			
		||||
    }
 | 
			
		||||
    pub fn from_canonical_type_helper_no_value(self, expected_name: &str) {
 | 
			
		||||
        assert_eq!(&*self.name, expected_name, "variant name doesn't match");
 | 
			
		||||
        assert!(
 | 
			
		||||
            self.ty.is_none(),
 | 
			
		||||
            "variant {expected_name} has a value but is expected to have no value"
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
    pub ty: Option<CanonicalType>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Eq)]
 | 
			
		||||
struct DynEnumTypeImpl {
 | 
			
		||||
    variants: Interned<[VariantType<Interned<dyn DynCanonicalType>>]>,
 | 
			
		||||
struct EnumImpl {
 | 
			
		||||
    variants: Interned<[EnumVariant]>,
 | 
			
		||||
    name_indexes: HashMap<Interned<str>, usize>,
 | 
			
		||||
    bit_width: usize,
 | 
			
		||||
    is_storable: bool,
 | 
			
		||||
    is_castable_from_bits: bool,
 | 
			
		||||
    type_properties: TypeProperties,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Debug for DynEnumTypeImpl {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        write!(f, "DynEnumType ")?;
 | 
			
		||||
        f.debug_set()
 | 
			
		||||
            .entries(
 | 
			
		||||
                self.variants
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|variant| variant.fmt_debug_in_enum()),
 | 
			
		||||
            )
 | 
			
		||||
impl std::fmt::Debug for EnumImpl {
 | 
			
		||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
			
		||||
        f.debug_struct("Enum")
 | 
			
		||||
            .field("variants", &self.variants)
 | 
			
		||||
            .field("name_indexes", &self.name_indexes)
 | 
			
		||||
            .field("type_properties", &self.type_properties)
 | 
			
		||||
            .finish()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PartialEq for DynEnumTypeImpl {
 | 
			
		||||
impl std::hash::Hash for EnumImpl {
 | 
			
		||||
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
 | 
			
		||||
        self.variants.hash(state);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PartialEq for EnumImpl {
 | 
			
		||||
    fn eq(&self, other: &Self) -> bool {
 | 
			
		||||
        self.variants == other.variants
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Hash for DynEnumTypeImpl {
 | 
			
		||||
    fn hash<H: Hasher>(&self, state: &mut H) {
 | 
			
		||||
        self.variants.hash(state);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
 | 
			
		||||
pub struct DynEnumType(Interned<DynEnumTypeImpl>);
 | 
			
		||||
 | 
			
		||||
impl fmt::Debug for DynEnumType {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        self.0.fmt(f)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 | 
			
		||||
pub struct Enum(Interned<EnumImpl>);
 | 
			
		||||
 | 
			
		||||
fn discriminant_bit_width_impl(variant_count: usize) -> usize {
 | 
			
		||||
    variant_count
 | 
			
		||||
| 
						 | 
				
			
			@ -153,38 +61,47 @@ fn discriminant_bit_width_impl(variant_count: usize) -> usize {
 | 
			
		|||
        .unwrap_or(0) as usize
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl DynEnumType {
 | 
			
		||||
impl Enum {
 | 
			
		||||
    #[track_caller]
 | 
			
		||||
    pub fn new(variants: Interned<[VariantType<Interned<dyn DynCanonicalType>>]>) -> Self {
 | 
			
		||||
    pub fn new(variants: Interned<[EnumVariant]>) -> Self {
 | 
			
		||||
        assert!(!variants.is_empty(), "zero-variant enums aren't yet supported: https://github.com/chipsalliance/firrtl-spec/issues/208");
 | 
			
		||||
        let mut name_indexes = HashMap::with_capacity(variants.len());
 | 
			
		||||
        let mut body_bit_width = 0usize;
 | 
			
		||||
        let mut is_storable = true;
 | 
			
		||||
        let mut is_castable_from_bits = true;
 | 
			
		||||
        for (index, &VariantType { name, ty }) in variants.iter().enumerate() {
 | 
			
		||||
            if let Some(old_index) = name_indexes.insert(name, index) {
 | 
			
		||||
        let mut type_properties = TypeProperties {
 | 
			
		||||
            is_passive: true,
 | 
			
		||||
            is_storable: true,
 | 
			
		||||
            is_castable_from_bits: true,
 | 
			
		||||
            bit_width: 0,
 | 
			
		||||
        };
 | 
			
		||||
        for (index, EnumVariant { name, ty }) in variants.iter().enumerate() {
 | 
			
		||||
            if let Some(old_index) = name_indexes.insert(*name, index) {
 | 
			
		||||
                panic!("duplicate variant name {name:?}: at both index {old_index} and {index}");
 | 
			
		||||
            }
 | 
			
		||||
            if let Some(ty) = ty {
 | 
			
		||||
                assert!(
 | 
			
		||||
                    ty.is_passive(),
 | 
			
		||||
                    "variant type must be a passive type: {ty:?}"
 | 
			
		||||
                );
 | 
			
		||||
                body_bit_width = body_bit_width.max(ty.bit_width());
 | 
			
		||||
                is_storable &= ty.is_storable();
 | 
			
		||||
                is_castable_from_bits &= ty.is_castable_from_bits();
 | 
			
		||||
                let TypeProperties {
 | 
			
		||||
                    is_passive,
 | 
			
		||||
                    is_storable,
 | 
			
		||||
                    is_castable_from_bits,
 | 
			
		||||
                    bit_width,
 | 
			
		||||
                } = ty.type_properties();
 | 
			
		||||
                assert!(is_passive, "variant type must be a passive type: {ty:?}");
 | 
			
		||||
                type_properties = TypeProperties {
 | 
			
		||||
                    is_passive: true,
 | 
			
		||||
                    is_storable: type_properties.is_storable & is_storable,
 | 
			
		||||
                    is_castable_from_bits: type_properties.is_castable_from_bits
 | 
			
		||||
                        & is_castable_from_bits,
 | 
			
		||||
                    bit_width: type_properties.bit_width.max(bit_width),
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        let bit_width = body_bit_width
 | 
			
		||||
        type_properties.bit_width = type_properties
 | 
			
		||||
            .bit_width
 | 
			
		||||
            .checked_add(discriminant_bit_width_impl(variants.len()))
 | 
			
		||||
            .unwrap_or_else(|| panic!("enum is too big: bit-width overflowed"));
 | 
			
		||||
        Self(
 | 
			
		||||
            DynEnumTypeImpl {
 | 
			
		||||
            EnumImpl {
 | 
			
		||||
                variants,
 | 
			
		||||
                name_indexes,
 | 
			
		||||
                bit_width,
 | 
			
		||||
                is_storable,
 | 
			
		||||
                is_castable_from_bits,
 | 
			
		||||
                type_properties,
 | 
			
		||||
            }
 | 
			
		||||
            .intern_sized(),
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			@ -192,233 +109,31 @@ impl DynEnumType {
 | 
			
		|||
    pub fn discriminant_bit_width(self) -> usize {
 | 
			
		||||
        discriminant_bit_width_impl(self.variants().len())
 | 
			
		||||
    }
 | 
			
		||||
    pub fn is_passive(self) -> bool {
 | 
			
		||||
        true
 | 
			
		||||
    }
 | 
			
		||||
    pub fn is_storable(self) -> bool {
 | 
			
		||||
        self.0.is_storable
 | 
			
		||||
    }
 | 
			
		||||
    pub fn is_castable_from_bits(self) -> bool {
 | 
			
		||||
        self.0.is_castable_from_bits
 | 
			
		||||
    }
 | 
			
		||||
    pub fn bit_width(self) -> usize {
 | 
			
		||||
        self.0.bit_width
 | 
			
		||||
    pub fn type_properties(self) -> TypeProperties {
 | 
			
		||||
        self.0.type_properties
 | 
			
		||||
    }
 | 
			
		||||
    pub fn name_indexes(&self) -> &HashMap<Interned<str>, usize> {
 | 
			
		||||
        &self.0.name_indexes
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
 | 
			
		||||
pub struct DynEnum {
 | 
			
		||||
    ty: DynEnumType,
 | 
			
		||||
    variant_index: usize,
 | 
			
		||||
    variant_value: Option<DynCanonicalValue>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl DynEnum {
 | 
			
		||||
    #[track_caller]
 | 
			
		||||
    pub fn new_by_index(
 | 
			
		||||
        ty: DynEnumType,
 | 
			
		||||
        variant_index: usize,
 | 
			
		||||
        variant_value: Option<DynCanonicalValue>,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        let variant = ty.variants()[variant_index];
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            variant_value.as_ref().map(|v| v.ty()),
 | 
			
		||||
            variant.ty,
 | 
			
		||||
            "variant value doesn't match type"
 | 
			
		||||
        );
 | 
			
		||||
        Self {
 | 
			
		||||
            ty,
 | 
			
		||||
            variant_index,
 | 
			
		||||
            variant_value,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    #[track_caller]
 | 
			
		||||
    pub fn new_by_name(
 | 
			
		||||
        ty: DynEnumType,
 | 
			
		||||
        variant_name: Interned<str>,
 | 
			
		||||
        variant_value: Option<DynCanonicalValue>,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        let variant_index = ty.name_indexes()[&variant_name];
 | 
			
		||||
        Self::new_by_index(ty, variant_index, variant_value)
 | 
			
		||||
    }
 | 
			
		||||
    pub fn variant_index(&self) -> usize {
 | 
			
		||||
        self.variant_index
 | 
			
		||||
    }
 | 
			
		||||
    pub fn variant_value(&self) -> &Option<DynCanonicalValue> {
 | 
			
		||||
        &self.variant_value
 | 
			
		||||
    }
 | 
			
		||||
    pub fn variant_with_type(&self) -> VariantType<Interned<dyn DynCanonicalType>> {
 | 
			
		||||
        self.ty.variants()[self.variant_index]
 | 
			
		||||
    }
 | 
			
		||||
    pub fn variant_name(&self) -> Interned<str> {
 | 
			
		||||
        self.variant_with_type().name
 | 
			
		||||
    }
 | 
			
		||||
    pub fn variant_type(&self) -> Option<Interned<dyn DynCanonicalType>> {
 | 
			
		||||
        self.variant_with_type().ty
 | 
			
		||||
    }
 | 
			
		||||
    pub fn variant_with_value(&self) -> VariantType<&DynCanonicalValue> {
 | 
			
		||||
        self.variant_with_type()
 | 
			
		||||
            .map_opt_ty(|_| self.variant_value.as_ref())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
 | 
			
		||||
pub struct VariantsHint {
 | 
			
		||||
    pub known_variants: Interned<[VariantType<Interned<dyn TypeHintTrait>>]>,
 | 
			
		||||
    pub more_variants: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl VariantsHint {
 | 
			
		||||
    pub fn new(
 | 
			
		||||
        known_variants: impl IntoIterator<Item = VariantType<Interned<dyn TypeHintTrait>>>,
 | 
			
		||||
        more_variants: bool,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        let known_variants = Intern::intern_owned(Vec::from_iter(known_variants));
 | 
			
		||||
        Self {
 | 
			
		||||
            known_variants,
 | 
			
		||||
            more_variants,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn check_variant(
 | 
			
		||||
        self,
 | 
			
		||||
        index: usize,
 | 
			
		||||
        variant: VariantType<&dyn DynType>,
 | 
			
		||||
    ) -> Result<(), String> {
 | 
			
		||||
        let Some(&known_variant) = self.known_variants.get(index) else {
 | 
			
		||||
            return if self.more_variants {
 | 
			
		||||
                Ok(())
 | 
			
		||||
            } else {
 | 
			
		||||
                Err(format!(
 | 
			
		||||
                    "too many variants: name={:?} index={index}",
 | 
			
		||||
                    variant.name
 | 
			
		||||
                ))
 | 
			
		||||
            };
 | 
			
		||||
        };
 | 
			
		||||
        let VariantType {
 | 
			
		||||
            name: known_name,
 | 
			
		||||
            ty: type_hint,
 | 
			
		||||
        } = known_variant;
 | 
			
		||||
        let VariantType { name, ty } = variant;
 | 
			
		||||
        if name != known_name {
 | 
			
		||||
            Err(format!(
 | 
			
		||||
                "wrong variant name {name:?}, expected {known_name:?}"
 | 
			
		||||
            ))
 | 
			
		||||
        } else {
 | 
			
		||||
            match (ty, type_hint) {
 | 
			
		||||
                (Some(ty), Some(type_hint)) => type_hint.matches(ty),
 | 
			
		||||
                (None, None) => Ok(()),
 | 
			
		||||
                (None, Some(_)) => Err(format!(
 | 
			
		||||
                    "expected variant {name:?} to have type, no type provided"
 | 
			
		||||
                )),
 | 
			
		||||
                (Some(_), None) => Err(format!(
 | 
			
		||||
                    "expected variant {name:?} to have no type, but a type was provided"
 | 
			
		||||
                )),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait EnumType:
 | 
			
		||||
    Type<
 | 
			
		||||
        CanonicalType = DynEnumType,
 | 
			
		||||
        CanonicalValue = DynEnum,
 | 
			
		||||
        MaskType = UIntType<1>,
 | 
			
		||||
        MaskValue = UInt<1>,
 | 
			
		||||
        MatchActiveScope = Scope,
 | 
			
		||||
        MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope<Self>,
 | 
			
		||||
        MatchVariantsIter = EnumMatchVariantsIter<Self>,
 | 
			
		||||
    > + Connect<Self>
 | 
			
		||||
where
 | 
			
		||||
    Self::Value: EnumValue + ToExpr<Type = Self>,
 | 
			
		||||
    MaskType = Bool,
 | 
			
		||||
    MatchActiveScope = Scope,
 | 
			
		||||
    MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope<Self>,
 | 
			
		||||
    MatchVariantsIter = EnumMatchVariantsIter<Self>,
 | 
			
		||||
>
 | 
			
		||||
{
 | 
			
		||||
    type Builder;
 | 
			
		||||
    fn variants(&self) -> Interned<[EnumVariant]>;
 | 
			
		||||
    fn match_activate_scope(
 | 
			
		||||
        v: Self::MatchVariantAndInactiveScope,
 | 
			
		||||
    ) -> (Self::MatchVariant, Self::MatchActiveScope);
 | 
			
		||||
    fn builder() -> Self::Builder;
 | 
			
		||||
    fn variants(&self) -> Interned<[VariantType<Interned<dyn DynCanonicalType>>]>;
 | 
			
		||||
    fn variants_hint() -> VariantsHint;
 | 
			
		||||
    #[allow(clippy::result_unit_err)]
 | 
			
		||||
    fn variant_to_bits<VariantValue: ToExpr + Eq + Hash + Send + Sync + 'static + Clone>(
 | 
			
		||||
        &self,
 | 
			
		||||
        variant_index: usize,
 | 
			
		||||
        variant_value: Option<&VariantValue>,
 | 
			
		||||
    ) -> Result<Interned<BitSlice>, ()> {
 | 
			
		||||
        #[derive(Hash, Eq, PartialEq)]
 | 
			
		||||
        struct VariantToBitsMemoize<E, V>(PhantomData<(E, V)>);
 | 
			
		||||
        impl<E, V> Clone for VariantToBitsMemoize<E, V> {
 | 
			
		||||
            fn clone(&self) -> Self {
 | 
			
		||||
                *self
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        impl<E, V> Copy for VariantToBitsMemoize<E, V> {}
 | 
			
		||||
        impl<
 | 
			
		||||
                E: EnumType<Value: EnumValue<Type = E>>,
 | 
			
		||||
                V: ToExpr + Eq + Hash + Send + Sync + 'static + Clone,
 | 
			
		||||
            > MemoizeGeneric for VariantToBitsMemoize<E, V>
 | 
			
		||||
        {
 | 
			
		||||
            type InputRef<'a> = (&'a E, usize, Option<&'a V>);
 | 
			
		||||
            type InputOwned = (E, usize, Option<V>);
 | 
			
		||||
            type InputCow<'a> = (Cow<'a, E>, usize, Option<Cow<'a, V>>);
 | 
			
		||||
            type Output = Result<Interned<BitSlice>, ()>;
 | 
			
		||||
 | 
			
		||||
            fn input_borrow(input: &Self::InputOwned) -> Self::InputRef<'_> {
 | 
			
		||||
                (&input.0, input.1, input.2.as_ref())
 | 
			
		||||
            }
 | 
			
		||||
            fn input_eq(a: Self::InputRef<'_>, b: Self::InputRef<'_>) -> bool {
 | 
			
		||||
                a == b
 | 
			
		||||
            }
 | 
			
		||||
            fn input_cow_into_owned(input: Self::InputCow<'_>) -> Self::InputOwned {
 | 
			
		||||
                (input.0.into_owned(), input.1, input.2.map(Cow::into_owned))
 | 
			
		||||
            }
 | 
			
		||||
            fn input_cow_borrow<'a>(input: &'a Self::InputCow<'_>) -> Self::InputRef<'a> {
 | 
			
		||||
                (&input.0, input.1, input.2.as_deref())
 | 
			
		||||
            }
 | 
			
		||||
            fn input_cow_from_owned<'a>(input: Self::InputOwned) -> Self::InputCow<'a> {
 | 
			
		||||
                (Cow::Owned(input.0), input.1, input.2.map(Cow::Owned))
 | 
			
		||||
            }
 | 
			
		||||
            fn input_cow_from_ref(input: Self::InputRef<'_>) -> Self::InputCow<'_> {
 | 
			
		||||
                (Cow::Borrowed(input.0), input.1, input.2.map(Cow::Borrowed))
 | 
			
		||||
            }
 | 
			
		||||
            fn inner(self, input: Self::InputRef<'_>) -> Self::Output {
 | 
			
		||||
                let (ty, variant_index, variant_value) = input;
 | 
			
		||||
                let ty = ty.canonical();
 | 
			
		||||
                let mut bits = BitVec::with_capacity(ty.bit_width());
 | 
			
		||||
                bits.extend_from_bitslice(
 | 
			
		||||
                    &variant_index.view_bits::<Lsb0>()[..ty.discriminant_bit_width()],
 | 
			
		||||
                );
 | 
			
		||||
                if let Some(variant_value) = variant_value {
 | 
			
		||||
                    bits.extend_from_bitslice(&variant_value.to_expr().to_literal_bits()?);
 | 
			
		||||
                }
 | 
			
		||||
                bits.resize(ty.bit_width(), false);
 | 
			
		||||
                Ok(Intern::intern_owned(bits))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        VariantToBitsMemoize::<Self, VariantValue>(PhantomData).get((
 | 
			
		||||
            self,
 | 
			
		||||
            variant_index,
 | 
			
		||||
            variant_value,
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait EnumValue: Value
 | 
			
		||||
where
 | 
			
		||||
    <Self as ToExpr>::Type: EnumType<Value = Self>,
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
pub struct EnumMatchVariantAndInactiveScope<T: EnumType>(EnumMatchVariantAndInactiveScopeImpl<T>);
 | 
			
		||||
 | 
			
		||||
pub struct EnumMatchVariantAndInactiveScope<T: EnumType>(EnumMatchVariantAndInactiveScopeImpl<T>)
 | 
			
		||||
where
 | 
			
		||||
    T::Value: EnumValue<Type = T>;
 | 
			
		||||
 | 
			
		||||
impl<T: EnumType> MatchVariantAndInactiveScope for EnumMatchVariantAndInactiveScope<T>
 | 
			
		||||
where
 | 
			
		||||
    T::Value: EnumValue<Type = T>,
 | 
			
		||||
{
 | 
			
		||||
impl<T: EnumType> MatchVariantAndInactiveScope for EnumMatchVariantAndInactiveScope<T> {
 | 
			
		||||
    type MatchVariant = T::MatchVariant;
 | 
			
		||||
    type MatchActiveScope = Scope;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -427,36 +142,22 @@ where
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: EnumType> EnumMatchVariantAndInactiveScope<T>
 | 
			
		||||
where
 | 
			
		||||
    T::Value: EnumValue<Type = T>,
 | 
			
		||||
{
 | 
			
		||||
    pub fn variant_access(&self) -> Interned<VariantAccess<T, Interned<dyn DynCanonicalType>>> {
 | 
			
		||||
impl<T: EnumType> EnumMatchVariantAndInactiveScope<T> {
 | 
			
		||||
    pub fn variant_access(&self) -> Interned<VariantAccess> {
 | 
			
		||||
        self.0.variant_access()
 | 
			
		||||
    }
 | 
			
		||||
    pub fn activate(
 | 
			
		||||
        self,
 | 
			
		||||
    ) -> (
 | 
			
		||||
        Interned<VariantAccess<T, Interned<dyn DynCanonicalType>>>,
 | 
			
		||||
        Scope,
 | 
			
		||||
    ) {
 | 
			
		||||
    pub fn activate(self) -> (Interned<VariantAccess>, Scope) {
 | 
			
		||||
        self.0.activate()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct EnumMatchVariantsIter<T: EnumType>
 | 
			
		||||
where
 | 
			
		||||
    T::Value: EnumValue<Type = T>,
 | 
			
		||||
{
 | 
			
		||||
pub struct EnumMatchVariantsIter<T: EnumType> {
 | 
			
		||||
    pub(crate) inner: EnumMatchVariantsIterImpl<T>,
 | 
			
		||||
    pub(crate) variant_index: std::ops::Range<usize>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: EnumType> Iterator for EnumMatchVariantsIter<T>
 | 
			
		||||
where
 | 
			
		||||
    T::Value: EnumValue<Type = T>,
 | 
			
		||||
{
 | 
			
		||||
impl<T: EnumType> Iterator for EnumMatchVariantsIter<T> {
 | 
			
		||||
    type Item = EnumMatchVariantAndInactiveScope<T>;
 | 
			
		||||
 | 
			
		||||
    fn next(&mut self) -> Option<Self::Item> {
 | 
			
		||||
| 
						 | 
				
			
			@ -470,21 +171,15 @@ where
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: EnumType> ExactSizeIterator for EnumMatchVariantsIter<T>
 | 
			
		||||
where
 | 
			
		||||
    T::Value: EnumValue<Type = T>,
 | 
			
		||||
{
 | 
			
		||||
impl<T: EnumType> ExactSizeIterator for EnumMatchVariantsIter<T> {
 | 
			
		||||
    fn len(&self) -> usize {
 | 
			
		||||
        self.variant_index.len()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: EnumType> FusedIterator for EnumMatchVariantsIter<T> where T::Value: EnumValue<Type = T> {}
 | 
			
		||||
impl<T: EnumType> FusedIterator for EnumMatchVariantsIter<T> {}
 | 
			
		||||
 | 
			
		||||
impl<T: EnumType> DoubleEndedIterator for EnumMatchVariantsIter<T>
 | 
			
		||||
where
 | 
			
		||||
    T::Value: EnumValue<Type = T>,
 | 
			
		||||
{
 | 
			
		||||
impl<T: EnumType> DoubleEndedIterator for EnumMatchVariantsIter<T> {
 | 
			
		||||
    fn next_back(&mut self) -> Option<Self::Item> {
 | 
			
		||||
        self.variant_index.next_back().map(|variant_index| {
 | 
			
		||||
            EnumMatchVariantAndInactiveScope(self.inner.for_variant_index(variant_index))
 | 
			
		||||
| 
						 | 
				
			
			@ -492,129 +187,55 @@ where
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Type for DynEnumType {
 | 
			
		||||
    type CanonicalType = DynEnumType;
 | 
			
		||||
    type Value = DynEnum;
 | 
			
		||||
    type CanonicalValue = DynEnum;
 | 
			
		||||
    type MaskType = UIntType<1>;
 | 
			
		||||
    type MaskValue = UInt<1>;
 | 
			
		||||
    type MatchVariant = Option<Expr<DynCanonicalValue>>;
 | 
			
		||||
    type MatchActiveScope = Scope;
 | 
			
		||||
    type MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope<Self>;
 | 
			
		||||
    type MatchVariantsIter = EnumMatchVariantsIter<Self>;
 | 
			
		||||
 | 
			
		||||
    fn match_variants<IO: BundleValue>(
 | 
			
		||||
        this: Expr<Self::Value>,
 | 
			
		||||
        module_builder: &mut ModuleBuilder<IO, NormalModule>,
 | 
			
		||||
        source_location: SourceLocation,
 | 
			
		||||
    ) -> Self::MatchVariantsIter
 | 
			
		||||
    where
 | 
			
		||||
        IO::Type: crate::bundle::BundleType<Value = IO>,
 | 
			
		||||
    {
 | 
			
		||||
        module_builder.enum_match_variants_helper(this, source_location)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn mask_type(&self) -> Self::MaskType {
 | 
			
		||||
        UIntType::new()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn canonical(&self) -> Self::CanonicalType {
 | 
			
		||||
        *self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn source_location(&self) -> SourceLocation {
 | 
			
		||||
        SourceLocation::builtin()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn type_enum(&self) -> TypeEnum {
 | 
			
		||||
        TypeEnum::EnumType(*self)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn from_canonical_type(t: Self::CanonicalType) -> Self {
 | 
			
		||||
        t
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn as_dyn_canonical_type_impl(this: &Self) -> Option<&dyn DynCanonicalType> {
 | 
			
		||||
        Some(this)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Connect<Self> for DynEnumType {}
 | 
			
		||||
 | 
			
		||||
pub struct NoBuilder;
 | 
			
		||||
 | 
			
		||||
impl EnumType for DynEnumType {
 | 
			
		||||
    type Builder = NoBuilder;
 | 
			
		||||
 | 
			
		||||
impl EnumType for Enum {
 | 
			
		||||
    fn match_activate_scope(
 | 
			
		||||
        v: Self::MatchVariantAndInactiveScope,
 | 
			
		||||
    ) -> (Self::MatchVariant, Self::MatchActiveScope) {
 | 
			
		||||
        let (expr, scope) = v.0.activate();
 | 
			
		||||
        (expr.variant_type().ty.map(|_| expr.to_expr()), scope)
 | 
			
		||||
        (expr.variant_type().map(|_| expr.to_expr()), scope)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn builder() -> Self::Builder {
 | 
			
		||||
        NoBuilder
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn variants(&self) -> Interned<[VariantType<Interned<dyn DynCanonicalType>>]> {
 | 
			
		||||
    fn variants(&self) -> Interned<[EnumVariant]> {
 | 
			
		||||
        self.0.variants
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    fn variants_hint() -> VariantsHint {
 | 
			
		||||
        VariantsHint {
 | 
			
		||||
            known_variants: [][..].intern(),
 | 
			
		||||
            more_variants: true,
 | 
			
		||||
        }
 | 
			
		||||
impl Type for Enum {
 | 
			
		||||
    type MaskType = Bool;
 | 
			
		||||
    type MatchVariant = Option<Expr<CanonicalType>>;
 | 
			
		||||
    type MatchActiveScope = Scope;
 | 
			
		||||
    type MatchVariantAndInactiveScope = EnumMatchVariantAndInactiveScope<Self>;
 | 
			
		||||
    type MatchVariantsIter = EnumMatchVariantsIter<Self>;
 | 
			
		||||
 | 
			
		||||
    fn match_variants(
 | 
			
		||||
        this: Expr<Self>,
 | 
			
		||||
        module_builder: &mut ModuleBuilder<NormalModule>,
 | 
			
		||||
        source_location: crate::source_location::SourceLocation,
 | 
			
		||||
    ) -> Self::MatchVariantsIter {
 | 
			
		||||
        module_builder.enum_match_variants_helper(this, source_location)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn mask_type(&self) -> Self::MaskType {
 | 
			
		||||
        Bool
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn canonical(&self) -> CanonicalType {
 | 
			
		||||
        CanonicalType::Enum(*self)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[track_caller]
 | 
			
		||||
    fn from_canonical(canonical_type: CanonicalType) -> Self {
 | 
			
		||||
        let CanonicalType::Enum(retval) = canonical_type else {
 | 
			
		||||
            panic!("expected enum");
 | 
			
		||||
        };
 | 
			
		||||
        retval
 | 
			
		||||
    }
 | 
			
		||||
    fn source_location() -> SourceLocation {
 | 
			
		||||
        SourceLocation::builtin()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl CanonicalType for DynEnumType {
 | 
			
		||||
    const CANONICAL_TYPE_KIND: CanonicalTypeKind = CanonicalTypeKind::EnumType;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ToExpr for DynEnum {
 | 
			
		||||
    type Type = DynEnumType;
 | 
			
		||||
 | 
			
		||||
    fn ty(&self) -> Self::Type {
 | 
			
		||||
        self.ty
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn to_expr(&self) -> Expr<<Self::Type as Type>::Value> {
 | 
			
		||||
        Expr::from_value(self)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Value for DynEnum {
 | 
			
		||||
    fn to_canonical(&self) -> <Self::Type as Type>::CanonicalValue {
 | 
			
		||||
        self.clone()
 | 
			
		||||
    }
 | 
			
		||||
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
			
		||||
        this.ty
 | 
			
		||||
            .variant_to_bits(this.variant_index, this.variant_value.as_ref())
 | 
			
		||||
            .unwrap()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl EnumValue for DynEnum {}
 | 
			
		||||
 | 
			
		||||
impl CanonicalValue for DynEnum {
 | 
			
		||||
    fn value_enum_impl(this: &Self) -> ValueEnum {
 | 
			
		||||
        ValueEnum::Enum(this.clone())
 | 
			
		||||
    }
 | 
			
		||||
    fn to_bits_impl(this: &Self) -> Interned<BitSlice> {
 | 
			
		||||
        this.ty
 | 
			
		||||
            .variant_to_bits(this.variant_index, this.variant_value.as_ref())
 | 
			
		||||
            .unwrap()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mod impl_option {
 | 
			
		||||
    #[allow(dead_code)]
 | 
			
		||||
    #[derive(crate::ty::Value)]
 | 
			
		||||
    #[hdl(target(std::option::Option), connect_inexact, outline_generated)]
 | 
			
		||||
    pub enum Option<T> {
 | 
			
		||||
        None,
 | 
			
		||||
        Some(T),
 | 
			
		||||
    }
 | 
			
		||||
#[hdl]
 | 
			
		||||
pub enum HdlOption<T: Type> {
 | 
			
		||||
    None,
 | 
			
		||||
    Some(T),
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -12,7 +12,6 @@ extern crate self as fayalite;
 | 
			
		|||
pub use std as __std;
 | 
			
		||||
 | 
			
		||||
#[doc(inline)]
 | 
			
		||||
#[doc(alias = "hdl")]
 | 
			
		||||
/// The `#[hdl_module]` attribute is applied to a Rust function so that that function creates
 | 
			
		||||
/// a [`Module`][`::fayalite::module::Module`] when called.
 | 
			
		||||
/// In the function body it will implicitly create a
 | 
			
		||||
| 
						 | 
				
			
			@ -21,25 +20,86 @@ pub use std as __std;
 | 
			
		|||
/// See [Fayalite Modules][crate::_docs::modules]
 | 
			
		||||
pub use fayalite_proc_macros::hdl_module;
 | 
			
		||||
 | 
			
		||||
#[doc(inline)]
 | 
			
		||||
pub use fayalite_proc_macros::hdl;
 | 
			
		||||
 | 
			
		||||
/// struct used as a placeholder when applying defaults
 | 
			
		||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
 | 
			
		||||
pub struct __;
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "unstable-doc")]
 | 
			
		||||
pub mod _docs;
 | 
			
		||||
 | 
			
		||||
pub mod annotations;
 | 
			
		||||
// FIXME: finish
 | 
			
		||||
//pub mod annotations;
 | 
			
		||||
pub mod array;
 | 
			
		||||
pub mod bundle;
 | 
			
		||||
pub mod cli;
 | 
			
		||||
pub mod clock;
 | 
			
		||||
//pub mod cli;
 | 
			
		||||
//pub mod clock;
 | 
			
		||||
pub mod enum_;
 | 
			
		||||
pub mod expr;
 | 
			
		||||
pub mod firrtl;
 | 
			
		||||
//pub mod firrtl;
 | 
			
		||||
pub mod int;
 | 
			
		||||
pub mod intern;
 | 
			
		||||
pub mod memory;
 | 
			
		||||
pub mod module;
 | 
			
		||||
pub mod reg;
 | 
			
		||||
pub mod reset;
 | 
			
		||||
//pub mod memory;
 | 
			
		||||
//pub mod module;
 | 
			
		||||
//pub mod reg;
 | 
			
		||||
//pub mod reset;
 | 
			
		||||
pub mod source_location;
 | 
			
		||||
pub mod ty;
 | 
			
		||||
pub mod util;
 | 
			
		||||
pub mod valueless;
 | 
			
		||||
pub mod wire;
 | 
			
		||||
//pub mod valueless;
 | 
			
		||||
//pub mod wire;
 | 
			
		||||
 | 
			
		||||
// FIXME: switch to real module mod
 | 
			
		||||
pub mod module {
 | 
			
		||||
    use crate::{
 | 
			
		||||
        enum_::{EnumMatchVariantsIter, EnumType},
 | 
			
		||||
        expr::{ops::VariantAccess, Expr},
 | 
			
		||||
        intern::Interned,
 | 
			
		||||
        source_location::SourceLocation,
 | 
			
		||||
    };
 | 
			
		||||
    use std::marker::PhantomData;
 | 
			
		||||
 | 
			
		||||
    pub struct NormalModule;
 | 
			
		||||
 | 
			
		||||
    pub struct ModuleBuilder<ModuleKind>(PhantomData<ModuleKind>);
 | 
			
		||||
 | 
			
		||||
    impl ModuleBuilder<NormalModule> {
 | 
			
		||||
        pub fn enum_match_variants_helper<Enum: EnumType>(
 | 
			
		||||
            &mut self,
 | 
			
		||||
            _base: Expr<Enum>,
 | 
			
		||||
            _source_location: SourceLocation,
 | 
			
		||||
        ) -> EnumMatchVariantsIter<Enum> {
 | 
			
		||||
            todo!()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub struct Scope(());
 | 
			
		||||
 | 
			
		||||
    pub(crate) struct EnumMatchVariantAndInactiveScopeImpl<T: EnumType> {
 | 
			
		||||
        variant_access: Interned<VariantAccess>,
 | 
			
		||||
        _phantom: PhantomData<T>,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl<T: EnumType> EnumMatchVariantAndInactiveScopeImpl<T> {
 | 
			
		||||
        pub(crate) fn activate(self) -> (Interned<VariantAccess>, Scope) {
 | 
			
		||||
            (self.variant_access, Scope(()))
 | 
			
		||||
        }
 | 
			
		||||
        pub(crate) fn variant_access(&self) -> Interned<VariantAccess> {
 | 
			
		||||
            self.variant_access
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[derive(Clone)]
 | 
			
		||||
    pub(crate) struct EnumMatchVariantsIterImpl<T>(PhantomData<T>);
 | 
			
		||||
 | 
			
		||||
    impl<T: EnumType> EnumMatchVariantsIterImpl<T> {
 | 
			
		||||
        pub(crate) fn for_variant_index(
 | 
			
		||||
            &self,
 | 
			
		||||
            _variant_index: usize,
 | 
			
		||||
        ) -> EnumMatchVariantAndInactiveScopeImpl<T> {
 | 
			
		||||
            todo!()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -3,10 +3,13 @@
 | 
			
		|||
 | 
			
		||||
mod const_bool;
 | 
			
		||||
mod const_cmp;
 | 
			
		||||
mod const_usize;
 | 
			
		||||
mod misc;
 | 
			
		||||
 | 
			
		||||
#[doc(inline)]
 | 
			
		||||
pub use const_bool::{ConstBool, ConstBoolDispatch, ConstBoolDispatchTag, GenericConstBool};
 | 
			
		||||
#[doc(inline)]
 | 
			
		||||
pub use const_usize::{ConstUsize, GenericConstUsize};
 | 
			
		||||
 | 
			
		||||
#[doc(inline)]
 | 
			
		||||
pub use const_cmp::{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										29
									
								
								crates/fayalite/src/util/const_usize.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								crates/fayalite/src/util/const_usize.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,29 @@
 | 
			
		|||
// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
			
		||||
// See Notices.txt for copyright information
 | 
			
		||||
use std::{fmt::Debug, hash::Hash};
 | 
			
		||||
 | 
			
		||||
mod sealed {
 | 
			
		||||
    pub trait Sealed {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// the only implementation is `ConstUsize<Self::VALUE>`
 | 
			
		||||
pub trait GenericConstUsize:
 | 
			
		||||
    sealed::Sealed + Copy + Ord + Hash + Default + Debug + 'static + Send + Sync
 | 
			
		||||
{
 | 
			
		||||
    const VALUE: usize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
 | 
			
		||||
pub struct ConstUsize<const VALUE: usize>;
 | 
			
		||||
 | 
			
		||||
impl<const VALUE: usize> Debug for ConstUsize<VALUE> {
 | 
			
		||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
			
		||||
        f.debug_tuple("ConstUsize").field(&Self::VALUE).finish()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<const VALUE: usize> sealed::Sealed for ConstUsize<VALUE> {}
 | 
			
		||||
 | 
			
		||||
impl<const VALUE: usize> GenericConstUsize for ConstUsize<VALUE> {
 | 
			
		||||
    const VALUE: usize = VALUE;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,32 +1,26 @@
 | 
			
		|||
// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
			
		||||
// See Notices.txt for copyright information
 | 
			
		||||
use fayalite::{
 | 
			
		||||
    int::UInt,
 | 
			
		||||
    ty::{StaticValue, Value},
 | 
			
		||||
    array::ArrayType,
 | 
			
		||||
    hdl,
 | 
			
		||||
    int::{IntType, Size, UInt},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Value, Clone, Hash, PartialEq, Eq, Debug)]
 | 
			
		||||
#[hdl(outline_generated)]
 | 
			
		||||
pub struct S<T> {
 | 
			
		||||
pub struct S<T: IntType, Len: Size> {
 | 
			
		||||
    pub a: T,
 | 
			
		||||
    b: UInt<3>,
 | 
			
		||||
    pub(crate) c: ArrayType<UInt<1>, Len>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Value, Clone, Hash, PartialEq, Eq, Debug)]
 | 
			
		||||
#[hdl(outline_generated)]
 | 
			
		||||
pub enum E<T> {
 | 
			
		||||
    A,
 | 
			
		||||
    B {},
 | 
			
		||||
    C(),
 | 
			
		||||
    D(UInt<3>),
 | 
			
		||||
    E { a: UInt<3> },
 | 
			
		||||
    F(UInt<3>, UInt<3>),
 | 
			
		||||
    G(T),
 | 
			
		||||
    H(T, UInt<1>),
 | 
			
		||||
    B(UInt<3>),
 | 
			
		||||
    C(T),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Value, Clone, Hash, PartialEq, Eq, Debug)]
 | 
			
		||||
#[hdl(outline_generated, static, where(T: StaticValue))]
 | 
			
		||||
#[hdl(outline_generated)]
 | 
			
		||||
pub struct S2<T> {
 | 
			
		||||
    pub v: E<T>,
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue