use bytes::Bytes;
use snafu::{ResultExt, Snafu};
use std::collections::{BTreeMap, HashMap};
mod api;
mod builder;
mod modify_api;
mod parse;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
struct InternalRef(usize);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MessageRef(InternalRef);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EnumRef(InternalRef);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PackageRef(InternalRef);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ServiceRef(InternalRef);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct OneofRef(InternalRef);
#[derive(Debug, Snafu)]
#[snafu(visibility(pub(crate)))]
#[non_exhaustive]
pub enum ParseError
{
#[snafu(display("Parsing error: {}", source))]
SyntaxError
{
source: Box<dyn std::error::Error + Send + Sync>,
},
#[snafu(display("Duplicate type: {}", name))]
DuplicateType
{
name: String,
},
#[snafu(display("Unknown type '{}' in '{}'", name, context))]
TypeNotFound
{
name: String,
context: String,
},
#[snafu(display(
"Invalid type '{}' ({:?}) for {}, expected {:?}",
type_name,
actual,
context,
expected
))]
InvalidTypeKind
{
type_name: String,
context: &'static str,
expected: ItemType,
actual: ItemType,
},
}
#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum InsertError
{
TypeExists
{
original: TypeRef,
},
}
#[derive(Debug)]
#[non_exhaustive]
pub enum MemberInsertError
{
NumberConflict,
NameConflict,
MissingOneof,
}
#[derive(Debug)]
#[non_exhaustive]
pub enum OneofInsertError
{
NameConflict,
FieldNotFound
{
field: u64,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TypeRef
{
Message(MessageRef),
Enum(EnumRef),
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ItemType
{
Message,
Enum,
Service,
}
#[derive(Default, Debug, PartialEq)]
pub struct Context
{
packages: Vec<Package>,
types: Vec<TypeInfo>,
types_by_name: HashMap<String, usize>,
services: Vec<Service>,
services_by_name: HashMap<String, usize>,
}
#[derive(Debug, PartialEq)]
pub struct Package
{
name: Option<String>,
self_ref: PackageRef,
types: Vec<TypeRef>,
services: Vec<usize>,
}
#[derive(Debug, PartialEq)]
pub enum TypeInfo
{
Message(MessageInfo),
Enum(EnumInfo),
}
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub struct MessageInfo
{
pub name: String,
pub full_name: String,
pub parent: TypeParent,
pub self_ref: MessageRef,
pub oneofs: Vec<Oneof>,
pub inner_types: Vec<TypeRef>,
fields: BTreeMap<u64, MessageField>,
fields_by_name: BTreeMap<String, u64>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TypeParent
{
Package(PackageRef),
Message(MessageRef),
}
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub struct EnumInfo
{
pub name: String,
pub full_name: String,
pub parent: TypeParent,
pub self_ref: EnumRef,
fields_by_value: BTreeMap<i64, EnumField>,
fields_by_name: BTreeMap<String, i64>,
}
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub struct MessageField
{
pub name: String,
pub number: u64,
pub field_type: ValueType,
pub multiplicity: Multiplicity,
pub options: Vec<ProtoOption>,
pub oneof: Option<OneofRef>,
}
#[derive(Debug, PartialEq, Clone)]
pub enum Multiplicity
{
Single,
Repeated,
RepeatedPacked,
Optional,
}
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub struct Oneof
{
pub name: String,
pub self_ref: OneofRef,
pub fields: Vec<u64>,
pub options: Vec<ProtoOption>,
}
#[derive(Debug, PartialEq, Clone)]
#[non_exhaustive]
pub struct EnumField
{
pub name: String,
pub value: i64,
pub options: Vec<ProtoOption>,
}
#[derive(Clone, Debug, PartialEq)]
pub enum ValueType
{
Double,
Float,
Int32,
Int64,
UInt32,
UInt64,
SInt32,
SInt64,
Fixed32,
Fixed64,
SFixed32,
SFixed64,
Bool,
String,
Bytes,
Message(MessageRef),
Enum(EnumRef),
}
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub struct Service
{
pub name: String,
pub full_name: String,
pub self_ref: ServiceRef,
pub parent: PackageRef,
pub rpcs: Vec<Rpc>,
pub options: Vec<ProtoOption>,
rpcs_by_name: HashMap<String, usize>,
}
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub struct Rpc
{
pub name: String,
pub input: RpcArg,
pub output: RpcArg,
pub options: Vec<ProtoOption>,
}
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub struct RpcArg
{
pub message: MessageRef,
pub stream: bool,
}
#[derive(Debug, PartialEq, Clone)]
pub struct ProtoOption
{
pub name: String,
pub value: Constant,
}
#[derive(Debug, PartialEq, Clone)]
pub enum Constant
{
Ident(String),
Integer(i64),
Float(f64),
String(Bytes),
Bool(bool),
}
#[cfg(test)]
mod test
{
use super::*;
#[test]
fn basic_package()
{
let ctx = Context::parse(&[r#"
syntax = "proto3";
message Message {}
"#])
.unwrap();
let m = ctx.get_message("Message").unwrap();
assert_eq!(m.parent, TypeParent::Package(PackageRef(InternalRef(0))));
}
#[test]
fn basic_multiple_package()
{
let ctx = Context::parse(&[
r#"
syntax = "proto3";
package First;
message Message {}
"#,
r#"
syntax = "proto3";
package Second;
message Message {}
"#,
])
.unwrap();
let m = ctx.get_message("First.Message").unwrap();
let pkg_ref = match m.parent {
TypeParent::Package(p) => p,
_ => panic!("Not a package reference: {:?}", m.parent),
};
let pkg = ctx.resolve_package(pkg_ref);
assert_eq!(m.parent, TypeParent::Package(PackageRef(InternalRef(0))));
assert_eq!(pkg.name.as_deref(), Some("First"));
assert_eq!(pkg.types.len(), 1);
let m = ctx.get_message("Second.Message").unwrap();
let pkg_ref = match m.parent {
TypeParent::Package(p) => p,
_ => panic!("Not a package reference: {:?}", m.parent),
};
let pkg = ctx.resolve_package(pkg_ref);
assert_eq!(m.parent, TypeParent::Package(PackageRef(InternalRef(1))));
assert_eq!(pkg.name.as_deref(), Some("Second"));
assert_eq!(pkg.types.len(), 1);
}
}