add PhantomConst accessor type aliases #44
					 10 changed files with 742 additions and 59 deletions
				
			
		| 
						 | 
				
			
			@ -12,7 +12,7 @@ Fayalite is a library for designing digital hardware -- a hardware description l
 | 
			
		|||
 | 
			
		||||
[Blinky example]: crates/fayalite/examples/blinky.rs
 | 
			
		||||
 | 
			
		||||
This uses the container image containing all the external programs and files that Fayalite needs to build for FPGAs, the sources for the container image are in https://git.libre-chip.org/libre-chip/fayalite-deps
 | 
			
		||||
This uses the container image containing all the external programs and files that Fayalite needs to build for FPGAs, the sources for the container image are in <https://git.libre-chip.org/libre-chip/fayalite-deps>
 | 
			
		||||
 | 
			
		||||
Steps:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -87,7 +87,11 @@ impl ParsedBundle {
 | 
			
		|||
            no_static: _,
 | 
			
		||||
            no_runtime_generics: _,
 | 
			
		||||
            cmp_eq: _,
 | 
			
		||||
            ref get,
 | 
			
		||||
        } = options.body;
 | 
			
		||||
        if let Some((get, ..)) = get {
 | 
			
		||||
            errors.error(get, "#[hdl(get(...))] is not allowed on structs");
 | 
			
		||||
        }
 | 
			
		||||
        let mut fields = match fields {
 | 
			
		||||
            syn::Fields::Named(fields) => fields,
 | 
			
		||||
            syn::Fields::Unnamed(fields) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -445,6 +449,7 @@ impl ToTokens for ParsedBundle {
 | 
			
		|||
            no_static,
 | 
			
		||||
            no_runtime_generics,
 | 
			
		||||
            cmp_eq,
 | 
			
		||||
            get: _,
 | 
			
		||||
        } = &options.body;
 | 
			
		||||
        let target = get_target(target, ident);
 | 
			
		||||
        let mut item_attrs = attrs.clone();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -159,10 +159,14 @@ impl ParsedEnum {
 | 
			
		|||
            no_static: _,
 | 
			
		||||
            no_runtime_generics: _,
 | 
			
		||||
            cmp_eq,
 | 
			
		||||
            ref get,
 | 
			
		||||
        } = options.body;
 | 
			
		||||
        if let Some((cmp_eq,)) = cmp_eq {
 | 
			
		||||
            errors.error(cmp_eq, "#[hdl(cmp_eq)] is not yet implemented for enums");
 | 
			
		||||
        }
 | 
			
		||||
        if let Some((get, ..)) = get {
 | 
			
		||||
            errors.error(get, "#[hdl(get(...))] is not allowed on enums");
 | 
			
		||||
        }
 | 
			
		||||
        attrs.retain(|attr| {
 | 
			
		||||
            if attr.path().is_ident("repr") {
 | 
			
		||||
                errors.error(attr, "#[repr] is not supported on #[hdl] enums");
 | 
			
		||||
| 
						 | 
				
			
			@ -225,6 +229,7 @@ impl ToTokens for ParsedEnum {
 | 
			
		|||
            no_static,
 | 
			
		||||
            no_runtime_generics,
 | 
			
		||||
            cmp_eq: _, // TODO: implement cmp_eq for enums
 | 
			
		||||
            get: _,
 | 
			
		||||
        } = &options.body;
 | 
			
		||||
        let target = get_target(target, ident);
 | 
			
		||||
        let mut struct_attrs = attrs.clone();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,28 +4,353 @@ use crate::{
 | 
			
		|||
    Errors, HdlAttr,
 | 
			
		||||
    hdl_type_common::{
 | 
			
		||||
        ItemOptions, MakeHdlTypeExpr, MaybeParsed, ParsedGenerics, ParsedType, TypesParser,
 | 
			
		||||
        get_target,
 | 
			
		||||
        WrappedInConst, common_derives, get_target, known_items,
 | 
			
		||||
    },
 | 
			
		||||
    kw,
 | 
			
		||||
};
 | 
			
		||||
use proc_macro2::TokenStream;
 | 
			
		||||
use quote::ToTokens;
 | 
			
		||||
use syn::{Attribute, Generics, Ident, ItemType, Token, Type, Visibility, parse_quote_spanned};
 | 
			
		||||
use quote::{ToTokens, format_ident, quote_spanned};
 | 
			
		||||
use syn::{
 | 
			
		||||
    AngleBracketedGenericArguments, Attribute, Expr, Fields, GenericArgument, GenericParam,
 | 
			
		||||
    Generics, Ident, ItemStruct, ItemType, Path, PathArguments, Token, TraitBound,
 | 
			
		||||
    TraitBoundModifier, Type, TypeGroup, TypeParam, TypeParamBound, TypeParen, Visibility,
 | 
			
		||||
    parse_quote_spanned, punctuated::Pair, token::Paren,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub(crate) struct ParsedTypeAlias {
 | 
			
		||||
    pub(crate) attrs: Vec<Attribute>,
 | 
			
		||||
    pub(crate) options: HdlAttr<ItemOptions, kw::hdl>,
 | 
			
		||||
    pub(crate) vis: Visibility,
 | 
			
		||||
    pub(crate) type_token: Token![type],
 | 
			
		||||
    pub(crate) ident: Ident,
 | 
			
		||||
    pub(crate) generics: MaybeParsed<ParsedGenerics, Generics>,
 | 
			
		||||
    pub(crate) eq_token: Token![=],
 | 
			
		||||
    pub(crate) ty: MaybeParsed<ParsedType, Type>,
 | 
			
		||||
    pub(crate) semi_token: Token![;],
 | 
			
		||||
pub(crate) struct PhantomConstGetBound {
 | 
			
		||||
    pub(crate) phantom_const_get: known_items::PhantomConstGet,
 | 
			
		||||
    pub(crate) colon2_token: Option<Token![::]>,
 | 
			
		||||
    pub(crate) lt_token: Token![<],
 | 
			
		||||
    pub(crate) ty: Type,
 | 
			
		||||
    pub(crate) comma_token: Option<Token![,]>,
 | 
			
		||||
    pub(crate) gt_token: Token![>],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<PhantomConstGetBound> for Path {
 | 
			
		||||
    fn from(value: PhantomConstGetBound) -> Self {
 | 
			
		||||
        let PhantomConstGetBound {
 | 
			
		||||
            phantom_const_get,
 | 
			
		||||
            colon2_token,
 | 
			
		||||
            lt_token,
 | 
			
		||||
            ty,
 | 
			
		||||
            comma_token,
 | 
			
		||||
            gt_token,
 | 
			
		||||
        } = value;
 | 
			
		||||
        let mut path = phantom_const_get.path;
 | 
			
		||||
        path.segments.last_mut().expect("known to exist").arguments =
 | 
			
		||||
            PathArguments::AngleBracketed(AngleBracketedGenericArguments {
 | 
			
		||||
                colon2_token,
 | 
			
		||||
                lt_token,
 | 
			
		||||
                args: FromIterator::from_iter([Pair::new(GenericArgument::Type(ty), comma_token)]),
 | 
			
		||||
                gt_token,
 | 
			
		||||
            });
 | 
			
		||||
        path
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<PhantomConstGetBound> for TraitBound {
 | 
			
		||||
    fn from(value: PhantomConstGetBound) -> Self {
 | 
			
		||||
        let path = Path::from(value);
 | 
			
		||||
        TraitBound {
 | 
			
		||||
            paren_token: None,
 | 
			
		||||
            modifier: TraitBoundModifier::None,
 | 
			
		||||
            lifetimes: None,
 | 
			
		||||
            path,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<PhantomConstGetBound> for TypeParamBound {
 | 
			
		||||
    fn from(value: PhantomConstGetBound) -> Self {
 | 
			
		||||
        TraitBound::from(value).into()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PhantomConstGetBound {
 | 
			
		||||
    fn parse_opt(bound: TypeParamBound) -> Option<Self> {
 | 
			
		||||
        let TypeParamBound::Trait(TraitBound {
 | 
			
		||||
            paren_token: None,
 | 
			
		||||
            modifier: TraitBoundModifier::None,
 | 
			
		||||
            lifetimes: None,
 | 
			
		||||
            path,
 | 
			
		||||
        }) = bound
 | 
			
		||||
        else {
 | 
			
		||||
            return None;
 | 
			
		||||
        };
 | 
			
		||||
        let Ok((
 | 
			
		||||
            phantom_const_get,
 | 
			
		||||
            PathArguments::AngleBracketed(AngleBracketedGenericArguments {
 | 
			
		||||
                colon2_token,
 | 
			
		||||
                lt_token,
 | 
			
		||||
                args,
 | 
			
		||||
                gt_token,
 | 
			
		||||
            }),
 | 
			
		||||
        )) = known_items::PhantomConstGet::parse_path_with_arguments(path)
 | 
			
		||||
        else {
 | 
			
		||||
            return None;
 | 
			
		||||
        };
 | 
			
		||||
        let mut args = args.into_pairs();
 | 
			
		||||
        let (GenericArgument::Type(ty), comma_token) = args.next()?.into_tuple() else {
 | 
			
		||||
            return None;
 | 
			
		||||
        };
 | 
			
		||||
        let None = args.next() else {
 | 
			
		||||
            return None;
 | 
			
		||||
        };
 | 
			
		||||
        Some(Self {
 | 
			
		||||
            phantom_const_get,
 | 
			
		||||
            colon2_token,
 | 
			
		||||
            lt_token,
 | 
			
		||||
            ty,
 | 
			
		||||
            comma_token,
 | 
			
		||||
            gt_token,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub(crate) struct PhantomConstAccessorTypeParam {
 | 
			
		||||
    attrs: Vec<Attribute>,
 | 
			
		||||
    ident: Ident,
 | 
			
		||||
    colon_token: Token![:],
 | 
			
		||||
    phantom_const_get_bound: PhantomConstGetBound,
 | 
			
		||||
    plus_token: Option<Token![+]>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<PhantomConstAccessorTypeParam> for TypeParam {
 | 
			
		||||
    fn from(value: PhantomConstAccessorTypeParam) -> Self {
 | 
			
		||||
        let PhantomConstAccessorTypeParam {
 | 
			
		||||
            attrs,
 | 
			
		||||
            ident,
 | 
			
		||||
            colon_token,
 | 
			
		||||
            phantom_const_get_bound,
 | 
			
		||||
            plus_token,
 | 
			
		||||
        } = value;
 | 
			
		||||
        TypeParam {
 | 
			
		||||
            attrs,
 | 
			
		||||
            ident,
 | 
			
		||||
            colon_token: Some(colon_token),
 | 
			
		||||
            bounds: FromIterator::from_iter([Pair::new(
 | 
			
		||||
                phantom_const_get_bound.into(),
 | 
			
		||||
                plus_token,
 | 
			
		||||
            )]),
 | 
			
		||||
            eq_token: None,
 | 
			
		||||
            default: None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<PhantomConstAccessorTypeParam> for GenericParam {
 | 
			
		||||
    fn from(value: PhantomConstAccessorTypeParam) -> Self {
 | 
			
		||||
        TypeParam::from(value).into()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PhantomConstAccessorTypeParam {
 | 
			
		||||
    fn parse_opt(generic_param: GenericParam) -> Option<Self> {
 | 
			
		||||
        let GenericParam::Type(TypeParam {
 | 
			
		||||
            attrs,
 | 
			
		||||
            ident,
 | 
			
		||||
            colon_token,
 | 
			
		||||
            bounds,
 | 
			
		||||
            eq_token: None,
 | 
			
		||||
            default: None,
 | 
			
		||||
        }) = generic_param
 | 
			
		||||
        else {
 | 
			
		||||
            return None;
 | 
			
		||||
        };
 | 
			
		||||
        let colon_token = colon_token.unwrap_or(Token));
 | 
			
		||||
        let mut bounds = bounds.into_pairs();
 | 
			
		||||
        let (bound, plus_token) = bounds.next()?.into_tuple();
 | 
			
		||||
        let phantom_const_get_bound = PhantomConstGetBound::parse_opt(bound)?;
 | 
			
		||||
        let None = bounds.next() else {
 | 
			
		||||
            return None;
 | 
			
		||||
        };
 | 
			
		||||
        Some(Self {
 | 
			
		||||
            attrs,
 | 
			
		||||
            ident,
 | 
			
		||||
            colon_token,
 | 
			
		||||
            phantom_const_get_bound,
 | 
			
		||||
            plus_token,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub(crate) struct PhantomConstAccessorGenerics {
 | 
			
		||||
    lt_token: Token![<],
 | 
			
		||||
    type_param: PhantomConstAccessorTypeParam,
 | 
			
		||||
    comma_token: Option<Token![,]>,
 | 
			
		||||
    gt_token: Token![>],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<PhantomConstAccessorGenerics> for Generics {
 | 
			
		||||
    fn from(value: PhantomConstAccessorGenerics) -> Self {
 | 
			
		||||
        let PhantomConstAccessorGenerics {
 | 
			
		||||
            lt_token,
 | 
			
		||||
            type_param,
 | 
			
		||||
            comma_token,
 | 
			
		||||
            gt_token,
 | 
			
		||||
        } = value;
 | 
			
		||||
        Generics {
 | 
			
		||||
            lt_token: Some(lt_token),
 | 
			
		||||
            params: FromIterator::from_iter([Pair::new(type_param.into(), comma_token)]),
 | 
			
		||||
            gt_token: Some(gt_token),
 | 
			
		||||
            where_clause: None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> From<&'a PhantomConstAccessorGenerics> for Generics {
 | 
			
		||||
    fn from(value: &'a PhantomConstAccessorGenerics) -> Self {
 | 
			
		||||
        value.clone().into()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PhantomConstAccessorGenerics {
 | 
			
		||||
    fn parse_opt(generics: Generics) -> Option<Self> {
 | 
			
		||||
        let Generics {
 | 
			
		||||
            lt_token,
 | 
			
		||||
            params,
 | 
			
		||||
            gt_token,
 | 
			
		||||
            where_clause: None,
 | 
			
		||||
        } = generics
 | 
			
		||||
        else {
 | 
			
		||||
            return None;
 | 
			
		||||
        };
 | 
			
		||||
        let mut params = params.into_pairs();
 | 
			
		||||
        let (generic_param, comma_token) = params.next()?.into_tuple();
 | 
			
		||||
        let type_param = PhantomConstAccessorTypeParam::parse_opt(generic_param)?;
 | 
			
		||||
        let span = type_param.ident.span();
 | 
			
		||||
        let lt_token = lt_token.unwrap_or(Token);
 | 
			
		||||
        let gt_token = gt_token.unwrap_or(Token);
 | 
			
		||||
        let None = params.next() else {
 | 
			
		||||
            return None;
 | 
			
		||||
        };
 | 
			
		||||
        Some(Self {
 | 
			
		||||
            lt_token,
 | 
			
		||||
            type_param,
 | 
			
		||||
            comma_token,
 | 
			
		||||
            gt_token,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub(crate) enum ParsedTypeAlias {
 | 
			
		||||
    TypeAlias {
 | 
			
		||||
        attrs: Vec<Attribute>,
 | 
			
		||||
        options: HdlAttr<ItemOptions, kw::hdl>,
 | 
			
		||||
        vis: Visibility,
 | 
			
		||||
        type_token: Token![type],
 | 
			
		||||
        ident: Ident,
 | 
			
		||||
        generics: MaybeParsed<ParsedGenerics, Generics>,
 | 
			
		||||
        eq_token: Token![=],
 | 
			
		||||
        ty: MaybeParsed<ParsedType, Type>,
 | 
			
		||||
        semi_token: Token![;],
 | 
			
		||||
    },
 | 
			
		||||
    PhantomConstAccessor {
 | 
			
		||||
        attrs: Vec<Attribute>,
 | 
			
		||||
        options: HdlAttr<ItemOptions, kw::hdl>,
 | 
			
		||||
        get: (kw::get, Paren, Expr),
 | 
			
		||||
        vis: Visibility,
 | 
			
		||||
        type_token: Token![type],
 | 
			
		||||
        ident: Ident,
 | 
			
		||||
        generics: PhantomConstAccessorGenerics,
 | 
			
		||||
        eq_token: Token![=],
 | 
			
		||||
        ty: Type,
 | 
			
		||||
        ty_is_dyn_size: Option<known_items::DynSize>,
 | 
			
		||||
        semi_token: Token![;],
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ParsedTypeAlias {
 | 
			
		||||
    fn ty_is_dyn_size(ty: &Type) -> Option<known_items::DynSize> {
 | 
			
		||||
        match ty {
 | 
			
		||||
            Type::Group(TypeGroup {
 | 
			
		||||
                group_token: _,
 | 
			
		||||
                elem,
 | 
			
		||||
            }) => Self::ty_is_dyn_size(elem),
 | 
			
		||||
            Type::Paren(TypeParen {
 | 
			
		||||
                paren_token: _,
 | 
			
		||||
                elem,
 | 
			
		||||
            }) => Self::ty_is_dyn_size(elem),
 | 
			
		||||
            Type::Path(syn::TypePath { qself: None, path }) => {
 | 
			
		||||
                known_items::DynSize::parse_path(path.clone()).ok()
 | 
			
		||||
            }
 | 
			
		||||
            _ => None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    fn parse_phantom_const_accessor(
 | 
			
		||||
        item: ItemType,
 | 
			
		||||
        mut errors: Errors,
 | 
			
		||||
        options: HdlAttr<ItemOptions, kw::hdl>,
 | 
			
		||||
        get: (kw::get, Paren, Expr),
 | 
			
		||||
    ) -> syn::Result<Self> {
 | 
			
		||||
        let ItemType {
 | 
			
		||||
            attrs,
 | 
			
		||||
            vis,
 | 
			
		||||
            type_token,
 | 
			
		||||
            ident,
 | 
			
		||||
            generics,
 | 
			
		||||
            eq_token,
 | 
			
		||||
            ty,
 | 
			
		||||
            semi_token,
 | 
			
		||||
        } = item;
 | 
			
		||||
        let ItemOptions {
 | 
			
		||||
            outline_generated: _,
 | 
			
		||||
            ref target,
 | 
			
		||||
            custom_bounds,
 | 
			
		||||
            no_static,
 | 
			
		||||
            no_runtime_generics,
 | 
			
		||||
            cmp_eq,
 | 
			
		||||
            get: _,
 | 
			
		||||
        } = options.body;
 | 
			
		||||
        if let Some((no_static,)) = no_static {
 | 
			
		||||
            errors.error(no_static, "no_static is not valid on type aliases");
 | 
			
		||||
        }
 | 
			
		||||
        if let Some((target, ..)) = target {
 | 
			
		||||
            errors.error(
 | 
			
		||||
                target,
 | 
			
		||||
                "target is not implemented on PhantomConstGet type aliases",
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        if let Some((no_runtime_generics,)) = no_runtime_generics {
 | 
			
		||||
            errors.error(
 | 
			
		||||
                no_runtime_generics,
 | 
			
		||||
                "no_runtime_generics is not implemented on PhantomConstGet type aliases",
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        if let Some((cmp_eq,)) = cmp_eq {
 | 
			
		||||
            errors.error(cmp_eq, "cmp_eq is not valid on type aliases");
 | 
			
		||||
        }
 | 
			
		||||
        if let Some((custom_bounds,)) = custom_bounds {
 | 
			
		||||
            errors.error(
 | 
			
		||||
                custom_bounds,
 | 
			
		||||
                "custom_bounds is not implemented on PhantomConstGet type aliases",
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        let Some(generics) = PhantomConstAccessorGenerics::parse_opt(generics) else {
 | 
			
		||||
            errors.error(ident, "#[hdl(get(...))] type alias must be of the form:\ntype MyTypeGetter<P: PhantomConstGet<MyType>> = RetType;");
 | 
			
		||||
            errors.finish()?;
 | 
			
		||||
            unreachable!();
 | 
			
		||||
        };
 | 
			
		||||
        errors.finish()?;
 | 
			
		||||
        let ty_is_dyn_size = Self::ty_is_dyn_size(&ty);
 | 
			
		||||
        Ok(Self::PhantomConstAccessor {
 | 
			
		||||
            attrs,
 | 
			
		||||
            options,
 | 
			
		||||
            get,
 | 
			
		||||
            vis,
 | 
			
		||||
            type_token,
 | 
			
		||||
            ident,
 | 
			
		||||
            generics,
 | 
			
		||||
            eq_token,
 | 
			
		||||
            ty: *ty,
 | 
			
		||||
            ty_is_dyn_size,
 | 
			
		||||
            semi_token,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
    fn parse(item: ItemType) -> syn::Result<Self> {
 | 
			
		||||
        let ItemType {
 | 
			
		||||
            mut attrs,
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +376,25 @@ impl ParsedTypeAlias {
 | 
			
		|||
            no_static,
 | 
			
		||||
            no_runtime_generics: _,
 | 
			
		||||
            cmp_eq,
 | 
			
		||||
            ref mut get,
 | 
			
		||||
        } = options.body;
 | 
			
		||||
        if let Some(get) = get.take() {
 | 
			
		||||
            return Self::parse_phantom_const_accessor(
 | 
			
		||||
                ItemType {
 | 
			
		||||
                    attrs,
 | 
			
		||||
                    vis,
 | 
			
		||||
                    type_token,
 | 
			
		||||
                    ident,
 | 
			
		||||
                    generics,
 | 
			
		||||
                    eq_token,
 | 
			
		||||
                    ty,
 | 
			
		||||
                    semi_token,
 | 
			
		||||
                },
 | 
			
		||||
                errors,
 | 
			
		||||
                options,
 | 
			
		||||
                get,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
        if let Some((no_static,)) = no_static {
 | 
			
		||||
            errors.error(no_static, "no_static is not valid on type aliases");
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +410,7 @@ impl ParsedTypeAlias {
 | 
			
		|||
        };
 | 
			
		||||
        let ty = TypesParser::maybe_run(generics.as_ref(), *ty, &mut errors);
 | 
			
		||||
        errors.finish()?;
 | 
			
		||||
        Ok(Self {
 | 
			
		||||
        Ok(Self::TypeAlias {
 | 
			
		||||
            attrs,
 | 
			
		||||
            options,
 | 
			
		||||
            vis,
 | 
			
		||||
| 
						 | 
				
			
			@ -83,54 +426,155 @@ impl ParsedTypeAlias {
 | 
			
		|||
 | 
			
		||||
impl ToTokens for ParsedTypeAlias {
 | 
			
		||||
    fn to_tokens(&self, tokens: &mut TokenStream) {
 | 
			
		||||
        let Self {
 | 
			
		||||
            attrs,
 | 
			
		||||
            options,
 | 
			
		||||
            vis,
 | 
			
		||||
            type_token,
 | 
			
		||||
            ident,
 | 
			
		||||
            generics,
 | 
			
		||||
            eq_token,
 | 
			
		||||
            ty,
 | 
			
		||||
            semi_token,
 | 
			
		||||
        } = self;
 | 
			
		||||
        let ItemOptions {
 | 
			
		||||
            outline_generated: _,
 | 
			
		||||
            target,
 | 
			
		||||
            custom_bounds: _,
 | 
			
		||||
            no_static: _,
 | 
			
		||||
            no_runtime_generics,
 | 
			
		||||
            cmp_eq: _,
 | 
			
		||||
        } = &options.body;
 | 
			
		||||
        let target = get_target(target, ident);
 | 
			
		||||
        let mut type_attrs = attrs.clone();
 | 
			
		||||
        type_attrs.push(parse_quote_spanned! {ident.span()=>
 | 
			
		||||
            #[allow(type_alias_bounds)]
 | 
			
		||||
        });
 | 
			
		||||
        ItemType {
 | 
			
		||||
            attrs: type_attrs,
 | 
			
		||||
            vis: vis.clone(),
 | 
			
		||||
            type_token: *type_token,
 | 
			
		||||
            ident: ident.clone(),
 | 
			
		||||
            generics: generics.into(),
 | 
			
		||||
            eq_token: *eq_token,
 | 
			
		||||
            ty: Box::new(ty.clone().into()),
 | 
			
		||||
            semi_token: *semi_token,
 | 
			
		||||
        }
 | 
			
		||||
        .to_tokens(tokens);
 | 
			
		||||
        if let (MaybeParsed::Parsed(generics), MaybeParsed::Parsed(ty), None) =
 | 
			
		||||
            (generics, ty, no_runtime_generics)
 | 
			
		||||
        {
 | 
			
		||||
            generics.make_runtime_generics(tokens, vis, ident, &target, |context| {
 | 
			
		||||
                ty.make_hdl_type_expr(context)
 | 
			
		||||
            })
 | 
			
		||||
        match self {
 | 
			
		||||
            Self::TypeAlias {
 | 
			
		||||
                attrs,
 | 
			
		||||
                options,
 | 
			
		||||
                vis,
 | 
			
		||||
                type_token,
 | 
			
		||||
                ident,
 | 
			
		||||
                generics,
 | 
			
		||||
                eq_token,
 | 
			
		||||
                ty,
 | 
			
		||||
                semi_token,
 | 
			
		||||
            } => {
 | 
			
		||||
                let ItemOptions {
 | 
			
		||||
                    outline_generated: _,
 | 
			
		||||
                    target,
 | 
			
		||||
                    custom_bounds: _,
 | 
			
		||||
                    no_static: _,
 | 
			
		||||
                    no_runtime_generics,
 | 
			
		||||
                    cmp_eq: _,
 | 
			
		||||
                    get: _,
 | 
			
		||||
                } = &options.body;
 | 
			
		||||
                let target = get_target(target, ident);
 | 
			
		||||
                let mut type_attrs = attrs.clone();
 | 
			
		||||
                type_attrs.push(parse_quote_spanned! {ident.span()=>
 | 
			
		||||
                    #[allow(type_alias_bounds)]
 | 
			
		||||
                });
 | 
			
		||||
                ItemType {
 | 
			
		||||
                    attrs: type_attrs,
 | 
			
		||||
                    vis: vis.clone(),
 | 
			
		||||
                    type_token: *type_token,
 | 
			
		||||
                    ident: ident.clone(),
 | 
			
		||||
                    generics: generics.into(),
 | 
			
		||||
                    eq_token: *eq_token,
 | 
			
		||||
                    ty: Box::new(ty.clone().into()),
 | 
			
		||||
                    semi_token: *semi_token,
 | 
			
		||||
                }
 | 
			
		||||
                .to_tokens(tokens);
 | 
			
		||||
                if let (MaybeParsed::Parsed(generics), MaybeParsed::Parsed(ty), None) =
 | 
			
		||||
                    (generics, ty, no_runtime_generics)
 | 
			
		||||
                {
 | 
			
		||||
                    generics.make_runtime_generics(tokens, vis, ident, &target, |context| {
 | 
			
		||||
                        ty.make_hdl_type_expr(context)
 | 
			
		||||
                    })
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            Self::PhantomConstAccessor {
 | 
			
		||||
                attrs,
 | 
			
		||||
                options,
 | 
			
		||||
                get: (_get_kw, _get_paren, get_expr),
 | 
			
		||||
                vis,
 | 
			
		||||
                type_token,
 | 
			
		||||
                ident,
 | 
			
		||||
                generics,
 | 
			
		||||
                eq_token,
 | 
			
		||||
                ty,
 | 
			
		||||
                ty_is_dyn_size,
 | 
			
		||||
                semi_token,
 | 
			
		||||
            } => {
 | 
			
		||||
                let ItemOptions {
 | 
			
		||||
                    outline_generated: _,
 | 
			
		||||
                    target: _,
 | 
			
		||||
                    custom_bounds: _,
 | 
			
		||||
                    no_static: _,
 | 
			
		||||
                    no_runtime_generics: _,
 | 
			
		||||
                    cmp_eq: _,
 | 
			
		||||
                    get: _,
 | 
			
		||||
                } = &options.body;
 | 
			
		||||
                let span = ident.span();
 | 
			
		||||
                let mut type_attrs = attrs.clone();
 | 
			
		||||
                type_attrs.push(parse_quote_spanned! {span=>
 | 
			
		||||
                    #[allow(type_alias_bounds)]
 | 
			
		||||
                });
 | 
			
		||||
                let type_param_ident = &generics.type_param.ident;
 | 
			
		||||
                let syn_generics = Generics::from(generics);
 | 
			
		||||
                ItemType {
 | 
			
		||||
                    attrs: type_attrs,
 | 
			
		||||
                    vis: vis.clone(),
 | 
			
		||||
                    type_token: *type_token,
 | 
			
		||||
                    ident: ident.clone(),
 | 
			
		||||
                    generics: syn_generics.clone(),
 | 
			
		||||
                    eq_token: *eq_token,
 | 
			
		||||
                    ty: parse_quote_spanned! {span=>
 | 
			
		||||
                        <#ty as ::fayalite::phantom_const::ReturnSelfUnchanged<#type_param_ident>>::Type
 | 
			
		||||
                    },
 | 
			
		||||
                    semi_token: *semi_token,
 | 
			
		||||
                }
 | 
			
		||||
                .to_tokens(tokens);
 | 
			
		||||
                let generics_accumulation_ident =
 | 
			
		||||
                    format_ident!("__{}__GenericsAccumulation", ident);
 | 
			
		||||
                ItemStruct {
 | 
			
		||||
                    attrs: vec![
 | 
			
		||||
                        common_derives(span),
 | 
			
		||||
                        parse_quote_spanned! {span=>
 | 
			
		||||
                            #[allow(non_camel_case_types)]
 | 
			
		||||
                        },
 | 
			
		||||
                    ],
 | 
			
		||||
                    vis: vis.clone(),
 | 
			
		||||
                    struct_token: Token,
 | 
			
		||||
                    ident: generics_accumulation_ident.clone(),
 | 
			
		||||
                    generics: Generics::default(),
 | 
			
		||||
                    fields: Fields::Unnamed(parse_quote_spanned! {span=>
 | 
			
		||||
                        (())
 | 
			
		||||
                    }),
 | 
			
		||||
                    semi_token: Some(Token),
 | 
			
		||||
                }
 | 
			
		||||
                .to_tokens(tokens);
 | 
			
		||||
                quote_spanned! {span=>
 | 
			
		||||
                    #[allow(non_upper_case_globals, dead_code)]
 | 
			
		||||
                    #vis const #ident: #generics_accumulation_ident = #generics_accumulation_ident(());
 | 
			
		||||
                }
 | 
			
		||||
                .to_tokens(tokens);
 | 
			
		||||
                let mut wrapped_in_const = WrappedInConst::new(tokens, span);
 | 
			
		||||
                let tokens = wrapped_in_const.inner();
 | 
			
		||||
                let (impl_generics, _type_generics, where_clause) = syn_generics.split_for_impl();
 | 
			
		||||
                let phantom_const_get_ty = &generics.type_param.phantom_const_get_bound.ty;
 | 
			
		||||
                let index_output = if let Some(ty_is_dyn_size) = ty_is_dyn_size {
 | 
			
		||||
                    known_items::usize(ty_is_dyn_size.span).to_token_stream()
 | 
			
		||||
                } else {
 | 
			
		||||
                    ty.to_token_stream()
 | 
			
		||||
                };
 | 
			
		||||
                quote_spanned! {span=>
 | 
			
		||||
                    #[allow(non_upper_case_globals)]
 | 
			
		||||
                    #[automatically_derived]
 | 
			
		||||
                    impl #impl_generics ::fayalite::__std::ops::Index<#type_param_ident>
 | 
			
		||||
                    for #generics_accumulation_ident
 | 
			
		||||
                    #where_clause
 | 
			
		||||
                    {
 | 
			
		||||
                        type Output = #index_output;
 | 
			
		||||
 | 
			
		||||
                        fn index(&self, __param: #type_param_ident) -> &Self::Output {
 | 
			
		||||
                            ::fayalite::phantom_const::type_alias_phantom_const_get_helper::<#phantom_const_get_ty, #index_output>(
 | 
			
		||||
                                __param,
 | 
			
		||||
                                #get_expr,
 | 
			
		||||
                            )
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                .to_tokens(tokens);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) fn hdl_type_alias_impl(item: ItemType) -> syn::Result<TokenStream> {
 | 
			
		||||
    let item = ParsedTypeAlias::parse(item)?;
 | 
			
		||||
    let outline_generated = item.options.body.outline_generated;
 | 
			
		||||
    let outline_generated = match &item {
 | 
			
		||||
        ParsedTypeAlias::TypeAlias { options, .. }
 | 
			
		||||
        | ParsedTypeAlias::PhantomConstAccessor { options, .. } => options.body.outline_generated,
 | 
			
		||||
    };
 | 
			
		||||
    let mut contents = item.to_token_stream();
 | 
			
		||||
    if outline_generated.is_some() {
 | 
			
		||||
        contents = crate::outline_generated(contents, "hdl-type-alias-");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,6 +27,7 @@ crate::options! {
 | 
			
		|||
        NoStatic(no_static),
 | 
			
		||||
        NoRuntimeGenerics(no_runtime_generics),
 | 
			
		||||
        CmpEq(cmp_eq),
 | 
			
		||||
        Get(get, Expr),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2045,6 +2046,7 @@ pub(crate) mod known_items {
 | 
			
		|||
    impl_known_item!(::fayalite::int::Size);
 | 
			
		||||
    impl_known_item!(::fayalite::int::UInt);
 | 
			
		||||
    impl_known_item!(::fayalite::int::UIntType);
 | 
			
		||||
    impl_known_item!(::fayalite::phantom_const::PhantomConstGet);
 | 
			
		||||
    impl_known_item!(::fayalite::reset::ResetType);
 | 
			
		||||
    impl_known_item!(::fayalite::ty::CanonicalType);
 | 
			
		||||
    impl_known_item!(::fayalite::ty::StaticType);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,6 +76,7 @@ mod kw {
 | 
			
		|||
    custom_keyword!(connect_inexact);
 | 
			
		||||
    custom_keyword!(custom_bounds);
 | 
			
		||||
    custom_keyword!(flip);
 | 
			
		||||
    custom_keyword!(get);
 | 
			
		||||
    custom_keyword!(hdl);
 | 
			
		||||
    custom_keyword!(hdl_module);
 | 
			
		||||
    custom_keyword!(incomplete_wire);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,18 @@
 | 
			
		|||
// TODO: enable:
 | 
			
		||||
// #![warn(missing_docs)]
 | 
			
		||||
 | 
			
		||||
#![deny(
 | 
			
		||||
    rustdoc::bare_urls,
 | 
			
		||||
    rustdoc::broken_intra_doc_links,
 | 
			
		||||
    rustdoc::invalid_codeblock_attributes,
 | 
			
		||||
    rustdoc::invalid_html_tags,
 | 
			
		||||
    rustdoc::invalid_rust_codeblocks,
 | 
			
		||||
    rustdoc::private_doc_tests,
 | 
			
		||||
    rustdoc::private_intra_doc_links,
 | 
			
		||||
    rustdoc::redundant_explicit_links,
 | 
			
		||||
    rustdoc::unescaped_backticks
 | 
			
		||||
)]
 | 
			
		||||
 | 
			
		||||
//! [Main Documentation][_docs]
 | 
			
		||||
 | 
			
		||||
extern crate self as fayalite;
 | 
			
		||||
| 
						 | 
				
			
			@ -74,6 +86,135 @@ macro_rules! __cfg_expansion_helper {
 | 
			
		|||
pub use fayalite_proc_macros::hdl_module;
 | 
			
		||||
 | 
			
		||||
#[doc(inline)]
 | 
			
		||||
/// The `#[hdl]` attribute is supported on several different kinds of [Rust Items](https://doc.rust-lang.org/reference/items.html):
 | 
			
		||||
///
 | 
			
		||||
/// # Functions and Methods
 | 
			
		||||
/// Enable's the stuff that you can use inside a [module's body](crate::_docs::modules::module_bodies),
 | 
			
		||||
/// but without being a module or changing the function's signature.
 | 
			
		||||
/// The only exception is that you can't use stuff that requires the automatically-provided `m` variable.
 | 
			
		||||
///
 | 
			
		||||
/// # Structs
 | 
			
		||||
// TODO: expand on struct docs
 | 
			
		||||
/// e.g.:
 | 
			
		||||
/// ```
 | 
			
		||||
/// # use fayalite::prelude::*;
 | 
			
		||||
/// # #[hdl]
 | 
			
		||||
/// # pub struct OtherStruct {}
 | 
			
		||||
/// #[hdl]
 | 
			
		||||
/// pub struct MyStruct {
 | 
			
		||||
///     #[hdl(flip)]
 | 
			
		||||
///     pub a: UInt<5>,
 | 
			
		||||
///     pub b: Bool,
 | 
			
		||||
///     #[hdl(flip)]
 | 
			
		||||
///     pub c: OtherStruct,
 | 
			
		||||
/// }
 | 
			
		||||
/// ```
 | 
			
		||||
///
 | 
			
		||||
/// # Enums
 | 
			
		||||
// TODO: expand on enum docs
 | 
			
		||||
/// e.g.:
 | 
			
		||||
/// ```
 | 
			
		||||
/// # use fayalite::prelude::*;
 | 
			
		||||
/// # #[hdl]
 | 
			
		||||
/// # pub struct MyStruct {}
 | 
			
		||||
/// #[hdl]
 | 
			
		||||
/// pub enum MyEnum {
 | 
			
		||||
///     A(UInt<3>),
 | 
			
		||||
///     B,
 | 
			
		||||
///     C(MyStruct),
 | 
			
		||||
/// }
 | 
			
		||||
/// ```
 | 
			
		||||
///
 | 
			
		||||
/// # Type Aliases
 | 
			
		||||
///
 | 
			
		||||
/// There's three different ways you can create a type alias:
 | 
			
		||||
///
 | 
			
		||||
/// # Normal Type Alias
 | 
			
		||||
///
 | 
			
		||||
/// This works exactly how you'd expect:
 | 
			
		||||
/// ```
 | 
			
		||||
/// # use fayalite::prelude::*;
 | 
			
		||||
/// # #[hdl]
 | 
			
		||||
/// # pub struct MyStruct<T: Type> {
 | 
			
		||||
/// #     v: T,
 | 
			
		||||
/// # }
 | 
			
		||||
/// #[hdl]
 | 
			
		||||
/// pub type MyType<T: Type> = MyStruct<T>;
 | 
			
		||||
///
 | 
			
		||||
/// // you can then use Fayalite's standard syntax for creating dynamic types at runtime:
 | 
			
		||||
///
 | 
			
		||||
/// let ty = MyType[UInt[3]];
 | 
			
		||||
/// assert_eq!(ty, MyStruct[UInt[3]]);
 | 
			
		||||
/// ```
 | 
			
		||||
///
 | 
			
		||||
/// # Type Alias that gets a [`Type`] from a [`PhantomConst`]
 | 
			
		||||
///
 | 
			
		||||
/// This allows you to use some computed property of a [`PhantomConst`] to get a [`Type`] that you can use in other #[hdl] types.
 | 
			
		||||
///
 | 
			
		||||
/// ```
 | 
			
		||||
/// # use fayalite::{intern::Intern, prelude::*};
 | 
			
		||||
/// #[derive(Clone, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
 | 
			
		||||
/// pub struct Config {
 | 
			
		||||
///     pub foo: usize,
 | 
			
		||||
///     pub bar: Bundle,
 | 
			
		||||
/// }
 | 
			
		||||
///
 | 
			
		||||
/// // the expression inside `get` is called with `Interned<Config>` and returns `Array<Bundle>`
 | 
			
		||||
/// #[hdl(get(|config| Array[config.bar][config.foo]))]
 | 
			
		||||
/// pub type GetMyArray<P: PhantomConstGet<Config>> = Array<Bundle>;
 | 
			
		||||
///
 | 
			
		||||
/// // you can then use it in other types:
 | 
			
		||||
///
 | 
			
		||||
/// #[hdl(no_static)]
 | 
			
		||||
/// pub struct WrapMyArray<P: Type + PhantomConstGet<Config>> {
 | 
			
		||||
///     pub my_array: GetMyArray<P>,
 | 
			
		||||
/// }
 | 
			
		||||
///
 | 
			
		||||
/// // you can then use Fayalite's standard syntax for creating dynamic types at runtime:
 | 
			
		||||
/// let bar = Bundle::new(Default::default());
 | 
			
		||||
/// let config = PhantomConst::new(Config { foo: 12, bar }.intern_sized());
 | 
			
		||||
/// let ty = WrapMyArray[config];
 | 
			
		||||
/// assert_eq!(ty.my_array, Array[bar][12]);
 | 
			
		||||
/// ```
 | 
			
		||||
///
 | 
			
		||||
/// # Type Alias that gets a [`Size`] from a [`PhantomConst`]
 | 
			
		||||
///
 | 
			
		||||
/// This allows you to use some computed property of a [`PhantomConst`] to get a [`Size`] that you can use in other #[hdl] types.
 | 
			
		||||
///
 | 
			
		||||
/// ```
 | 
			
		||||
/// # use fayalite::{intern::Intern, prelude::*};
 | 
			
		||||
/// # #[derive(Clone, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
 | 
			
		||||
/// # pub struct ConfigItem {}
 | 
			
		||||
/// # impl ConfigItem {
 | 
			
		||||
/// #     pub fn new() -> Self {
 | 
			
		||||
/// #         Self {}
 | 
			
		||||
/// #     }
 | 
			
		||||
/// # }
 | 
			
		||||
/// #[derive(Clone, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
 | 
			
		||||
/// pub struct Config {
 | 
			
		||||
///     pub items: Vec<ConfigItem>,
 | 
			
		||||
/// }
 | 
			
		||||
///
 | 
			
		||||
/// // the expression inside `get` is called with `Interned<Config>` and returns `usize` (not DynSize)
 | 
			
		||||
/// #[hdl(get(|config| config.items.len()))]
 | 
			
		||||
/// pub type GetItemsLen<P: PhantomConstGet<Config>> = DynSize; // must be DynSize
 | 
			
		||||
///
 | 
			
		||||
/// // you can then use it in other types:
 | 
			
		||||
///
 | 
			
		||||
/// #[hdl(no_static)]
 | 
			
		||||
/// pub struct FlagPerItem<P: Type + PhantomConstGet<Config>> {
 | 
			
		||||
///     pub flags: ArrayType<Bool, GetItemsLen<P>>,
 | 
			
		||||
/// }
 | 
			
		||||
///
 | 
			
		||||
/// // you can then use Fayalite's standard syntax for creating dynamic types at runtime:
 | 
			
		||||
/// let config = PhantomConst::new(Config { items: vec![ConfigItem::new(); 5] }.intern_sized());
 | 
			
		||||
/// let ty = FlagPerItem[config];
 | 
			
		||||
/// assert_eq!(ty.flags, Array[Bool][5]);
 | 
			
		||||
/// ```
 | 
			
		||||
///
 | 
			
		||||
/// [`PhantomConst`]: crate::phantom_const::PhantomConst
 | 
			
		||||
/// [`Size`]: crate::int::Size
 | 
			
		||||
/// [`Type`]: crate::ty::Type
 | 
			
		||||
pub use fayalite_proc_macros::hdl;
 | 
			
		||||
 | 
			
		||||
pub use bitvec;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -415,3 +415,71 @@ impl<T: ?Sized + PhantomConstValue> ToSimValueWithType<CanonicalType> for Phanto
 | 
			
		|||
        SimValue::into_canonical(SimValue::from_value(Self::from_canonical(ty), *self))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
mod sealed {
 | 
			
		||||
    pub trait Sealed<T: ?Sized> {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub trait PhantomConstGet<T: ?Sized + PhantomConstValue>: sealed::Sealed<T> {
 | 
			
		||||
    fn get(&self) -> Interned<T>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + PhantomConstValue, This: ?Sized + std::ops::Deref<Target: PhantomConstGet<T>>>
 | 
			
		||||
    sealed::Sealed<T> for This
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: ?Sized + PhantomConstValue, This: ?Sized + std::ops::Deref<Target: PhantomConstGet<T>>>
 | 
			
		||||
    PhantomConstGet<T> for This
 | 
			
		||||
{
 | 
			
		||||
    fn get(&self) -> Interned<T> {
 | 
			
		||||
        This::Target::get(&**self)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
macro_rules! impl_phantom_const_get {
 | 
			
		||||
    (
 | 
			
		||||
        impl PhantomConstGet<$T:ident> for $ty:ty {
 | 
			
		||||
            fn $get:ident(&$get_self:ident) -> _ $get_body:block
 | 
			
		||||
        }
 | 
			
		||||
    ) => {
 | 
			
		||||
        impl<$T: ?Sized + PhantomConstValue> sealed::Sealed<$T> for $ty {}
 | 
			
		||||
 | 
			
		||||
        impl<$T: ?Sized + PhantomConstValue> PhantomConstGet<$T> for $ty {
 | 
			
		||||
            fn $get(&$get_self) -> Interned<$T> $get_body
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl_phantom_const_get! {
 | 
			
		||||
    impl PhantomConstGet<T> for PhantomConst<T> {
 | 
			
		||||
        fn get(&self) -> _ {
 | 
			
		||||
            PhantomConst::get(*self)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl_phantom_const_get! {
 | 
			
		||||
    impl PhantomConstGet<T> for Expr<PhantomConst<T>> {
 | 
			
		||||
        fn get(&self) -> _ {
 | 
			
		||||
            PhantomConst::get(Expr::ty(*self))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[doc(hidden)]
 | 
			
		||||
pub trait ReturnSelfUnchanged<T: ?Sized> {
 | 
			
		||||
    type Type: ?Sized;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<This: ?Sized, T: ?Sized> ReturnSelfUnchanged<T> for This {
 | 
			
		||||
    type Type = This;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[doc(hidden)]
 | 
			
		||||
pub fn type_alias_phantom_const_get_helper<T: ?Sized + PhantomConstValue, R: Intern + Clone>(
 | 
			
		||||
    param: impl PhantomConstGet<T>,
 | 
			
		||||
    get: impl FnOnce(Interned<T>) -> R,
 | 
			
		||||
) -> &'static R {
 | 
			
		||||
    Interned::into_inner(get(param.get()).intern_sized())
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ pub use crate::{
 | 
			
		|||
        Instance, Module, ModuleBuilder, annotate, connect, connect_any, incomplete_wire, instance,
 | 
			
		||||
        memory, memory_array, memory_with_init, reg_builder, wire,
 | 
			
		||||
    },
 | 
			
		||||
    phantom_const::PhantomConst,
 | 
			
		||||
    phantom_const::{PhantomConst, PhantomConstGet},
 | 
			
		||||
    platform::{DynPlatform, Platform, PlatformIOBuilder, peripherals},
 | 
			
		||||
    reg::Reg,
 | 
			
		||||
    reset::{AsyncReset, Reset, SyncReset, ToAsyncReset, ToReset, ToSyncReset},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,6 @@ use fayalite::{
 | 
			
		|||
    bundle::BundleType,
 | 
			
		||||
    enum_::EnumType,
 | 
			
		||||
    int::{BoolOrIntType, IntType},
 | 
			
		||||
    phantom_const::PhantomConst,
 | 
			
		||||
    prelude::*,
 | 
			
		||||
    ty::StaticType,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -197,3 +196,21 @@ check_bounds!(CheckBoundsTTT2<#[a, Type] A: BundleType +, #[b, Type] B: Type +,
 | 
			
		|||
check_bounds!(CheckBoundsTTT3<#[a, Type] A: EnumType +, #[b, Type] B: Type +, #[c, Type] C: Type +>);
 | 
			
		||||
check_bounds!(CheckBoundsTTT4<#[a, Type] A: IntType +, #[b, Type] B: Type +, #[c, Type] C: Type +>);
 | 
			
		||||
check_bounds!(CheckBoundsTTT5<#[a, Type] A: StaticType +, #[b, Type] B: Type +, #[c, Type] C: Type +>);
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, serde::Serialize, serde::Deserialize)]
 | 
			
		||||
pub struct MyPhantomConstInner {
 | 
			
		||||
    pub a: usize,
 | 
			
		||||
    pub b: UInt,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[hdl(outline_generated, get(|v| v.a))]
 | 
			
		||||
pub type GetA<P: PhantomConstGet<MyPhantomConstInner>> = DynSize;
 | 
			
		||||
 | 
			
		||||
#[hdl(outline_generated, get(|v| v.b))]
 | 
			
		||||
pub type GetB<P: PhantomConstGet<MyPhantomConstInner>> = UInt;
 | 
			
		||||
 | 
			
		||||
#[hdl(outline_generated, no_static)]
 | 
			
		||||
pub struct MyTypeWithPhantomConstParameter<P: Type + PhantomConstGet<MyPhantomConstInner>> {
 | 
			
		||||
    pub a: ArrayType<Bool, GetA<P>>,
 | 
			
		||||
    pub b: HdlOption<GetB<P>>,
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue