fayalite/crates/fayalite/src/annotations.rs

353 lines
9.8 KiB
Rust

// 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, Debug)]
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 {
(
#[$non_exhaustive:ident]
$(#[$meta:meta])*
$vis:vis enum $AnnotationEnum:ident {
$($Variant:ident($T:ty),)*
}
) => {
crate::annotations::make_annotation_enum!(@require_non_exhaustive $non_exhaustive);
#[$non_exhaustive]
$(#[$meta])*
#[derive(Clone, PartialEq, Eq, Hash)]
$vis enum $AnnotationEnum {
$($Variant($T),)*
}
impl std::fmt::Debug for $AnnotationEnum {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
$(Self::$Variant(v) => v.fmt(f),)*
}
}
}
$(impl From<$T> for crate::annotations::Annotation {
fn from(v: $T) -> Self {
$AnnotationEnum::$Variant(v).into()
}
}
impl crate::annotations::IntoAnnotations for $T {
type IntoAnnotations = [crate::annotations::Annotation; 1];
fn into_annotations(self) -> Self::IntoAnnotations {
[self.into()]
}
}
impl crate::annotations::IntoAnnotations for &'_ $T {
type IntoAnnotations = [crate::annotations::Annotation; 1];
fn into_annotations(self) -> Self::IntoAnnotations {
[crate::annotations::Annotation::from(self.clone())]
}
}
impl crate::annotations::IntoAnnotations for &'_ mut $T {
type IntoAnnotations = [crate::annotations::Annotation; 1];
fn into_annotations(self) -> Self::IntoAnnotations {
[crate::annotations::Annotation::from(self.clone())]
}
}
impl crate::annotations::IntoAnnotations for Box<$T> {
type IntoAnnotations = [crate::annotations::Annotation; 1];
fn into_annotations(self) -> Self::IntoAnnotations {
[crate::annotations::Annotation::from(*self)]
}
})*
};
(@require_non_exhaustive non_exhaustive) => {};
}
pub(crate) use make_annotation_enum;
make_annotation_enum! {
#[non_exhaustive]
pub enum Annotation {
DontTouch(DontTouchAnnotation),
SVAttribute(SVAttributeAnnotation),
BlackBoxInline(BlackBoxInlineAnnotation),
BlackBoxPath(BlackBoxPathAnnotation),
DocString(DocStringAnnotation),
CustomFirrtl(CustomFirrtlAnnotation),
Xilinx(crate::vendor::xilinx::XilinxAnnotation),
}
}
#[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,
}
}
}