353 lines
9.8 KiB
Rust
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,
|
|
}
|
|
}
|
|
}
|