use crate::patterns::TypePattern;
use crate::util::{ctypes_from_type_recursive, IdPrettifier};
use std::collections::HashSet;
use std::hash::{Hash, Hasher};
#[derive(Clone, Debug, PartialOrd, PartialEq)]
pub enum PrimitiveValue {
Bool(bool),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
I8(i8),
I16(i16),
I32(i32),
I64(i64),
F32(f32),
F64(f64),
}
#[derive(Clone, Debug, PartialOrd, PartialEq)]
pub enum ConstantValue {
Primitive(PrimitiveValue),
}
impl ConstantValue {
pub(crate) fn fucking_hash_it_already<H: Hasher>(&self, h: &mut H) {
match self {
ConstantValue::Primitive(x) => match x {
PrimitiveValue::Bool(x) => x.hash(h),
PrimitiveValue::U8(x) => x.hash(h),
PrimitiveValue::U16(x) => x.hash(h),
PrimitiveValue::U32(x) => x.hash(h),
PrimitiveValue::U64(x) => x.hash(h),
PrimitiveValue::I8(x) => x.hash(h),
PrimitiveValue::I16(x) => x.hash(h),
PrimitiveValue::I32(x) => x.hash(h),
PrimitiveValue::I64(x) => x.hash(h),
PrimitiveValue::F32(x) => x.to_le_bytes().hash(h),
PrimitiveValue::F64(x) => x.to_le_bytes().hash(h),
},
}
}
}
#[derive(Clone, Debug, PartialOrd, PartialEq)]
pub struct Constant {
name: String,
value: ConstantValue,
meta: Meta,
}
impl Constant {
pub fn new(name: String, value: ConstantValue, meta: Meta) -> Self {
Self { name, value, meta }
}
pub fn name(&self) -> &str {
&self.name
}
pub fn value(&self) -> &ConstantValue {
&self.value
}
pub fn meta(&self) -> &Meta {
&self.meta
}
pub fn the_type(&self) -> CType {
match &self.value {
ConstantValue::Primitive(x) => CType::Primitive(match x {
PrimitiveValue::Bool(_) => PrimitiveType::Bool,
PrimitiveValue::U8(_) => PrimitiveType::U8,
PrimitiveValue::U16(_) => PrimitiveType::U16,
PrimitiveValue::U32(_) => PrimitiveType::U32,
PrimitiveValue::U64(_) => PrimitiveType::U64,
PrimitiveValue::I8(_) => PrimitiveType::I8,
PrimitiveValue::I16(_) => PrimitiveType::I16,
PrimitiveValue::I32(_) => PrimitiveType::I32,
PrimitiveValue::I64(_) => PrimitiveType::I64,
PrimitiveValue::F32(_) => PrimitiveType::F32,
PrimitiveValue::F64(_) => PrimitiveType::F64,
}),
}
}
}
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub enum CType {
Primitive(PrimitiveType),
Array(ArrayType),
Enum(EnumType),
Opaque(OpaqueType),
Composite(CompositeType),
FnPointer(FnPointerType),
ReadPointer(Box<CType>),
ReadWritePointer(Box<CType>),
Pattern(TypePattern),
}
impl Default for CType {
fn default() -> Self {
Self::Primitive(PrimitiveType::Void)
}
}
impl CType {
pub fn size_of(&self) -> usize {
match self {
CType::Primitive(p) => match p {
PrimitiveType::Void => 0,
PrimitiveType::Bool => 1,
PrimitiveType::U8 => 1,
PrimitiveType::U16 => 2,
PrimitiveType::U32 => 4,
PrimitiveType::U64 => 8,
PrimitiveType::I8 => 1,
PrimitiveType::I16 => 2,
PrimitiveType::I32 => 4,
PrimitiveType::I64 => 8,
PrimitiveType::F32 => 4,
PrimitiveType::F64 => 8,
},
_ => 999,
}
}
pub fn align_of(&self) -> usize {
unimplemented!()
}
pub const fn void() -> Self {
Self::Primitive(PrimitiveType::Void)
}
pub fn name_within_lib(&self) -> String {
match self {
CType::Primitive(x) => x.rust_name().to_string(),
CType::Enum(x) => x.rust_name().to_string(),
CType::Opaque(x) => x.rust_name().to_string(),
CType::Composite(x) => x.rust_name().to_string(),
CType::FnPointer(x) => x.rust_name(),
CType::ReadPointer(x) => format!("*const {}", x.name_within_lib()),
CType::ReadWritePointer(x) => format!("*mut {}", x.name_within_lib()),
CType::Pattern(x) => match x {
TypePattern::Bool => "Bool".to_string(),
_ => x.fallback_type().name_within_lib(),
},
CType::Array(x) => x.rust_name(),
}
}
pub fn embedded_types(&self) -> Vec<CType> {
let mut hash_set: HashSet<CType> = HashSet::new();
ctypes_from_type_recursive(self, &mut hash_set);
hash_set.remove(self);
hash_set.iter().cloned().collect()
}
pub fn deref_pointer(&self) -> Option<&CType> {
match self {
CType::Primitive(_) => None,
CType::Enum(_) => None,
CType::Opaque(_) => None,
CType::Composite(_) => None,
CType::FnPointer(_) => None,
CType::ReadPointer(x) => Some(x.as_ref()),
CType::ReadWritePointer(x) => Some(x.as_ref()),
CType::Pattern(_) => None,
CType::Array(_) => None,
}
}
pub fn as_composite_type(&self) -> Option<&CompositeType> {
match self {
CType::Composite(x) => Some(x),
_ => None,
}
}
pub fn as_opaque_type(&self) -> Option<&OpaqueType> {
match self {
CType::Opaque(x) => Some(x),
_ => None,
}
}
pub fn is_void(&self) -> bool {
matches!(self, CType::Primitive(PrimitiveType::Void))
}
pub fn namespace(&self) -> Option<&str> {
match self {
CType::Array(t) => t.array_type().namespace(),
CType::Enum(t) => Some(t.meta.namespace()),
CType::Opaque(t) => Some(t.meta.namespace()),
CType::Composite(t) => Some(t.meta.namespace()),
CType::Pattern(TypePattern::NamedCallback(t)) => Some(t.meta().namespace()),
_ => None,
}
}
}
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub enum PrimitiveType {
Void,
Bool,
U8,
U16,
U32,
U64,
I8,
I16,
I32,
I64,
F32,
F64,
}
impl PrimitiveType {
pub fn rust_name(&self) -> &str {
match self {
PrimitiveType::Void => "()",
PrimitiveType::Bool => "bool",
PrimitiveType::U8 => "u8",
PrimitiveType::U16 => "u16",
PrimitiveType::U32 => "u32",
PrimitiveType::U64 => "u64",
PrimitiveType::I8 => "i8",
PrimitiveType::I16 => "i16",
PrimitiveType::I32 => "i32",
PrimitiveType::I64 => "i64",
PrimitiveType::F32 => "f32",
PrimitiveType::F64 => "f64",
}
}
}
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct ArrayType {
array_type: Box<CType>,
len: usize,
}
impl ArrayType {
pub fn new(array_type: CType, len: usize) -> Self {
Self {
array_type: Box::new(array_type),
len,
}
}
pub fn rust_name(&self) -> String {
format!("{}[{}]", self.array_type.name_within_lib(), self.len)
}
pub fn array_type(&self) -> &CType {
&self.array_type
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
}
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct EnumType {
name: String,
variants: Vec<Variant>,
meta: Meta,
}
impl EnumType {
pub fn new(name: String, variants: Vec<Variant>, meta: Meta) -> Self {
Self { name, variants, meta }
}
pub fn rust_name(&self) -> &str {
&self.name
}
pub fn variants(&self) -> &[Variant] {
&self.variants
}
pub fn variant_by_name(&self, name: &str) -> Option<Variant> {
self.variants.iter().find(|x| x.name == name).cloned()
}
pub fn meta(&self) -> &Meta {
&self.meta
}
}
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct Variant {
name: String,
value: usize,
documentation: Documentation,
}
impl Variant {
pub fn new(name: String, value: usize, documentation: Documentation) -> Self {
Self { name, value, documentation }
}
pub fn name(&self) -> &str {
&self.name
}
pub fn value(&self) -> usize {
self.value
}
pub fn documentation(&self) -> &Documentation {
&self.documentation
}
}
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct CompositeType {
name: String,
fields: Vec<Field>,
meta: Meta,
}
impl CompositeType {
pub fn new(name: String, fields: Vec<Field>) -> Self {
Self::with_meta(name, fields, Meta::new())
}
pub fn with_meta(name: String, fields: Vec<Field>, meta: Meta) -> Self {
Self { name, fields, meta }
}
pub fn rust_name(&self) -> &str {
&self.name
}
pub fn fields(&self) -> &[Field] {
&self.fields
}
pub fn is_empty(&self) -> bool {
self.fields.is_empty()
}
pub fn meta(&self) -> &Meta {
&self.meta
}
}
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub enum Visibility {
Public,
Private,
}
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct Field {
name: String,
visibility: Visibility,
the_type: CType,
documentation: Documentation,
}
impl Field {
pub fn new(name: String, the_type: CType) -> Self {
Self::with_documentation(name, the_type, Visibility::Public, Documentation::new())
}
pub fn with_documentation(name: String, the_type: CType, visibility: Visibility, documentation: Documentation) -> Self {
Self {
name,
visibility,
the_type,
documentation,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn the_type(&self) -> &CType {
&self.the_type
}
pub fn visibility(&self) -> &Visibility {
&self.visibility
}
pub fn documentation(&self) -> &Documentation {
&self.documentation
}
}
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct OpaqueType {
name: String,
meta: Meta,
}
impl OpaqueType {
pub fn new(name: String, meta: Meta) -> Self {
Self { name, meta }
}
pub fn rust_name(&self) -> &str {
&self.name
}
pub fn meta(&self) -> &Meta {
&self.meta
}
}
#[derive(Clone, Debug, Default, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct Meta {
documentation: Documentation,
namespace: String,
alignment: Option<usize>,
}
impl Meta {
pub fn new() -> Self {
Self::default()
}
pub fn with_namespace_documentation(namespace: String, documentation: Documentation, alignment: Option<usize>) -> Self {
Self {
documentation,
namespace,
alignment,
}
}
pub fn with_documentation(documentation: Documentation, alignment: Option<usize>) -> Self {
Self::with_namespace_documentation(String::new(), documentation, alignment)
}
pub fn documentation(&self) -> &Documentation {
&self.documentation
}
pub fn namespace(&self) -> &str {
&self.namespace
}
pub fn is_namespace(&self, namespace: &str) -> bool {
self.namespace == namespace
}
pub fn alignment(&self) -> Option<usize> {
self.alignment
}
}
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct Function {
name: String,
meta: Meta,
signature: FunctionSignature,
}
impl Function {
pub fn new(name: String, signature: FunctionSignature, meta: Meta) -> Self {
Self { name, meta, signature }
}
pub fn name(&self) -> &str {
&self.name
}
pub fn signature(&self) -> &FunctionSignature {
&self.signature
}
pub fn meta(&self) -> &Meta {
&self.meta
}
pub fn prettifier(&self) -> IdPrettifier {
IdPrettifier::from_rust_lower(self.name())
}
}
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Default)]
pub struct FunctionSignature {
params: Vec<Parameter>,
rval: CType,
}
impl FunctionSignature {
pub fn new(params: Vec<Parameter>, rval: CType) -> Self {
Self { params, rval }
}
pub fn params(&self) -> &[Parameter] {
&self.params
}
pub fn rval(&self) -> &CType {
&self.rval
}
}
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct Parameter {
name: String,
the_type: CType,
}
impl Parameter {
pub fn new(name: String, the_type: CType) -> Self {
Self { name, the_type }
}
pub fn name(&self) -> &str {
&self.name
}
pub fn the_type(&self) -> &CType {
&self.the_type
}
}
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct FnPointerType {
name: Option<String>,
signature: Box<FunctionSignature>,
}
impl FnPointerType {
pub fn new(signature: FunctionSignature) -> Self {
Self {
signature: Box::new(signature),
name: None,
}
}
pub fn new_named(signature: FunctionSignature, name: String) -> Self {
Self {
signature: Box::new(signature),
name: Some(name),
}
}
pub fn signature(&self) -> &FunctionSignature {
&self.signature
}
pub fn name(&self) -> Option<&str> {
self.name.as_deref()
}
pub fn internal_name(&self) -> String {
let signature = self.signature();
let params = signature.params.iter().map(|x| x.the_type().name_within_lib()).collect::<Vec<_>>().join(",");
let rval = signature.rval.name_within_lib();
format!("fn({}) -> {}", params, rval)
}
pub fn rust_name(&self) -> String {
self.name.clone().unwrap_or_else(|| self.internal_name())
}
}
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Default)]
pub struct Documentation {
lines: Vec<String>,
}
impl Documentation {
pub fn new() -> Self {
Self::default()
}
pub fn from_line(joined_line: &str) -> Self {
if joined_line.is_empty() {
Documentation::new()
} else {
Documentation {
lines: joined_line.split('\n').map(|x| x.to_string()).collect(),
}
}
}
pub fn from_lines(lines: Vec<String>) -> Self {
Documentation { lines }
}
pub fn lines(&self) -> &[String] {
&self.lines
}
}