1use crate::{
43 builtin::attr_interfaces::{OutlinedAttr, TypedAttrInterface},
44 combine::{Parser, parser, token},
45 common_traits::Verify,
46 context::{Context, collect_deduped_interface_verifiers},
47 dialect::{Dialect, DialectName},
48 dyn_clone::DynClone,
49 identifier::Identifier,
50 impl_printable_for_display, input_err, input_error,
51 irfmt::{
52 parsers::{attr_parser, delimited_list_parser, spaced},
53 printers::iter_with_sep,
54 },
55 parsable::{IntoParseResult, Parsable, ParseResult, StateStream, StreamLocation},
56 printable::{self, Printable},
57 result::Result,
58 std_deps::sync::LazyLock,
59 storage_uniquer::TypeValueHash,
60 r#type::TypeHandle,
61 utils::{
62 table::{HMap, SmallMap},
63 trait_cast::impls_trait_static,
64 },
65};
66use alloc::{
67 boxed::Box,
68 string::{String, ToString},
69 vec::Vec,
70};
71use core::{
72 fmt::{Debug, Display},
73 hash::{Hash, Hasher},
74 ops::Deref,
75};
76use downcast_rs::{Downcast, impl_downcast};
77use thiserror::Error;
78
79#[derive(Clone)]
81struct AttributeDictKeyVal<'a> {
82 key: &'a Identifier,
83 val: &'a AttrObj,
84}
85
86impl<'a> Printable for AttributeDictKeyVal<'a> {
87 fn fmt(
88 &self,
89 ctx: &Context,
90 state: &printable::State,
91 f: &mut core::fmt::Formatter<'_>,
92 ) -> core::fmt::Result {
93 write!(f, "{}: {}", self.key, self.val.print(ctx, state))
94 }
95}
96
97impl<'b> Parsable for AttributeDictKeyVal<'b> {
98 type Arg = ();
99
100 type Parsed = (Identifier, AttrObj);
101
102 fn parse<'a>(
103 state_stream: &mut StateStream<'a>,
104 _arg: Self::Arg,
105 ) -> ParseResult<'a, Self::Parsed> {
106 (Identifier::parser(()), spaced(token(':')), attr_parser())
107 .map(|(key, _, val)| (key, val))
108 .parse_stream(state_stream)
109 .into_result()
110 }
111}
112
113impl Printable for AttributeDict {
114 fn fmt(
115 &self,
116 ctx: &Context,
117 state: &printable::State,
118 f: &mut core::fmt::Formatter<'_>,
119 ) -> core::fmt::Result {
120 write!(
121 f,
122 "[{}]",
123 iter_with_sep(
124 self.0
125 .iter()
126 .map(|(key, val)| AttributeDictKeyVal { key, val }),
127 printable::ListSeparator::CharSpace(','),
128 )
129 .print(ctx, state)
130 )
131 }
132}
133
134impl Parsable for AttributeDict {
135 type Arg = ();
136 type Parsed = Self;
137
138 fn parse<'a>(
139 state_stream: &mut StateStream<'a>,
140 _arg: Self::Arg,
141 ) -> ParseResult<'a, Self::Parsed> {
142 delimited_list_parser('[', ']', ',', AttributeDictKeyVal::parser(()))
143 .map(|key_vals| AttributeDict(key_vals.into_iter().collect()))
144 .parse_stream(state_stream)
145 .into_result()
146 }
147}
148
149pub type AttributeDictContainer = SmallMap<Identifier, AttrObj, 1>;
150
151#[derive(Default, Debug, Clone, PartialEq, Eq)]
153pub struct AttributeDict(pub AttributeDictContainer);
154
155impl Hash for AttributeDict {
156 fn hash<H: Hasher>(&self, state: &mut H) {
157 let mut entries: Vec<_> = self.0.iter().collect();
159 entries.sort_by_key(|(k, _)| *k);
160 entries.hash(state);
161 }
162}
163
164impl AttributeDict {
165 pub fn get<T: Attribute>(&self, k: &Identifier) -> Option<&T> {
167 self.0.get(k).and_then(|ao| ao.downcast_ref::<T>())
168 }
169
170 pub fn get_mut<T: Attribute>(&mut self, k: &Identifier) -> Option<&mut T> {
172 self.0.get_mut(k).and_then(|ao| ao.downcast_mut::<T>())
173 }
174
175 pub fn get_as<T: ?Sized + AttrInterfaceMarker + 'static>(&self, k: &Identifier) -> Option<&T> {
177 self.0.get(k).and_then(|ao| attr_cast::<T>(&**ao))
178 }
179
180 pub fn set<T: Attribute>(&mut self, k: Identifier, v: T) {
182 self.0.insert(k, Box::new(v));
183 }
184
185 pub fn clone_skip_outlined(&self, ctx: &Context) -> Self {
187 self.0
188 .iter()
189 .filter_map(|(k, v)| {
190 if attr_should_outline(&**v, ctx) {
191 None
192 } else {
193 Some((k.clone(), dyn_clone::clone_box(&**v)))
194 }
195 })
196 .collect::<AttributeDictContainer>()
197 .into()
198 }
199}
200
201impl From<AttributeDictContainer> for AttributeDict {
202 fn from(value: AttributeDictContainer) -> Self {
203 AttributeDict(value)
204 }
205}
206
207pub trait Attribute: Printable + Verify + Downcast + Sync + Send + DynClone + Debug {
211 fn hash_attr(&self) -> TypeValueHash;
214
215 fn eq_attr(&self, other: &dyn Attribute) -> bool;
217
218 fn get_attr_id(&self) -> AttrId;
221
222 fn get_attr_id_static() -> AttrId
224 where
225 Self: Sized;
226
227 #[doc(hidden)]
228 fn verify_interfaces(&self, ctx: &Context) -> Result<()>;
230
231 fn register<A: Attribute>(ctx: &mut Context)
233 where
234 Self: Sized + Parsable<Arg = (), Parsed = A>,
235 {
236 let attr_parser: AttrParserFn = |parsable_state, &()| {
237 Self::parse(parsable_state, ()).map(|(attr, r)| -> (AttrObj, _) { (Box::new(attr), r) })
238 };
239 let attrid = Self::get_attr_id_static();
240 Dialect::register(ctx, &attrid.dialect).add_attr(attrid.clone(), attr_parser);
241 }
242}
243impl_downcast!(Attribute);
244dyn_clone::clone_trait_object!(Attribute);
245
246pub type AttrObj = Box<dyn Attribute>;
248
249pub(crate) type AttrParserFn = for<'a> fn(&mut StateStream<'a>, &'a ()) -> ParseResult<'a, AttrObj>;
252
253impl PartialEq for AttrObj {
254 fn eq(&self, other: &Self) -> bool {
255 (**self).eq_attr(&**other)
256 }
257}
258
259impl<T: Attribute> From<T> for AttrObj {
260 fn from(value: T) -> Self {
261 Box::new(value)
262 }
263}
264
265impl Eq for AttrObj {}
266
267impl Hash for AttrObj {
268 fn hash<H: Hasher>(&self, state: &mut H) {
269 state.write_u64(self.hash_attr().into());
270 }
271}
272
273pub fn fmt_attr_obj(
288 attr: &dyn Attribute,
289 ctx: &Context,
290 state: &printable::State,
291 f: &mut core::fmt::Formatter<'_>,
292) -> core::fmt::Result {
293 write!(f, "{} ", attr.get_attr_id())?;
294 Printable::fmt(attr, ctx, state, f)
295}
296
297impl Printable for AttrObj {
298 fn fmt(
299 &self,
300 ctx: &Context,
301 state: &printable::State,
302 f: &mut core::fmt::Formatter<'_>,
303 ) -> core::fmt::Result {
304 fmt_attr_obj(self.deref(), ctx, state, f)
305 }
306}
307
308#[derive(Debug, Error)]
309#[error("{provided} does not implement the attribute interface {interface}")]
310pub struct AttrInterfaceCastErr {
311 pub interface: String,
312 pub provided: String,
313}
314
315pub fn parse_attr_interface_obj<'a, I: ?Sized + AttrInterfaceMarker + 'static>(
340 state_stream: &mut StateStream<'a>,
341) -> ParseResult<'a, Box<I>> {
342 let loc = state_stream.loc();
343 let (attr, _) = attr_parser().parse_stream(state_stream).into_result()?;
344
345 let provided = attr.get_attr_id();
347 boxed_attr_cast::<I>(attr)
348 .ok_or_else(|| {
349 input_error!(
350 loc,
351 AttrInterfaceCastErr {
352 interface: core::any::type_name::<I>().to_string(),
353 provided: provided.to_string(),
354 }
355 )
356 })
357 .into_parse_result()
358}
359
360impl Parsable for AttrObj {
361 type Arg = ();
362 type Parsed = AttrObj;
363
364 fn parse<'a>(
365 state_stream: &mut StateStream<'a>,
366 _arg: Self::Arg,
367 ) -> ParseResult<'a, Self::Parsed> {
368 let loc = state_stream.loc();
369 let attr_id_parser = spaced(AttrId::parser(()));
370
371 let mut attr_parser = attr_id_parser.then(move |attr_id: AttrId| {
372 let loc = loc.clone();
373 combine::parser(move |parsable_state: &mut StateStream<'a>| {
374 let state = &parsable_state.state;
375 let dialect = state
376 .ctx
377 .dialects
378 .get(&attr_id.dialect)
379 .expect("Dialect name parsed but dialect isn't registered");
380 let Some(attr_parser) = dialect.attributes.get(&attr_id) else {
381 input_err!(
382 loc.clone(),
383 "Unregistered attribute {}",
384 attr_id.disp(state.ctx)
385 )?
386 };
387 attr_parser(parsable_state, &())
388 })
389 });
390
391 attr_parser.parse_stream(state_stream).into_result()
392 }
393}
394
395pub fn verify_attr(attr: &dyn Attribute, ctx: &Context) -> Result<()> {
399 attr.verify_interfaces(ctx)?;
401
402 Verify::verify(attr, ctx)
404}
405
406impl Verify for AttrObj {
407 fn verify(&self, ctx: &Context) -> Result<()> {
408 verify_attr(self.as_ref(), ctx)
409 }
410}
411
412#[diagnostic::on_unimplemented(
417 message = "`{Self}` not an attribute interface.",
418 label = "If `{Self}` is a trait, annotate it with #[attr_interface] to be able to cast to it from a `&dyn Attribute`",
419 note = "If you want to cast to a concrete `Attribute`, use `downcast_ref` instead."
420)]
421pub trait AttrInterfaceMarker {}
422
423pub fn attr_cast<T: ?Sized + AttrInterfaceMarker + 'static>(attr: &dyn Attribute) -> Option<&T> {
447 crate::utils::trait_cast::any_to_trait::<T>(attr.as_any())
448}
449
450pub fn attr_impls<T: ?Sized + AttrInterfaceMarker + 'static>(attr: &dyn Attribute) -> bool {
472 attr_cast::<T>(attr).is_some()
473}
474
475pub fn attr_should_outline(attr: &dyn Attribute, ctx: &Context) -> bool {
477 attr_cast::<dyn OutlinedAttr>(attr).is_some_and(|attr| OutlinedAttr::outline(attr, ctx))
478}
479
480pub fn attr_impls_static<A: Attribute, I: ?Sized + AttrInterfaceMarker + 'static>() -> bool {
492 impls_trait_static::<A, I>()
493}
494
495pub fn boxed_attr_cast<T: ?Sized + AttrInterfaceMarker + 'static>(
537 attr: Box<dyn Attribute>,
538) -> Option<Box<T>> {
539 crate::utils::trait_cast::boxed_any_to_trait::<T>(attr as Box<dyn core::any::Any>)
540}
541
542pub fn attr_type(attr: &dyn Attribute, ctx: &Context) -> Option<TypeHandle> {
564 attr_cast::<dyn TypedAttrInterface>(attr).map(|typed| typed.get_type(ctx))
565}
566
567#[derive(Clone, Hash, PartialEq, Eq)]
568pub struct AttrName(Identifier);
570
571impl AttrName {
572 pub fn try_new(name: &str) -> Result<AttrName> {
574 Identifier::try_from(name).map(AttrName)
575 }
576}
577
578impl_printable_for_display!(AttrName);
579
580impl Display for AttrName {
581 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
582 write!(f, "{}", self.0)
583 }
584}
585
586impl Parsable for AttrName {
587 type Arg = ();
588 type Parsed = AttrName;
589
590 fn parse<'a>(
591 state_stream: &mut crate::parsable::StateStream<'a>,
592 _arg: Self::Arg,
593 ) -> ParseResult<'a, Self::Parsed>
594 where
595 Self: Sized,
596 {
597 Identifier::parser(())
598 .map(AttrName)
599 .parse_stream(state_stream)
600 .into()
601 }
602}
603
604impl AsRef<str> for AttrName {
605 fn as_ref(&self) -> &str {
606 self.0.as_ref()
607 }
608}
609
610impl AsRef<Identifier> for AttrName {
611 fn as_ref(&self) -> &Identifier {
612 &self.0
613 }
614}
615
616impl From<Identifier> for AttrName {
617 fn from(value: Identifier) -> Self {
618 AttrName(value)
619 }
620}
621
622impl From<AttrName> for Identifier {
623 fn from(value: AttrName) -> Self {
624 value.0
625 }
626}
627
628impl TryFrom<&str> for AttrName {
629 type Error = crate::result::Error;
630
631 fn try_from(value: &str) -> Result<Self> {
632 Identifier::try_from(value).map(AttrName)
633 }
634}
635
636impl TryFrom<String> for AttrName {
637 type Error = crate::result::Error;
638
639 fn try_from(value: String) -> Result<Self> {
640 Identifier::try_from(value).map(AttrName)
641 }
642}
643
644#[derive(Clone, Hash, PartialEq, Eq)]
646pub struct AttrId {
647 pub dialect: DialectName,
648 pub name: AttrName,
649}
650
651impl_printable_for_display!(AttrId);
652
653impl Display for AttrId {
654 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
655 write!(f, "{}.{}", self.dialect, self.name)
656 }
657}
658
659impl Parsable for AttrId {
660 type Arg = ();
661 type Parsed = AttrId;
662
663 fn parse<'a>(
665 state_stream: &mut StateStream<'a>,
666 _arg: Self::Arg,
667 ) -> ParseResult<'a, Self::Parsed>
668 where
669 Self: Sized,
670 {
671 let mut parser = DialectName::parser(())
672 .skip(parser::char::char('.'))
673 .and(AttrName::parser(()))
674 .map(|(dialect, name)| AttrId { dialect, name });
675 parser.parse_stream(state_stream).into()
676 }
677}
678
679pub type AttrInterfaceVerifier = fn(&dyn Attribute, &Context) -> Result<()>;
681pub type AttrInterfaceAllVerifiers = fn() -> Vec<AttrInterfaceVerifier>;
683
684#[doc(hidden)]
685type AttrInterfaceVerifierInfo = &'static [(core::any::TypeId, AttrInterfaceAllVerifiers)];
688
689#[doc(hidden)]
690#[cfg(not(target_family = "wasm"))]
691pub mod statics {
692 use super::*;
693
694 #[::pliron::linkme::distributed_slice]
695 pub static ATTR_INTERFACE_VERIFIERS: [AttrInterfaceVerifierInfo] = [..];
696
697 pub(super) fn get_attr_interface_verifiers()
698 -> impl Iterator<Item = &'static AttrInterfaceVerifierInfo> {
699 ATTR_INTERFACE_VERIFIERS.iter()
700 }
701}
702#[doc(hidden)]
703#[cfg(not(target_family = "wasm"))]
704pub use statics::ATTR_INTERFACE_VERIFIERS;
705
706#[doc(hidden)]
707#[cfg(target_family = "wasm")]
708pub mod statics {
709 use super::*;
710 use crate::InventoryWrapper;
711
712 ::pliron::inventory::collect!(InventoryWrapper<AttrInterfaceVerifierInfo>);
713
714 pub(super) fn get_attr_interface_verifiers()
715 -> impl Iterator<Item = &'static AttrInterfaceVerifierInfo> {
716 ::pliron::inventory::iter::<InventoryWrapper<AttrInterfaceVerifierInfo>>().map(|llw| llw.0)
717 }
718}
719
720#[doc(hidden)]
721pub static ATTR_INTERFACE_VERIFIERS_MAP: LazyLock<
724 HMap<core::any::TypeId, Vec<AttrInterfaceVerifier>>,
725> = LazyLock::new(|| collect_deduped_interface_verifiers(statics::get_attr_interface_verifiers()));