#![forbid(missing_docs)]
#![allow(clippy::float_cmp)]
#![warn(
anonymous_parameters,
bare_trait_objects,
elided_lifetimes_in_paths,
rust_2018_idioms,
trivial_casts,
trivial_numeric_casts,
unsafe_code,
unused_extern_crates,
unused_import_braces
)]
#![warn(
clippy::all,
clippy::dbg_macro,
clippy::float_cmp_const,
clippy::get_unwrap,
clippy::mem_forget,
clippy::nursery,
clippy::pedantic,
clippy::todo,
clippy::unwrap_used,
clippy::wrong_pub_self_convention
)]
#![allow(
clippy::default_trait_access,
clippy::doc_markdown,
clippy::if_not_else,
clippy::must_use_candidate,
clippy::needless_pass_by_value,
clippy::pub_enum_variant_names,
clippy::use_self,
clippy::cargo_common_metadata,
clippy::missing_errors_doc,
clippy::enum_glob_use,
clippy::struct_excessive_bools,
clippy::module_name_repetitions,
clippy::used_underscore_binding,
clippy::future_not_send,
clippy::missing_const_for_fn,
clippy::type_complexity,
clippy::option_if_let_else
)]
#![cfg_attr(
test,
allow(clippy::unwrap_used, clippy::blacklisted_name, clippy::float_cmp)
)]
mod de;
mod error;
mod ser;
pub use de::{deserialize_unordered_array, from_bytes};
pub use error::{Error, Result};
pub use ser::{to_vec, to_writer};
#[cfg(test)]
mod tests {
use super::{from_bytes, to_vec};
use proptest::prelude::any;
use proptest::proptest;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
macro_rules! roundtrip {
($ty:ty, $value:expr) => {
let val = $value;
let serialized = to_vec(&val).expect("Serialization failed");
eprintln!("{}", String::from_utf8_lossy(serialized.as_slice()));
let deserialized: $ty =
from_bytes(serialized.as_slice()).expect("Deserialization failed");
assert_eq!(deserialized, val);
};
}
#[test]
fn roundtrip_newtype() {
#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
struct MyNewtype(i32);
roundtrip!(MyNewtype, MyNewtype(0));
roundtrip!(MyNewtype, MyNewtype(1));
roundtrip!(MyNewtype, MyNewtype(-1));
}
proptest! {
#[test]
fn roundtrip_unit(v in any::<()>()) {
roundtrip!((), v);
}
#[test]
fn roundtrip_bool(v in any::<bool>()) {
roundtrip!(bool, v);
}
#[test]
fn roundtrip_u8(v in any::<u8>()) {
roundtrip!(u8, v);
}
#[test]
fn roundtrip_u16(v in any::<u16>()) {
roundtrip!(u16, v);
}
#[test]
fn roundtrip_u32(v in any::<u32>()) {
roundtrip!(u32, v);
}
#[test]
fn roundtrip_u64(v in 0..(std::i64::MAX as u64)) {
roundtrip!(u64, v);
}
#[test]
fn roundtrip_i8(v in any::<i8>()) {
roundtrip!(i8, v);
}
#[test]
fn roundtrip_i16(v in any::<i16>()) {
roundtrip!(i16, v);
}
#[test]
fn roundtrip_i32(v in any::<i32>()) {
roundtrip!(i32, v);
}
#[test]
fn roundtrip_i64(v in any::<i64>()) {
roundtrip!(i64, v);
}
#[test]
fn roundtrip_f32(v in any::<f32>()) {
roundtrip!(f32, v);
}
#[test]
fn roundtrip_f64(v in any::<f64>()) {
roundtrip!(f64, v);
}
#[test]
fn roundtrip_bytes(v in any::<Vec<u8>>()) {
roundtrip!(Vec<u8>, v);
}
#[test]
fn roundtrip_char(v in any::<char>()) {
roundtrip!(char, v);
}
#[test]
fn roundtrip_string(v in any::<String>()) {
roundtrip!(String, v);
}
#[test]
fn roundtrip_option(v in any::<Option<i32>>()) {
roundtrip!(Option<i32>, v);
}
#[test]
fn roundtrip_same_type_tuple(v in any::<(u32, u32)>()) {
roundtrip!((u32, u32), v);
}
#[test]
fn roundtrip_mixed_type_tuple(v in any::<(String, i32)>()) {
roundtrip!((String, i32), v);
}
#[test]
fn roundtrip_string_string_hashmap(v in proptest::collection::hash_map(any::<String>(), any::<String>(), 0..100)) {
roundtrip!(HashMap<String, String>, v);
}
}
use std::io::prelude::*;
use std::io::Result;
use std::io::SeekFrom;
use std::process::Command;
use tempfile::tempfile;
fn through_php(bytes: &[u8]) -> Result<Vec<u8>> {
let mut file = tempfile()?;
file.write_all(bytes)?;
file.seek(SeekFrom::Start(0))?;
let res = Command::new("php")
.stdin(file)
.args(&[
"-r",
"print(serialize(unserialize(file_get_contents('php://stdin'))));",
])
.output()?;
Ok(res.stdout)
}
macro_rules! php_roundtrip {
($ty:ty, $value:expr) => {
let val = $value;
let serialized = to_vec(&val).expect("Serialization failed");
eprintln!(
"serialized={:?}",
String::from_utf8_lossy(serialized.as_slice())
);
let output = through_php(serialized.as_slice()).expect("Failed to deser&ser with php");
eprintln!("output={:?}", String::from_utf8_lossy(output.as_slice()));
let deserialized: $ty = from_bytes(output.as_slice()).expect("Deserialization failed");
assert_eq!(deserialized, val);
};
}
proptest! {
#[test]
#[ignore]
fn php_roundtrip_unit(v in any::<()>()) {
php_roundtrip!((), v);
}
#[test]
#[ignore]
fn php_roundtrip_bool(v in any::<bool>()) {
php_roundtrip!(bool, v);
}
#[test]
#[ignore]
fn php_roundtrip_i64(v in any::<f64>()) {
php_roundtrip!(f64, v);
}
#[test]
#[ignore]
fn php_roundtrip_u64(v in any::<f64>()) {
php_roundtrip!(f64, v);
}
#[test]
#[ignore]
fn php_roundtrip_f64(v in any::<f64>()) {
php_roundtrip!(f64, v);
}
#[test]
fn php_roundtrip_char(v in any::<char>()) {
php_roundtrip!(char, v);
}
#[test]
#[ignore]
fn php_roundtrip_string(v in any::<String>()) {
php_roundtrip!(String, v);
}
#[test]
#[ignore]
fn php_roundtrip_option(v in any::<Option<i32>>()) {
php_roundtrip!(Option<i32>, v);
}
#[test]
#[ignore]
fn php_roundtrip_same_type_tuple(v in any::<(u32, u32)>()) {
php_roundtrip!((u32, u32), v);
}
#[test]
#[ignore]
fn php_roundtrip_mixed_type_tuple(v in any::<(String, i32)>()) {
php_roundtrip!((String, i32), v);
}
}
}