use std::collections::HashMap;
use codespan::{FileId, Span};
use indexmap::IndexMap;
pub type RawIdentifier = string_interner::DefaultSymbol;
pub type Interner = string_interner::StringInterner;
#[derive(Copy, Clone, Debug)]
pub struct Identifier {
pub span: Span,
pub value: RawIdentifier,
}
pub struct Schema {
pub file_id: FileId,
pub docstrings: Docstrings,
pub native_includes: Vec<StringLiteral>,
pub includes: Vec<StringLiteral>,
pub namespace: Option<(Span, NamespacePath)>,
pub root_type: Option<(Span, Type)>,
pub file_extension: Option<(Span, StringLiteral)>,
pub file_identifier: Option<(Span, StringLiteral)>,
pub attributes: Vec<Attribute>,
pub type_declarations: IndexMap<RawIdentifier, Declaration>,
}
impl Schema {
pub fn new(file_id: FileId, location: String) -> Self {
Self {
file_id,
docstrings: Docstrings::new(Some(location)),
namespace: Default::default(),
native_includes: Default::default(),
includes: Default::default(),
root_type: Default::default(),
file_extension: Default::default(),
file_identifier: Default::default(),
attributes: Default::default(),
type_declarations: Default::default(),
}
}
}
pub struct Attribute {
pub span: Span,
pub kind: AttributeKind,
}
pub enum AttributeKind {
Identifier(RawIdentifier),
String(String),
}
#[derive(Clone)]
pub struct Declaration {
pub file_id: FileId,
pub full_span: Span,
pub definition_span: Span,
pub identifier: Identifier,
pub kind: TypeDeclarationKind,
pub docstrings: Docstrings,
}
#[derive(Clone)]
pub enum TypeDeclarationKind {
Table(Struct),
Struct(Struct),
Enum(Enum),
Union(Union),
RpcService(RpcService),
}
#[derive(Clone, Debug, Default)]
pub struct MetadataMap {
pub seen: HashMap<MetadataValueKindKey, Span>,
pub values: Vec<MetadataValue>,
}
#[derive(Clone)]
pub struct Struct {
pub metadata: MetadataMap,
pub fields: IndexMap<RawIdentifier, StructField>,
}
#[derive(Clone, Debug)]
pub struct StructField {
pub span: Span,
pub ident: Identifier,
pub type_: Type,
pub assignment: Option<Literal>,
pub metadata: MetadataMap,
pub docstrings: Docstrings,
}
#[derive(Clone)]
pub struct Enum {
pub metadata: MetadataMap,
pub type_: IntegerType,
pub type_span: Span,
pub variants: IndexMap<RawIdentifier, EnumVariant>,
}
#[derive(Clone)]
pub struct EnumVariant {
pub span: Span,
pub ident: Identifier,
pub value: Option<IntegerLiteral>,
pub docstrings: Docstrings,
}
#[derive(Clone)]
pub struct Union {
pub metadata: MetadataMap,
pub variants: IndexMap<UnionKey, UnionVariant>,
}
#[derive(Clone, Debug)]
pub enum UnionKey {
Identifier(RawIdentifier),
Type(Type),
}
impl PartialEq for UnionKey {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(UnionKey::Identifier(i0), UnionKey::Identifier(i1)) => i0 == i1,
(UnionKey::Type(t0), UnionKey::Type(t1)) => t0.eq_unspanned(t1),
_ => false,
}
}
}
impl Eq for UnionKey {}
impl std::hash::Hash for UnionKey {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
std::hash::Hash::hash(&std::mem::discriminant(self), state);
match self {
UnionKey::Identifier(i) => i.hash(state),
UnionKey::Type(t) => t.hash_unspanned(state),
}
}
}
#[derive(Clone)]
pub struct UnionVariant {
pub span: Span,
pub ident: Option<Identifier>,
pub type_: Type,
pub docstrings: Docstrings,
}
#[derive(Clone)]
pub struct RpcService {
pub methods: IndexMap<RawIdentifier, RpcMethod>,
}
#[derive(Clone)]
pub struct RpcMethod {
pub span: Span,
pub ident: Identifier,
pub argument_type: Type,
pub return_type: Type,
pub metadata: MetadataMap,
pub docstrings: Docstrings,
}
#[derive(Clone, Debug)]
pub struct MetadataValue {
pub span: Span,
pub kind: MetadataValueKind,
}
#[derive(Clone, Debug)]
pub enum MetadataValueKind {
ForceAlign(IntegerLiteral),
BitFlags,
CsharpPartial,
Private,
NativeType(StringLiteral),
NativeTypePackName(StringLiteral),
OriginalOrder,
Required,
Deprecated,
Key,
Shared,
NestedFlatbuffer(StringLiteral),
Id(IntegerLiteral),
Hash(StringLiteral),
CppType(StringLiteral),
CppPtrType(StringLiteral),
CppPtrTypeGet(StringLiteral),
CppStrType(StringLiteral),
CppStrFlexCtor,
NativeInline,
NativeDefault(StringLiteral),
Flexbuffer,
Streaming(StringLiteral),
Idempotent,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum MetadataValueKindKey {
ForceAlign,
BitFlags,
CsharpPartial,
Private,
NativeType,
NativeTypePackName,
OriginalOrder,
Required,
Deprecated,
Key,
Shared,
NestedFlatbuffer,
Id,
Hash,
CppType,
CppPtrType,
CppPtrTypeGet,
CppStrType,
CppStrFlexCtor,
NativeInline,
NativeDefault,
Flexbuffer,
Streaming,
Idempotent,
}
impl MetadataValueKindKey {
pub fn parse(s: &str) -> Option<MetadataValueKindKey> {
match s {
"force_align" => Some(Self::ForceAlign),
"bit_flags" => Some(Self::BitFlags),
"csharp_partial" => Some(Self::CsharpPartial),
"private" => Some(Self::Private),
"native_type" => Some(Self::NativeType),
"native_type_pack_name" => Some(Self::NativeTypePackName),
"original_order" => Some(Self::OriginalOrder),
"required" => Some(Self::Required),
"deprecated" => Some(Self::Deprecated),
"key" => Some(Self::Key),
"shared" => Some(Self::Shared),
"nested_flatbuffer" => Some(Self::NestedFlatbuffer),
"id" => Some(Self::Id),
"hash" => Some(Self::Hash),
"cpp_type" => Some(Self::CppType),
"cpp_ptr_type" => Some(Self::CppPtrType),
"cpp_ptr_type_get" => Some(Self::CppPtrTypeGet),
"cpp_str_type" => Some(Self::CppStrType),
"cpp_str_flex_ctor" => Some(Self::CppStrFlexCtor),
"native_inline" => Some(Self::NativeInline),
"native_default" => Some(Self::NativeDefault),
"flexbuffer" => Some(Self::Flexbuffer),
"streaming" => Some(Self::Streaming),
"idempotent" => Some(Self::Idempotent),
_ => None,
}
}
pub fn requirement(&self) -> &'static str {
match self {
Self::BitFlags
| Self::CsharpPartial
| Self::Private
| Self::OriginalOrder
| Self::Required
| Self::Deprecated
| Self::Key
| Self::Shared
| Self::CppStrFlexCtor
| Self::NativeInline
| Self::Flexbuffer
| Self::Idempotent => "should not have an argument",
Self::ForceAlign | Self::Id => "should have an integer argument",
Self::NativeType
| Self::NativeTypePackName
| Self::NestedFlatbuffer
| Self::Hash
| Self::CppType
| Self::CppPtrType
| Self::CppPtrTypeGet
| Self::CppStrType
| Self::NativeDefault
| Self::Streaming => "should have a string argument",
}
}
}
impl MetadataValueKind {
pub fn is_supported(&self) -> bool {
matches!(
self,
Self::ForceAlign(_) | Self::Required | Self::Deprecated | Self::Id(_)
)
}
pub fn accepted_on_enums(&self) -> bool {
matches!(self, Self::BitFlags | Self::CsharpPartial | Self::Private)
}
pub fn accepted_on_structs(&self) -> bool {
matches!(
self,
Self::ForceAlign(_)
| Self::CsharpPartial
| Self::Private
| Self::NativeType(_)
| Self::NativeTypePackName(_)
)
}
pub fn accepted_on_tables(&self) -> bool {
matches!(
self,
Self::CsharpPartial
| Self::Private
| Self::NativeType(_)
| Self::NativeTypePackName(_)
| Self::OriginalOrder
)
}
pub fn accepted_on_unions(&self) -> bool {
matches!(
self,
Self::CsharpPartial | Self::Private | Self::NativeType(_) | Self::NativeTypePackName(_)
)
}
pub fn accepted_on_rpc_services(&self) -> bool {
matches!(self, Self::Private)
}
pub fn accepted_on_struct_fields(&self) -> bool {
matches!(
self,
Self::Key
| Self::Hash(_)
| Self::CppType(_)
| Self::CppPtrType(_)
| Self::CppPtrTypeGet(_)
| Self::NativeInline
| Self::NativeDefault(_)
)
}
pub fn accepted_on_table_fields(&self) -> bool {
matches!(
self,
Self::ForceAlign(_)
| Self::Required
| Self::Deprecated
| Self::Key
| Self::Shared
| Self::NestedFlatbuffer(_)
| Self::Id(_)
| Self::Hash(_)
| Self::CppType(_)
| Self::CppPtrType(_)
| Self::CppPtrTypeGet(_)
| Self::CppStrType(_)
| Self::CppStrFlexCtor
| Self::NativeInline
| Self::NativeDefault(_)
| Self::Flexbuffer
)
}
pub fn accepted_on_rpc_methods(&self) -> bool {
matches!(self, Self::Streaming(_) | Self::Idempotent)
}
}
#[derive(Clone, Debug)]
pub struct NamespacePath {
pub span: Span,
pub parts: Vec<RawIdentifier>,
}
#[derive(Clone, Debug)]
pub struct Type {
pub span: Span,
pub kind: TypeKind,
}
impl Type {
pub fn hash_unspanned<H>(&self, state: &mut H)
where
H: std::hash::Hasher,
{
self.kind.hash_unspanned(state);
}
pub fn eq_unspanned(&self, other: &Self) -> bool {
self.kind.eq_unspanned(&other.kind)
}
}
#[derive(Clone, Debug)]
pub enum TypeKind {
Builtin(BuiltinType),
Vector { inner_type: Box<Type> },
Array { inner_type: Box<Type>, size: u32 },
Path(NamespacePath),
Invalid,
}
impl TypeKind {
pub fn hash_unspanned<H>(&self, state: &mut H)
where
H: std::hash::Hasher,
{
std::hash::Hash::hash(&std::mem::discriminant(self), state);
match self {
TypeKind::Builtin(t) => std::hash::Hash::hash(t, state),
TypeKind::Vector { inner_type } => inner_type.hash_unspanned(state),
TypeKind::Array { inner_type, size } => {
inner_type.hash_unspanned(state);
std::hash::Hash::hash(size, state);
}
TypeKind::Path(path) => {
std::hash::Hash::hash(&path.parts, state);
}
TypeKind::Invalid => (),
}
}
pub fn eq_unspanned(&self, other: &Self) -> bool {
match (self, other) {
(TypeKind::Builtin(t0), TypeKind::Builtin(t1)) => t0 == t1,
(TypeKind::Vector { inner_type: t0 }, TypeKind::Vector { inner_type: t1 }) => {
t0.eq_unspanned(t1)
}
(
TypeKind::Array {
inner_type: t0,
size: s0,
},
TypeKind::Array {
inner_type: t1,
size: s1,
},
) => s0 == s1 && t0.eq_unspanned(t1),
(TypeKind::Path(p0), TypeKind::Path(p1)) => p0.parts == p1.parts,
(TypeKind::Invalid, TypeKind::Invalid) => true,
_ => false,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum BuiltinType {
Bool,
Integer(IntegerType),
Float(FloatType),
String,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum IntegerType {
U8,
U16,
U32,
U64,
I8,
I16,
I32,
I64,
}
impl IntegerType {
pub fn byte_size(&self) -> u32 {
match self {
IntegerType::U8 => 1,
IntegerType::I8 => 1,
IntegerType::U16 => 2,
IntegerType::I16 => 2,
IntegerType::U32 => 4,
IntegerType::I32 => 4,
IntegerType::U64 => 8,
IntegerType::I64 => 8,
}
}
pub fn flatbuffer_name(&self) -> &'static str {
match self {
IntegerType::U8 => "uint8",
IntegerType::U16 => "uint16",
IntegerType::U32 => "uint32",
IntegerType::U64 => "uint64",
IntegerType::I8 => "int8",
IntegerType::I16 => "int16",
IntegerType::I32 => "int32",
IntegerType::I64 => "int64",
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum FloatType {
F32,
F64,
}
impl FloatType {
pub fn byte_size(&self) -> u32 {
match self {
FloatType::F32 => 4,
FloatType::F64 => 8,
}
}
pub fn flatbuffer_name(&self) -> &'static str {
match self {
FloatType::F32 => "float32",
FloatType::F64 => "float64",
}
}
}
#[derive(Clone, Debug)]
pub struct Literal {
pub span: Span,
pub kind: LiteralKind,
}
#[derive(Clone, Debug)]
pub enum LiteralKind {
Bool(bool),
Integer { is_negative: bool, value: String },
Float { is_negative: bool, value: String },
String(String),
List(Vec<Literal>),
Null,
Constant(String),
}
#[derive(Clone, Debug)]
pub struct IntegerLiteral {
pub span: Span,
pub is_negative: bool,
pub value: String,
}
#[derive(Clone, Debug)]
pub struct StringLiteral {
pub span: Span,
pub value: String,
}
#[derive(Clone, Debug)]
pub struct Docstrings {
pub docstrings: Vec<Docstring>,
pub default_docstring: String,
pub locations: Vec<String>,
}
#[derive(Clone, Debug)]
pub struct Docstring {
pub span: Span,
pub value: String,
}
impl Docstrings {
pub fn new(location: Option<String>) -> Self {
Self {
docstrings: Default::default(),
default_docstring: Default::default(),
locations: location.into_iter().collect(),
}
}
pub fn iter_strings(&self) -> impl Iterator<Item = &str> {
self.docstrings
.iter()
.map(|docstring| docstring.value.as_str())
.chain(
(self.docstrings.is_empty() && !self.default_docstring.is_empty())
.then_some(self.default_docstring.as_str()),
)
.chain(
(!self.locations.is_empty())
.then_some(
["", "Generated from these locations:"]
.into_iter()
.chain(self.locations.iter().map(|s| s.as_str())),
)
.into_iter()
.flatten(),
)
}
}