use std::sync::Arc;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub enum Value {
Null,
Bool(bool),
Int(i64),
Float(f64),
Bytes(#[serde(with = "arc_bytes")] Arc<[u8]>),
Str(String),
Array(Vec<Value>),
Map(Vec<(Value, Value)>),
}
mod arc_bytes {
use std::sync::Arc;
use std::fmt;
use serde::de::{self, SeqAccess, Visitor};
use serde::{Deserializer, Serializer};
pub(super) fn serialize<S: Serializer>(
bytes: &Arc<[u8]>,
serializer: S,
) -> Result<S::Ok, S::Error> {
serde_bytes::serialize(&**bytes, serializer)
}
pub(super) fn deserialize<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Arc<[u8]>, D::Error> {
deserializer.deserialize_bytes(ArcBytesVisitor)
}
struct ArcBytesVisitor;
impl<'de> Visitor<'de> for ArcBytesVisitor {
type Value = Arc<[u8]>;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("bytes (MessagePack bin, or the legacy int array)")
}
fn visit_bytes<E: de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
Ok(Arc::from(v))
}
fn visit_borrowed_bytes<E: de::Error>(self, v: &'de [u8]) -> Result<Self::Value, E> {
Ok(Arc::from(v))
}
fn visit_byte_buf<E: de::Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
Ok(Arc::from(v))
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut bytes = Vec::with_capacity(seq.size_hint().unwrap_or(0));
while let Some(byte) = seq.next_element::<u8>()? {
bytes.push(byte);
}
Ok(Arc::from(bytes))
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
Ok(Arc::from(v.as_bytes()))
}
}
}
impl Value {
pub fn as_str(&self) -> Option<&str> {
match self {
Self::Str(s) => Some(s.as_str()),
_ => None,
}
}
pub fn as_bytes(&self) -> Option<&[u8]> {
match self {
Self::Bytes(b) => Some(b),
Self::Str(s) => Some(s.as_bytes()),
_ => None,
}
}
pub fn as_shared_bytes(&self) -> Option<&Arc<[u8]>> {
match self {
Self::Bytes(b) => Some(b),
_ => None,
}
}
pub fn into_shared_bytes(self) -> Option<Arc<[u8]>> {
match self {
Self::Bytes(b) => Some(b),
_ => None,
}
}
pub fn bytes(buffer: impl Into<Arc<[u8]>>) -> Self {
Self::Bytes(buffer.into())
}
pub fn as_int(&self) -> Option<i64> {
match self {
Self::Int(i) => Some(*i),
_ => None,
}
}
pub fn as_float(&self) -> Option<f64> {
match self {
Self::Float(f) => Some(*f),
Self::Int(i) => Some(*i as f64),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match self {
Self::Bool(b) => Some(*b),
_ => None,
}
}
pub fn as_array(&self) -> Option<&[Value]> {
match self {
Self::Array(items) => Some(items.as_slice()),
_ => None,
}
}
pub fn as_map(&self) -> Option<&[(Value, Value)]> {
match self {
Self::Map(pairs) => Some(pairs.as_slice()),
_ => None,
}
}
pub fn map_get(&self, key: &str) -> Option<&Value> {
self.as_map()?
.iter()
.find(|(k, _)| k.as_str() == Some(key))
.map(|(_, v)| v)
}
pub fn is_null(&self) -> bool {
matches!(self, Self::Null)
}
}
impl From<bool> for Value {
fn from(b: bool) -> Self {
Self::Bool(b)
}
}
impl From<i64> for Value {
fn from(i: i64) -> Self {
Self::Int(i)
}
}
impl From<f64> for Value {
fn from(f: f64) -> Self {
Self::Float(f)
}
}
impl From<String> for Value {
fn from(s: String) -> Self {
Self::Str(s)
}
}
impl From<&str> for Value {
fn from(s: &str) -> Self {
Self::Str(s.to_owned())
}
}
impl From<Vec<u8>> for Value {
fn from(b: Vec<u8>) -> Self {
Self::Bytes(Arc::from(b))
}
}
impl From<Arc<[u8]>> for Value {
fn from(b: Arc<[u8]>) -> Self {
Self::Bytes(b)
}
}
impl From<&[u8]> for Value {
fn from(b: &[u8]) -> Self {
Self::Bytes(Arc::from(b))
}
}
impl From<Vec<Value>> for Value {
fn from(items: Vec<Value>) -> Self {
Self::Array(items)
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Request {
pub id: u32,
pub command: String,
pub args: Vec<Value>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Response {
pub id: u32,
pub result: Result<Value, String>,
}
impl Response {
pub fn ok(id: u32, value: Value) -> Self {
Self {
id,
result: Ok(value),
}
}
pub fn err(id: u32, message: impl Into<String>) -> Self {
Self {
id,
result: Err(message.into()),
}
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod bytes_sharing_tests {
use super::*;
#[test]
fn bytes_are_shared_not_copied() {
let buffer: Arc<[u8]> = Arc::from(vec![7u8; 4096]);
let value = Value::from(Arc::clone(&buffer));
let taken = value.into_shared_bytes().unwrap();
assert_eq!(Arc::strong_count(&buffer), 2, "shared, not cloned");
assert!(
Arc::ptr_eq(&buffer, &taken),
"the very same allocation must come back out"
);
}
#[test]
fn a_stored_buffer_reaches_a_value_without_copying() {
let stored: Arc<[u8]> = Arc::from(vec![1u8, 2, 3]);
let value = Value::bytes(Arc::clone(&stored));
let inside = value.as_shared_bytes().unwrap();
assert!(Arc::ptr_eq(&stored, inside));
}
#[test]
fn sharing_does_not_change_the_wire() {
let value = Value::bytes(vec![1u8, 2, 3, 255]);
let encoded = rmp_serde::to_vec(&value).unwrap();
assert!(
encoded.contains(&0xc4),
"still emitted as bin, not an int array: {encoded:02x?}"
);
let decoded: Value = rmp_serde::from_slice(&encoded).unwrap();
assert_eq!(decoded, value);
}
}