about summary refs log tree commit diff
path: root/library/stdarch/crates/stdarch-gen-arm/src/matching.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/stdarch/crates/stdarch-gen-arm/src/matching.rs')
-rw-r--r--library/stdarch/crates/stdarch-gen-arm/src/matching.rs170
1 files changed, 170 insertions, 0 deletions
diff --git a/library/stdarch/crates/stdarch-gen-arm/src/matching.rs b/library/stdarch/crates/stdarch-gen-arm/src/matching.rs
new file mode 100644
index 00000000000..0c480620428
--- /dev/null
+++ b/library/stdarch/crates/stdarch-gen-arm/src/matching.rs
@@ -0,0 +1,170 @@
+use proc_macro2::TokenStream;
+use quote::ToTokens;
+use serde::{Deserialize, Serialize};
+use std::fmt;
+
+use crate::context::{self, LocalContext};
+use crate::typekinds::{BaseType, BaseTypeKind, TypeKind};
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(deny_unknown_fields)]
+pub struct MatchSizeValues<T> {
+    pub default: T,
+    pub byte: Option<T>,
+    pub halfword: Option<T>,
+    pub doubleword: Option<T>,
+}
+
+impl<T> MatchSizeValues<T> {
+    pub fn get(&mut self, ty: &TypeKind, ctx: &LocalContext) -> context::Result<&T> {
+        let base_ty = if let Some(w) = ty.wildcard() {
+            ctx.provide_type_wildcard(w)?
+        } else {
+            ty.clone()
+        };
+
+        if let BaseType::Sized(_, bitsize) = base_ty.base_type().unwrap() {
+            match (bitsize, &self.byte, &self.halfword, &self.doubleword) {
+                (64, _, _, Some(v)) | (16, _, Some(v), _) | (8, Some(v), _, _) => Ok(v),
+                _ => Ok(&self.default),
+            }
+        } else {
+            Err(format!("cannot match bitsize to unsized type {ty:?}!"))
+        }
+    }
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(deny_unknown_fields)]
+pub struct MatchKindValues<T> {
+    pub default: T,
+    pub float: Option<T>,
+    pub unsigned: Option<T>,
+}
+
+impl<T> MatchKindValues<T> {
+    pub fn get(&mut self, ty: &TypeKind, ctx: &LocalContext) -> context::Result<&T> {
+        let base_ty = if let Some(w) = ty.wildcard() {
+            ctx.provide_type_wildcard(w)?
+        } else {
+            ty.clone()
+        };
+
+        match (
+            base_ty.base_type().unwrap().kind(),
+            &self.float,
+            &self.unsigned,
+        ) {
+            (BaseTypeKind::Float, Some(v), _) | (BaseTypeKind::UInt, _, Some(v)) => Ok(v),
+            _ => Ok(&self.default),
+        }
+    }
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(untagged, deny_unknown_fields)]
+pub enum SizeMatchable<T> {
+    Matched(T),
+    Unmatched {
+        match_size: Option<TypeKind>,
+        #[serde(flatten)]
+        values: MatchSizeValues<Box<T>>,
+    },
+}
+
+impl<T: Clone> SizeMatchable<T> {
+    pub fn perform_match(&mut self, ctx: &LocalContext) -> context::Result {
+        match self {
+            Self::Unmatched {
+                match_size: None,
+                values: MatchSizeValues { default, .. },
+            } => *self = Self::Matched(*default.to_owned()),
+            Self::Unmatched {
+                match_size: Some(ty),
+                values,
+            } => *self = Self::Matched(*values.get(ty, ctx)?.to_owned()),
+            _ => {}
+        }
+        Ok(())
+    }
+}
+
+impl<T: fmt::Debug> AsRef<T> for SizeMatchable<T> {
+    fn as_ref(&self) -> &T {
+        if let SizeMatchable::Matched(v) = self {
+            v
+        } else {
+            panic!("no match for {self:?} was performed");
+        }
+    }
+}
+
+impl<T: fmt::Debug> AsMut<T> for SizeMatchable<T> {
+    fn as_mut(&mut self) -> &mut T {
+        if let SizeMatchable::Matched(v) = self {
+            v
+        } else {
+            panic!("no match for {self:?} was performed");
+        }
+    }
+}
+
+impl<T: fmt::Debug + ToTokens> ToTokens for SizeMatchable<T> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        self.as_ref().to_tokens(tokens)
+    }
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(untagged, deny_unknown_fields)]
+pub enum KindMatchable<T> {
+    Matched(T),
+    Unmatched {
+        match_kind: Option<TypeKind>,
+        #[serde(flatten)]
+        values: MatchKindValues<Box<T>>,
+    },
+}
+
+impl<T: Clone> KindMatchable<T> {
+    pub fn perform_match(&mut self, ctx: &LocalContext) -> context::Result {
+        match self {
+            Self::Unmatched {
+                match_kind: None,
+                values: MatchKindValues { default, .. },
+            } => *self = Self::Matched(*default.to_owned()),
+            Self::Unmatched {
+                match_kind: Some(ty),
+                values,
+            } => *self = Self::Matched(*values.get(ty, ctx)?.to_owned()),
+            _ => {}
+        }
+        Ok(())
+    }
+}
+
+impl<T: fmt::Debug> AsRef<T> for KindMatchable<T> {
+    fn as_ref(&self) -> &T {
+        if let KindMatchable::Matched(v) = self {
+            v
+        } else {
+            panic!("no match for {self:?} was performed");
+        }
+    }
+}
+
+impl<T: fmt::Debug> AsMut<T> for KindMatchable<T> {
+    fn as_mut(&mut self) -> &mut T {
+        if let KindMatchable::Matched(v) = self {
+            v
+        } else {
+            panic!("no match for {self:?} was performed");
+        }
+    }
+}
+
+impl<T: fmt::Debug + ToTokens> ToTokens for KindMatchable<T> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        self.as_ref().to_tokens(tokens)
+    }
+}