compose_library/foundations/
ty.rs

1use crate::{Scope, Sink, Trace, UnBoundError, Value};
2use compose_library::diag::StrResult;
3use compose_library::{UnboundItem, UntypedRef};
4use compose_macros::{cast, ty};
5use compose_syntax::Span;
6use compose_utils::Static;
7use ecow::eco_format;
8use std::fmt::Display;
9use std::sync::LazyLock;
10
11#[derive(Clone, Debug, PartialEq)]
12#[ty(cast, name = "type")]
13pub struct Type(Static<NativeTypeData>);
14
15impl Type {
16    pub fn of<T: NativeType>() -> Self {
17        T::ty()
18    }
19
20    pub fn scope(&self) -> &'static Scope {
21        &self.0.0.scope
22    }
23
24    pub fn field(&self, field: &str, access_span: Span, sink: &mut Sink) -> StrResult<&Value> {
25        self.0
26            .scope
27            .get(field)
28            .map(|b| b.read_checked(access_span, sink))
29            .ok_or_else(|| eco_format!("no field or method `{}` on type `{}`", field, self))
30    }
31
32    pub fn path(
33        &self,
34        path: &str,
35        access_span: Span,
36        sink: &mut Sink,
37    ) -> Result<&Value, UnBoundError> {
38        self.0
39            .scope
40            .try_get(path)
41            .map_err(|e| e.with_item(UnboundItem::AssociatedFieldOrFunction(self.name().into())))
42            .map(|b| b.read_checked(access_span, sink))
43    }
44
45    pub fn name(&self) -> &'static str {
46        self.0.name
47    }
48}
49
50impl Trace for Type {
51    fn visit_refs(&self, f: &mut dyn FnMut(UntypedRef)) {
52        self.scope().visit_refs(f);
53    }
54}
55
56#[derive(Debug)]
57pub struct NativeTypeData {
58    pub name: &'static str,
59    pub title: &'static str,
60    pub docs: &'static str,
61    pub scope: LazyLock<&'static Scope>,
62}
63
64impl Display for Type {
65    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66        write!(f, "{}", self.0.name)
67    }
68}
69
70pub trait NativeType {
71    const NAME: &'static str;
72    fn ty() -> Type {
73        Type::from(Self::data())
74    }
75
76    fn data() -> &'static NativeTypeData;
77}
78
79impl From<&'static NativeTypeData> for Type {
80    fn from(data: &'static NativeTypeData) -> Self {
81        Self(Static(data))
82    }
83}
84
85cast! {
86    &'static NativeTypeData,
87    self => Type::from(self).into_value(),
88}