use std::collections::HashMap;
use buffa::bytes::Bytes;
use crate::{
dynamic::message::DynamicMessage,
field::{FieldDescriptor, Kind},
};
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
Bool(bool),
I32(i32),
I64(i64),
U32(u32),
U64(u64),
F32(f32),
F64(f64),
String(String),
Bytes(Bytes),
EnumNumber(i32),
Message(DynamicMessage),
List(Vec<Value>),
Map(HashMap<MapKey, Value>),
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum MapKey {
Bool(bool),
I32(i32),
I64(i64),
U32(u32),
U64(u64),
String(String),
}
#[derive(Clone, Debug, PartialEq, thiserror::Error)]
pub enum SetFieldError {
#[error("field not found")]
NotFound,
#[error("invalid value for field `{}`", field.full_name())]
InvalidType {
field: FieldDescriptor,
value: Box<Value>,
},
}
impl Value {
#[must_use]
pub fn default_value(kind: &Kind) -> Self {
match kind {
Kind::Bool => Value::Bool(false),
Kind::Int32 | Kind::Sint32 | Kind::Sfixed32 => Value::I32(0),
Kind::Int64 | Kind::Sint64 | Kind::Sfixed64 => Value::I64(0),
Kind::Uint32 | Kind::Fixed32 => Value::U32(0),
Kind::Uint64 | Kind::Fixed64 => Value::U64(0),
Kind::Float => Value::F32(0.0),
Kind::Double => Value::F64(0.0),
Kind::String => Value::String(String::new()),
Kind::Bytes => Value::Bytes(Bytes::new()),
Kind::Enum(_) => Value::EnumNumber(0),
Kind::Message(m) => Value::Message(DynamicMessage::new(m.clone())),
}
}
#[must_use]
pub fn default_value_for_field(field: &FieldDescriptor) -> Self {
if field.is_list() {
return Value::List(Vec::new());
}
if field.is_map() {
return Value::Map(HashMap::new());
}
if let Some(value) = field.parsed_default_value() {
return value;
}
Value::default_value(&field.kind())
}
#[must_use]
pub fn is_default(&self, kind: &Kind) -> bool {
match (self, kind) {
(Value::Bool(b), Kind::Bool) => !*b,
(Value::I32(v), Kind::Int32 | Kind::Sint32 | Kind::Sfixed32) => *v == 0,
(Value::I64(v), Kind::Int64 | Kind::Sint64 | Kind::Sfixed64) => *v == 0,
(Value::U32(v), Kind::Uint32 | Kind::Fixed32) => *v == 0,
(Value::U64(v), Kind::Uint64 | Kind::Fixed64) => *v == 0,
(Value::F32(v), Kind::Float) => *v == 0.0,
(Value::F64(v), Kind::Double) => *v == 0.0,
(Value::String(s), Kind::String) => s.is_empty(),
(Value::Bytes(b), Kind::Bytes) => b.is_empty(),
(Value::EnumNumber(n), Kind::Enum(_)) => *n == 0,
(Value::Message(m), Kind::Message(_)) => m.is_empty(),
(Value::List(l), _) => l.is_empty(),
(Value::Map(m), _) => m.is_empty(),
_ => false,
}
}
#[must_use]
pub fn is_valid_for_field(&self, field: &FieldDescriptor) -> bool {
if field.is_list() {
if let Value::List(items) = self {
let kind = field.kind();
return items.iter().all(|v| value_matches_kind(v, &kind));
}
return false;
}
if field.is_map() {
if let Value::Map(entries) = self {
let (key_kind, value_kind) = match map_entry_kinds(field) {
Some(kinds) => kinds,
None => return false,
};
return entries.iter().all(|(k, v)| {
map_key_matches_kind(k, &key_kind) && value_matches_kind(v, &value_kind)
});
}
return false;
}
value_matches_kind(self, &field.kind())
}
#[must_use]
pub fn as_bool(&self) -> Option<bool> {
match self {
Value::Bool(v) => Some(*v),
_ => None,
}
}
#[must_use]
pub fn as_i32(&self) -> Option<i32> {
match self {
Value::I32(v) => Some(*v),
_ => None,
}
}
#[must_use]
pub fn as_i64(&self) -> Option<i64> {
match self {
Value::I64(v) => Some(*v),
_ => None,
}
}
#[must_use]
pub fn as_u32(&self) -> Option<u32> {
match self {
Value::U32(v) => Some(*v),
_ => None,
}
}
#[must_use]
pub fn as_u64(&self) -> Option<u64> {
match self {
Value::U64(v) => Some(*v),
_ => None,
}
}
#[must_use]
pub fn as_f32(&self) -> Option<f32> {
match self {
Value::F32(v) => Some(*v),
_ => None,
}
}
#[must_use]
pub fn as_f64(&self) -> Option<f64> {
match self {
Value::F64(v) => Some(*v),
_ => None,
}
}
#[must_use]
pub fn as_str(&self) -> Option<&str> {
match self {
Value::String(v) => Some(v.as_str()),
_ => None,
}
}
#[must_use]
pub fn as_bytes(&self) -> Option<&Bytes> {
match self {
Value::Bytes(v) => Some(v),
_ => None,
}
}
#[must_use]
pub fn as_enum_number(&self) -> Option<i32> {
match self {
Value::EnumNumber(v) => Some(*v),
_ => None,
}
}
#[must_use]
pub fn as_message(&self) -> Option<&DynamicMessage> {
match self {
Value::Message(v) => Some(v),
_ => None,
}
}
pub fn as_message_mut(&mut self) -> Option<&mut DynamicMessage> {
match self {
Value::Message(v) => Some(v),
_ => None,
}
}
#[must_use]
pub fn as_list(&self) -> Option<&[Value]> {
match self {
Value::List(v) => Some(v.as_slice()),
_ => None,
}
}
pub fn as_list_mut(&mut self) -> Option<&mut Vec<Value>> {
match self {
Value::List(v) => Some(v),
_ => None,
}
}
#[must_use]
pub fn as_map(&self) -> Option<&HashMap<MapKey, Value>> {
match self {
Value::Map(v) => Some(v),
_ => None,
}
}
pub fn as_map_mut(&mut self) -> Option<&mut HashMap<MapKey, Value>> {
match self {
Value::Map(v) => Some(v),
_ => None,
}
}
}
impl MapKey {
#[must_use]
pub fn default_value(kind: &Kind) -> Self {
match kind {
Kind::Bool => MapKey::Bool(false),
Kind::Int32 | Kind::Sint32 | Kind::Sfixed32 => MapKey::I32(0),
Kind::Int64 | Kind::Sint64 | Kind::Sfixed64 => MapKey::I64(0),
Kind::Uint32 | Kind::Fixed32 => MapKey::U32(0),
Kind::Uint64 | Kind::Fixed64 => MapKey::U64(0),
Kind::String => MapKey::String(String::new()),
other => panic!("invalid map-key kind: {other:?}"),
}
}
}
pub(crate) fn value_matches_kind(value: &Value, kind: &Kind) -> bool {
match (value, kind) {
(Value::Bool(_), Kind::Bool) => true,
(Value::I32(_), Kind::Int32 | Kind::Sint32 | Kind::Sfixed32) => true,
(Value::I64(_), Kind::Int64 | Kind::Sint64 | Kind::Sfixed64) => true,
(Value::U32(_), Kind::Uint32 | Kind::Fixed32) => true,
(Value::U64(_), Kind::Uint64 | Kind::Fixed64) => true,
(Value::F32(_), Kind::Float) => true,
(Value::F64(_), Kind::Double) => true,
(Value::String(_), Kind::String) => true,
(Value::Bytes(_), Kind::Bytes) => true,
(Value::EnumNumber(_), Kind::Enum(_)) => true,
(Value::Message(m), Kind::Message(d)) => m.descriptor().full_name() == d.full_name(),
_ => false,
}
}
pub(crate) fn map_key_matches_kind(key: &MapKey, kind: &Kind) -> bool {
matches!(
(key, kind),
(MapKey::Bool(_), Kind::Bool)
| (MapKey::I32(_), Kind::Int32 | Kind::Sint32 | Kind::Sfixed32)
| (MapKey::I64(_), Kind::Int64 | Kind::Sint64 | Kind::Sfixed64)
| (MapKey::U32(_), Kind::Uint32 | Kind::Fixed32)
| (MapKey::U64(_), Kind::Uint64 | Kind::Fixed64)
| (MapKey::String(_), Kind::String)
)
}
pub(crate) fn map_entry_kinds(field: &FieldDescriptor) -> Option<(Kind, Kind)> {
let Kind::Message(entry) = field.kind() else {
return None;
};
if !entry.is_map_entry() {
return None;
}
let key = entry.get_field_by_number(1)?.kind();
let value = entry.get_field_by_number(2)?.kind();
Some((key, value))
}
impl From<bool> for Value {
fn from(v: bool) -> Self {
Value::Bool(v)
}
}
impl From<i32> for Value {
fn from(v: i32) -> Self {
Value::I32(v)
}
}
impl From<i64> for Value {
fn from(v: i64) -> Self {
Value::I64(v)
}
}
impl From<u32> for Value {
fn from(v: u32) -> Self {
Value::U32(v)
}
}
impl From<u64> for Value {
fn from(v: u64) -> Self {
Value::U64(v)
}
}
impl From<f32> for Value {
fn from(v: f32) -> Self {
Value::F32(v)
}
}
impl From<f64> for Value {
fn from(v: f64) -> Self {
Value::F64(v)
}
}
impl From<String> for Value {
fn from(v: String) -> Self {
Value::String(v)
}
}
impl From<&str> for Value {
fn from(v: &str) -> Self {
Value::String(v.to_owned())
}
}
impl From<Bytes> for Value {
fn from(v: Bytes) -> Self {
Value::Bytes(v)
}
}
impl From<Vec<u8>> for Value {
fn from(v: Vec<u8>) -> Self {
Value::Bytes(Bytes::from(v))
}
}
impl From<DynamicMessage> for Value {
fn from(v: DynamicMessage) -> Self {
Value::Message(v)
}
}