use crate::rpc::protocol;
use serde::de::Error;
use serde::Deserialize;
use serde_json::{from_str, Result, Value};
use std::fmt;
use std::str::from_utf8;
#[derive(Debug, Clone)]
pub struct Blob(protocol::TypedData);
impl Blob {
pub fn as_str(&self) -> Option<&str> {
if self.0.has_string() {
return Some(self.0.get_string());
}
if self.0.has_json() {
return Some(self.0.get_json());
}
if self.0.has_bytes() {
return from_utf8(self.0.get_bytes()).map(|s| s).ok();
}
if self.0.has_stream() {
return from_utf8(self.0.get_stream()).map(|s| s).ok();
}
None
}
pub fn as_bytes(&self) -> &[u8] {
if self.0.has_string() {
return self.0.get_string().as_bytes();
}
if self.0.has_json() {
return self.0.get_json().as_bytes();
}
if self.0.has_bytes() {
return self.0.get_bytes();
}
if self.0.has_stream() {
return self.0.get_stream();
}
panic!("unexpected data for blob content");
}
pub fn as_json<'b, T>(&'b self) -> Result<T>
where
T: Deserialize<'b>,
{
from_str(
self.as_str()
.ok_or_else(|| ::serde_json::Error::custom("blob is not valid UTF-8"))?,
)
}
}
impl fmt::Display for Blob {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_str().unwrap_or(""))
}
}
impl<'a> From<&'a str> for Blob {
fn from(content: &'a str) -> Self {
let mut data = protocol::TypedData::new();
data.set_string(content.to_owned());
Blob(data)
}
}
impl From<String> for Blob {
fn from(content: String) -> Self {
let mut data = protocol::TypedData::new();
data.set_string(content);
Blob(data)
}
}
impl From<&Value> for Blob {
fn from(content: &Value) -> Self {
let mut data = protocol::TypedData::new();
data.set_json(content.to_string());
Blob(data)
}
}
impl From<Value> for Blob {
fn from(content: Value) -> Self {
let mut data = protocol::TypedData::new();
data.set_json(content.to_string());
Blob(data)
}
}
impl<'a> From<&'a [u8]> for Blob {
fn from(content: &'a [u8]) -> Self {
let mut data = protocol::TypedData::new();
data.set_bytes(content.to_owned());
Blob(data)
}
}
impl From<Vec<u8>> for Blob {
fn from(content: Vec<u8>) -> Self {
let mut data = protocol::TypedData::new();
data.set_bytes(content);
Blob(data)
}
}
impl From<protocol::TypedData> for Blob {
fn from(data: protocol::TypedData) -> Self {
Blob(data)
}
}
impl Into<protocol::TypedData> for Blob {
fn into(self) -> protocol::TypedData {
self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::to_value;
use std::fmt::Write;
#[test]
fn it_has_string_content() {
const BLOB: &'static str = "test blob";
let blob: Blob = BLOB.into();
assert_eq!(blob.as_str().unwrap(), BLOB);
let data: protocol::TypedData = blob.into();
assert_eq!(data.get_string(), BLOB);
}
#[test]
fn it_has_json_content() {
#[derive(Serialize, Deserialize)]
struct Data {
message: String,
};
const MESSAGE: &'static str = "test";
let data = Data {
message: MESSAGE.to_string(),
};
let blob: Blob = ::serde_json::to_value(data).unwrap().into();
assert_eq!(blob.as_json::<Data>().unwrap().message, MESSAGE);
let data: protocol::TypedData = blob.into();
assert_eq!(data.get_json(), r#"{"message":"test"}"#);
}
#[test]
fn it_has_bytes_content() {
const BLOB: &'static [u8] = &[1, 2, 3];
let blob: Blob = BLOB.into();
assert_eq!(blob.as_bytes(), BLOB);
let data: protocol::TypedData = blob.into();
assert_eq!(data.get_bytes(), BLOB);
}
#[test]
fn it_displays_as_a_string() {
const BLOB: &'static str = "test";
let blob: Blob = BLOB.into();
let mut s = String::new();
write!(s, "{}", blob).unwrap();
assert_eq!(s, BLOB);
}
#[test]
fn it_converts_from_str() {
let blob: Blob = "test".into();
assert_eq!(blob.as_str().unwrap(), "test");
}
#[test]
fn it_converts_from_string() {
let blob: Blob = "test".to_string().into();
assert_eq!(blob.as_str().unwrap(), "test");
}
#[test]
fn it_converts_from_json() {
let blob: Blob = to_value("hello world").unwrap().into();
assert_eq!(blob.as_str().unwrap(), r#""hello world""#);
}
#[test]
fn it_converts_from_u8_slice() {
let blob: Blob = [0, 1, 2][..].into();
assert_eq!(blob.as_bytes(), [0, 1, 2]);
}
#[test]
fn it_converts_from_u8_vec() {
let blob: Blob = vec![0, 1, 2].into();
assert_eq!(blob.as_bytes(), [0, 1, 2]);
}
#[test]
fn it_converts_from_typed_data() {
const BLOB: &'static str = "hello world!";
let mut data = protocol::TypedData::new();
data.set_string(BLOB.to_string());
let blob: Blob = data.into();
assert_eq!(blob.as_str().unwrap(), BLOB);
}
#[test]
fn it_converts_to_typed_data() {
let blob: Blob = "test".into();
let data: protocol::TypedData = blob.into();
assert!(data.has_string());
assert_eq!(data.get_string(), "test");
let blob: Blob = to_value("test").unwrap().into();
let data: protocol::TypedData = blob.into();
assert!(data.has_json());
assert_eq!(data.get_json(), r#""test""#);
let blob: Blob = vec![1, 2, 3].into();
let data: protocol::TypedData = blob.into();
assert!(data.has_bytes());
assert_eq!(data.get_bytes(), [1, 2, 3]);
}
}