use prost_types::value::Kind;
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct DoubleValue {
pub value: f64,
}
#[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct FloatValue {
pub value: f32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Int64Value {
pub value: i64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct UInt64Value {
pub value: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Int32Value {
pub value: i32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct UInt32Value {
pub value: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct BoolValue {
pub value: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct StringValue {
pub value: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct BytesValue {
pub value: Vec<u8>,
}
pub trait WrapperExt<T> {
fn wrap(value: T) -> Self;
fn unwrap_value(&self) -> T;
}
impl WrapperExt<f64> for DoubleValue {
fn wrap(value: f64) -> Self {
DoubleValue { value }
}
fn unwrap_value(&self) -> f64 {
self.value
}
}
impl WrapperExt<f32> for FloatValue {
fn wrap(value: f32) -> Self {
FloatValue { value }
}
fn unwrap_value(&self) -> f32 {
self.value
}
}
impl WrapperExt<i64> for Int64Value {
fn wrap(value: i64) -> Self {
Int64Value { value }
}
fn unwrap_value(&self) -> i64 {
self.value
}
}
impl WrapperExt<u64> for UInt64Value {
fn wrap(value: u64) -> Self {
UInt64Value { value }
}
fn unwrap_value(&self) -> u64 {
self.value
}
}
impl WrapperExt<i32> for Int32Value {
fn wrap(value: i32) -> Self {
Int32Value { value }
}
fn unwrap_value(&self) -> i32 {
self.value
}
}
impl WrapperExt<u32> for UInt32Value {
fn wrap(value: u32) -> Self {
UInt32Value { value }
}
fn unwrap_value(&self) -> u32 {
self.value
}
}
impl WrapperExt<bool> for BoolValue {
fn wrap(value: bool) -> Self {
BoolValue { value }
}
fn unwrap_value(&self) -> bool {
self.value
}
}
impl WrapperExt<String> for StringValue {
fn wrap(value: String) -> Self {
StringValue { value }
}
fn unwrap_value(&self) -> String {
self.value.clone()
}
}
impl WrapperExt<Vec<u8>> for BytesValue {
fn wrap(value: Vec<u8>) -> Self {
BytesValue { value }
}
fn unwrap_value(&self) -> Vec<u8> {
self.value.clone()
}
}
pub trait ValueExt {
fn null() -> Self;
fn from_bool(b: bool) -> Self;
fn from_f64(n: f64) -> Self;
fn from_string(s: impl Into<String>) -> Self;
fn as_bool(&self) -> Option<bool>;
fn as_number(&self) -> Option<f64>;
fn as_string(&self) -> Option<&str>;
fn is_null(&self) -> bool;
}
impl ValueExt for prost_types::Value {
fn null() -> Self {
prost_types::Value {
kind: Some(Kind::NullValue(0)),
}
}
fn from_bool(b: bool) -> Self {
prost_types::Value {
kind: Some(Kind::BoolValue(b)),
}
}
fn from_f64(n: f64) -> Self {
prost_types::Value {
kind: Some(Kind::NumberValue(n)),
}
}
fn from_string(s: impl Into<String>) -> Self {
prost_types::Value {
kind: Some(Kind::StringValue(s.into())),
}
}
fn as_bool(&self) -> Option<bool> {
match &self.kind {
Some(Kind::BoolValue(b)) => Some(*b),
_ => None,
}
}
fn as_number(&self) -> Option<f64> {
match &self.kind {
Some(Kind::NumberValue(n)) => Some(*n),
_ => None,
}
}
fn as_string(&self) -> Option<&str> {
match &self.kind {
Some(Kind::StringValue(s)) => Some(s.as_str()),
_ => None,
}
}
fn is_null(&self) -> bool {
matches!(&self.kind, Some(Kind::NullValue(_)) | None)
}
}
pub trait StructExt {
fn empty() -> Self;
fn insert(&mut self, key: impl Into<String>, value: prost_types::Value);
fn get(&self, key: &str) -> Option<&prost_types::Value>;
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
}
impl StructExt for prost_types::Struct {
fn empty() -> Self {
prost_types::Struct {
fields: std::collections::BTreeMap::new(),
}
}
fn insert(&mut self, key: impl Into<String>, value: prost_types::Value) {
self.fields.insert(key.into(), value);
}
fn get(&self, key: &str) -> Option<&prost_types::Value> {
self.fields.get(key)
}
fn len(&self) -> usize {
self.fields.len()
}
fn is_empty(&self) -> bool {
self.fields.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn double_value_wrap_unwrap() {
let wrapped = DoubleValue::wrap(12.5);
assert!((wrapped.unwrap_value() - 12.5).abs() < f64::EPSILON);
}
#[test]
fn int64_value_wrap_unwrap() {
let wrapped = Int64Value::wrap(-42);
assert_eq!(wrapped.unwrap_value(), -42);
}
#[test]
fn bool_value_wrap_unwrap() {
assert!(BoolValue::wrap(true).unwrap_value());
assert!(!BoolValue::wrap(false).unwrap_value());
}
#[test]
fn string_value_wrap_unwrap() {
let wrapped = StringValue::wrap("hello".to_string());
assert_eq!(wrapped.unwrap_value(), "hello");
}
#[test]
fn bytes_value_wrap_unwrap() {
let wrapped = BytesValue::wrap(vec![1, 2, 3]);
assert_eq!(wrapped.unwrap_value(), vec![1, 2, 3]);
}
#[test]
fn value_null() {
let v = prost_types::Value::null();
assert!(v.is_null());
assert!(v.as_bool().is_none());
}
#[test]
fn value_bool() {
let v = prost_types::Value::from_bool(true);
assert_eq!(v.as_bool(), Some(true));
assert!(!v.is_null());
}
#[test]
fn value_number() {
let v = prost_types::Value::from_f64(42.0);
assert_eq!(v.as_number(), Some(42.0));
}
#[test]
fn value_string() {
let v = prost_types::Value::from_string("test");
assert_eq!(v.as_string(), Some("test"));
}
#[test]
fn struct_operations() {
let mut s = prost_types::Struct::empty();
assert!(s.is_empty());
s.insert("name", prost_types::Value::from_string("Alice"));
s.insert("age", prost_types::Value::from_f64(30.0));
assert_eq!(s.len(), 2);
assert!(!s.is_empty());
let name = s.get("name");
assert!(name.is_some());
assert_eq!(name.and_then(|v| v.as_string()), Some("Alice"));
assert!(s.get("missing").is_none());
}
}