fayalite 0.2.0

Hardware Description Language embedded in Rust, using FIRRTL's semantics
Documentation
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use crate::{
    expr::target::Target,
    intern::{Intern, Interned},
};
use serde::{Deserialize, Serialize};
use std::{
    fmt,
    hash::{Hash, Hasher},
    iter::FusedIterator,
    ops::Deref,
};

#[derive(Clone)]
struct CustomFirrtlAnnotationFieldsImpl {
    value: serde_json::Map<String, serde_json::Value>,
    serialized: Interned<str>,
}

impl Hash for CustomFirrtlAnnotationFieldsImpl {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.serialized.hash(state);
    }
}

impl Eq for CustomFirrtlAnnotationFieldsImpl {}

impl PartialEq for CustomFirrtlAnnotationFieldsImpl {
    fn eq(&self, other: &Self) -> bool {
        self.serialized == other.serialized
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct CustomFirrtlAnnotationFields(Interned<CustomFirrtlAnnotationFieldsImpl>);

impl fmt::Debug for CustomFirrtlAnnotationFields {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.value.fmt(f)
    }
}

impl<'de> Deserialize<'de> for CustomFirrtlAnnotationFields {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        serde_json::Map::<String, serde_json::Value>::deserialize(deserializer).map(Self::from)
    }
}

impl Serialize for CustomFirrtlAnnotationFields {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        self.0.value.serialize(serializer)
    }
}

impl Deref for CustomFirrtlAnnotationFields {
    type Target = serde_json::Map<String, serde_json::Value>;

    fn deref(&self) -> &Self::Target {
        &self.0.value
    }
}

impl From<serde_json::Map<String, serde_json::Value>> for CustomFirrtlAnnotationFields {
    fn from(value: serde_json::Map<String, serde_json::Value>) -> Self {
        let serialized =
            serde_json::to_string(&value).expect("serialization of JSON should succeed");
        Self(Intern::intern_sized(CustomFirrtlAnnotationFieldsImpl {
            value,
            serialized: Intern::intern_owned(serialized),
        }))
    }
}

#[derive(Debug, Clone)]
pub struct NotAJsonObject(pub serde_json::Value);

impl fmt::Display for NotAJsonObject {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("not a JSON object")
    }
}

impl std::error::Error for NotAJsonObject {}

impl TryFrom<serde_json::Value> for CustomFirrtlAnnotationFields {
    type Error = NotAJsonObject;

    fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
        match value {
            serde_json::Value::Object(value) => Ok(value.into()),
            _ => Err(NotAJsonObject(value)),
        }
    }
}

impl From<CustomFirrtlAnnotationFields> for serde_json::Map<String, serde_json::Value> {
    fn from(value: CustomFirrtlAnnotationFields) -> Self {
        Self::clone(&value)
    }
}

impl From<CustomFirrtlAnnotationFields> for serde_json::Value {
    fn from(value: CustomFirrtlAnnotationFields) -> Self {
        serde_json::Value::Object(value.into())
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
pub struct CustomFirrtlAnnotation {
    pub class: Interned<str>,
    #[serde(flatten)]
    pub additional_fields: CustomFirrtlAnnotationFields,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
pub struct DontTouchAnnotation;

#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
pub struct SVAttributeAnnotation {
    pub text: Interned<str>,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
pub struct BlackBoxInlineAnnotation {
    pub path: Interned<str>,
    pub text: Interned<str>,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
pub struct BlackBoxPathAnnotation {
    pub path: Interned<str>,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Serialize, Deserialize)]
pub struct DocStringAnnotation {
    pub text: Interned<str>,
}

macro_rules! make_annotation_enum {
    (
        $(#[$meta:meta])*
        $vis:vis enum $Annotation:ident {
            $($Variant:ident($T:ident),)*
        }
    ) => {
        $(#[$meta])*
        $vis enum $Annotation {
            $($Variant($T),)*
        }

        $(impl IntoAnnotations for $T {
            type IntoAnnotations = [$Annotation; 1];

            fn into_annotations(self) -> Self::IntoAnnotations {
                [$Annotation::$Variant(self)]
            }
        }

        impl IntoAnnotations for &'_ $T {
            type IntoAnnotations = [$Annotation; 1];

            fn into_annotations(self) -> Self::IntoAnnotations {
                [$Annotation::$Variant(*self)]
            }
        }

        impl IntoAnnotations for &'_ mut $T {
            type IntoAnnotations = [$Annotation; 1];

            fn into_annotations(self) -> Self::IntoAnnotations {
                [$Annotation::$Variant(*self)]
            }
        }

        impl IntoAnnotations for Box<$T> {
            type IntoAnnotations = [$Annotation; 1];

            fn into_annotations(self) -> Self::IntoAnnotations {
                [$Annotation::$Variant(*self)]
            }
        })*
    };
}

make_annotation_enum! {
    #[derive(Clone, PartialEq, Eq, Hash, Debug)]
    #[non_exhaustive]
    pub enum Annotation {
        DontTouch(DontTouchAnnotation),
        SVAttribute(SVAttributeAnnotation),
        BlackBoxInline(BlackBoxInlineAnnotation),
        BlackBoxPath(BlackBoxPathAnnotation),
        DocString(DocStringAnnotation),
        CustomFirrtl(CustomFirrtlAnnotation),
    }
}

#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct TargetedAnnotation {
    target: Interned<Target>,
    annotation: Annotation,
}

impl TargetedAnnotation {
    #[track_caller]
    pub fn new(target: Interned<Target>, annotation: Annotation) -> Self {
        Self::assert_valid_target(target);
        Self { target, annotation }
    }
    #[track_caller]
    pub fn assert_valid_target(target: Interned<Target>) {
        assert!(target.is_static(), "can't annotate non-static targets");
    }
    pub fn target(&self) -> Interned<Target> {
        self.target
    }
    pub fn annotation(&self) -> &Annotation {
        &self.annotation
    }
}

pub trait IntoAnnotations {
    type IntoAnnotations: IntoIterator<Item = Annotation>;

    fn into_annotations(self) -> Self::IntoAnnotations;
}

impl IntoAnnotations for Annotation {
    type IntoAnnotations = [Annotation; 1];

    fn into_annotations(self) -> Self::IntoAnnotations {
        [self]
    }
}

impl IntoAnnotations for Box<Annotation> {
    type IntoAnnotations = [Annotation; 1];

    fn into_annotations(self) -> Self::IntoAnnotations {
        [*self]
    }
}

impl IntoAnnotations for &'_ Annotation {
    type IntoAnnotations = [Annotation; 1];

    fn into_annotations(self) -> Self::IntoAnnotations {
        [self.clone()]
    }
}

impl IntoAnnotations for &'_ mut Annotation {
    type IntoAnnotations = [Annotation; 1];

    fn into_annotations(self) -> Self::IntoAnnotations {
        [self.clone()]
    }
}

pub struct IterIntoAnnotations<T: Iterator<Item: IntoAnnotations>> {
    outer: T,
    inner: Option<<<T::Item as IntoAnnotations>::IntoAnnotations as IntoIterator>::IntoIter>,
}

impl<T: Iterator<Item: IntoAnnotations>> Iterator for IterIntoAnnotations<T> {
    type Item = Annotation;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(inner) = &mut self.inner {
                let Some(retval) = inner.next() else {
                    self.inner = None;
                    continue;
                };
                return Some(retval);
            } else {
                self.inner = Some(self.outer.next()?.into_annotations().into_iter());
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        if let (0, Some(0)) = self.outer.size_hint() {
            self.inner
                .as_ref()
                .map(|v| v.size_hint())
                .unwrap_or((0, Some(0)))
        } else {
            (
                self.inner.as_ref().map(|v| v.size_hint().0).unwrap_or(0),
                None,
            )
        }
    }

    fn fold<B, F>(self, init: B, f: F) -> B
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> B,
    {
        self.inner
            .into_iter()
            .chain(self.outer.map(|v| v.into_annotations().into_iter()))
            .flatten()
            .fold(init, f)
    }
}

impl<
        T: FusedIterator<
            Item: IntoAnnotations<IntoAnnotations: IntoIterator<IntoIter: FusedIterator>>,
        >,
    > FusedIterator for IterIntoAnnotations<T>
{
}

impl<T: IntoIterator<Item: IntoAnnotations>> IntoAnnotations for T {
    type IntoAnnotations = IterIntoAnnotations<T::IntoIter>;

    fn into_annotations(self) -> Self::IntoAnnotations {
        IterIntoAnnotations {
            outer: self.into_iter(),
            inner: None,
        }
    }
}