#![warn(
absolute_paths_not_starting_with_crate,
anonymous_parameters,
box_pointers,
confusable_idents,
deprecated_in_future,
elided_lifetimes_in_paths,
explicit_outlives_requirements,
indirect_structural_match,
keyword_idents,
macro_use_extern_crate,
meta_variable_misuse,
missing_copy_implementations,
missing_crate_level_docs,
missing_debug_implementations,
missing_docs,
missing_doc_code_examples,
non_ascii_idents,
private_doc_tests,
single_use_lifetimes,
trivial_casts,
trivial_numeric_casts,
unaligned_references,
unreachable_pub,
unsafe_code,
unstable_features,
unused_crate_dependencies,
unused_extern_crates,
unused_import_braces,
unused_lifetimes,
unused_qualifications,
unused_results,
variant_size_differences
)]
#![warn(
clippy::cargo,
clippy::complexity,
clippy::correctness,
clippy::nursery,
clippy::pedantic,
clippy::perf,
clippy::style
)]
#![allow(clippy::implicit_return, clippy::shadow_unrelated)]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(all(not(feature = "std"), not(feature = "alloc")))]
core::compile_error!("This crate requires either the std or the alloc feature");
use serde::{
de::{Deserializer, Error},
private::de::{Content, ContentRefDeserializer},
ser::Serializer,
Deserialize, Serialize,
};
use core::{marker::PhantomData, cmp::Ordering, hash::{Hash, Hasher}, ops::{Deref, DerefMut}, fmt};
#[cfg(feature = "std")]
use std::{borrow::Cow, vec, vec::Vec};
#[cfg(feature = "alloc")]
use alloc::{borrow::Cow, vec, vec::Vec};
#[allow(unused_lifetimes)]
pub trait Storage<'a, T> {
type Backing;
fn single(ty: T) -> Self::Backing;
fn get_first_with_len(b: &Self::Backing) -> Option<(&T, usize)>;
}
impl<T> Storage<'_, T> for Vec<T> {
type Backing = Self;
fn single(ty: T) -> Self::Backing {
vec![ty]
}
fn get_first_with_len(b: &Self::Backing) -> Option<(&T, usize)> {
b.split_first().map(|(t, r)| (t, r.len()))
}
}
impl<'a, T: 'a + Clone> Storage<'a, T> for Cow<'a, [T]> {
type Backing = Self;
fn single(ty: T) -> Self::Backing {
Cow::Owned(vec![ty])
}
fn get_first_with_len(b: &Self::Backing) -> Option<(&T, usize)> {
b.split_first().map(|(t, r)| (t, r.len()))
}
}
pub trait Format {
fn use_single() -> bool;
}
#[derive(Debug, Clone, Copy)]
pub struct PreferSingle {}
impl Format for PreferSingle {
fn use_single() -> bool {
true
}
}
#[derive(Debug, Clone, Copy)]
pub struct AlwaysVector {}
impl Format for AlwaysVector {
fn use_single() -> bool {
false
}
}
#[allow(single_use_lifetimes)]
pub struct SingleOrVec<'a, T, F: Format = PreferSingle, S: Storage<'a, T> = Vec<T>> {
data: S::Backing,
format: PhantomData<F>,
}
impl<'a, T, F, S, B> Default for SingleOrVec<'a, T, F, S>
where
F: Format,
S: Storage<'a, T, Backing = B>,
B: Default,
{
fn default() -> Self {
Self {
data: B::default(),
format: PhantomData,
}
}
}
impl<'a, T, F, S, B> Clone for SingleOrVec<'a, T, F, S>
where
F: Format,
S: Storage<'a, T, Backing = B>,
B: Clone,
{
fn clone(&self) -> Self {
Self {
data: self.data.clone(),
format: PhantomData,
}
}
}
impl<'a, T, F, S, B> fmt::Debug for SingleOrVec<'a, T, F, S>
where
F: Format,
S: Storage<'a, T, Backing = B>,
B: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SingleOrVec")
.field("data", &self.data)
.finish()
}
}
impl<'a, T, F, S, B> Eq for SingleOrVec<'a, T, F, S>
where
F: Format,
S: Storage<'a, T, Backing = B>,
B: Eq,
{
}
impl<'a, T, F, F2, S, B> PartialEq<SingleOrVec<'a, T, F2, S>> for SingleOrVec<'a, T, F, S>
where
F: Format,
F2: Format,
S: Storage<'a, T, Backing = B>,
B: PartialEq,
{
fn eq(&self, other: &SingleOrVec<'a, T, F2, S>) -> bool {
self.data.eq(&other.data)
}
}
impl<'a, T, F, S, B> Ord for SingleOrVec<'a, T, F, S>
where
F: Format,
S: Storage<'a, T, Backing = B>,
B: Ord,
{
fn cmp(&self, other: &Self) -> Ordering {
self.data.cmp(&other.data)
}
}
impl<'a, T, F, F2, S, B> PartialOrd<SingleOrVec<'a, T, F2, S>> for SingleOrVec<'a, T, F, S>
where
F: Format,
F2: Format,
S: Storage<'a, T, Backing = B>,
B: PartialOrd,
{
fn partial_cmp(&self, other: &SingleOrVec<'a, T, F2, S>) -> Option<Ordering> {
self.data.partial_cmp(&other.data)
}
}
impl<'a, T, F, S, B> Hash for SingleOrVec<'a, T, F, S>
where
F: Format,
S: Storage<'a, T, Backing = B>,
B: Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.data.hash(state)
}
}
impl<'a, T, F, S> SingleOrVec<'a, T, F, S>
where
F: Format,
S: Storage<'a, T>,
{
#[must_use]
pub fn new(ty: S::Backing) -> Self {
Self {
data: ty,
format: PhantomData,
}
}
#[must_use]
pub fn new_single(ty: T) -> Self {
Self {
data: S::single(ty),
format: PhantomData,
}
}
}
impl<'a, T, F, S> Deref for SingleOrVec<'a, T, F, S>
where
F: Format,
S: Storage<'a, T>,
{
type Target = S::Backing;
#[inline]
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<'a, T, F, S> DerefMut for SingleOrVec<'a, T, F, S>
where
F: Format,
S: Storage<'a, T>,
{
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
impl<'a, T, F, S, B> From<T> for SingleOrVec<'a, T, F, S>
where
F: Format,
S: Storage<'a, T, Backing = B>,
B: From<T>,
{
fn from(d: T) -> Self {
Self {
data: B::from(d),
format: PhantomData,
}
}
}
impl<'a, T, F, St, B> Serialize for SingleOrVec<'a, T, F, St>
where
T: Serialize,
F: Format,
St: Storage<'a, T, Backing = B>,
B: Serialize,
{
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
if F::use_single() {
if let Some((first, len)) = St::get_first_with_len(&self.data) {
if len == 0 {
return first.serialize(serializer);
}
}
}
self.data.serialize(serializer)
}
}
impl<'de, 'a, T, F, S, B> Deserialize<'de> for SingleOrVec<'a, T, F, S>
where
T: Deserialize<'de>,
F: Format,
S: Storage<'a, T, Backing = B>,
B: Deserialize<'de>,
{
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let content = Content::deserialize(deserializer)?;
<T as Deserialize>::deserialize(ContentRefDeserializer::<D::Error>::new(&content))
.map(S::single)
.or_else(|_| B::deserialize(ContentRefDeserializer::<D::Error>::new(&content)))
.map(Self::new)
.map_err(|_| Error::custom("Expected either a sequence or a single value"))
}
}
#[cfg(test)]
mod tests {
use super::SingleOrVec;
use arrayvec as _;
use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
use std::{vec, string::String, vec::Vec};
#[cfg(feature = "alloc")]
use alloc::{vec, string::String, vec::Vec};
macro_rules! multiple {
($t:ty, $i:expr, $e:expr) => {
let input: SingleOrVec<'_, $t> = SingleOrVec::new(vec![$i, $i, $i]);
let json_expected = $e;
let json = serde_json::to_string(&input).expect("Unable to deserialize");
assert_eq!(
json_expected, json,
"Deserializing not matching with expected value"
);
let output: SingleOrVec<'_, $t> = serde_json::from_str(&json).expect("Unable to parse");
assert_eq!(output, input, "Output and input not matching up")
};
}
macro_rules! single {
($t:ty, $i:expr, $e:expr) => {
let input: SingleOrVec<'_, $t> = SingleOrVec::new_single($i);
let json_expected = $e;
let json = serde_json::to_string(&input).expect("Unable to deserialize");
assert_eq!(
json_expected, json,
"Deserializing not matching with expected value"
);
let output: SingleOrVec<'_, $t> = serde_json::from_str(&json).expect("Unable to parse");
assert_eq!(output, input, "Output and input not matching up")
};
}
macro_rules! numbers {
($x:ident) => {
#[test]
fn $x() {
multiple!($x, 0, "[0,0,0]");
single!($x, 0, "0");
single!($x, 1, "1");
}
};
($x:ident, $($y:ident),+) => (
numbers!($x);
numbers!($($y),+);
);
}
macro_rules! decimals {
($x:ident) => {
#[test]
fn $x() {
multiple!($x, 0.0, "[0.0,0.0,0.0]");
single!($x, 0.0, "0.0");
single!($x, 1.1, "1.1");
}
};
($x:ident, $($y:ident),+) => (
decimals!($x);
decimals!($($y),+);
);
}
#[test]
fn bool() {
multiple!(bool, true, "[true,true,true]");
single!(bool, false, "false");
single!(bool, true, "true");
}
numbers!(i8, i16, i32, i64, u8, u16, u32, u64);
decimals!(f32, f64);
#[test]
fn char() {
multiple!(char, ' ', "[\" \",\" \",\" \"]");
single!(char, ' ', "\" \"");
}
#[test]
fn str() {
multiple!(&str, " ", "[\" \",\" \",\" \"]");
single!(&str, " ", "\" \"");
}
#[test]
fn string() {
multiple!(String, String::from(" "), "[\" \",\" \",\" \"]");
single!(String, String::from(" "), "\" \"");
}
#[test]
fn bytes_buf() {
multiple!(Vec<u8>, vec![0, 1, 2], "[[0,1,2],[0,1,2],[0,1,2]]");
single!(Vec<u8>, vec![0, 1, 2], "[0,1,2]");
}
#[test]
fn none() {
multiple!(Option<()>, None, "[null,null,null]");
single!(Option<()>, None, "null");
}
#[test]
fn some() {
multiple!(Option<u8>, Some(0_u8), "[0,0,0]");
single!(Option<u8>, Some(0_u8), "0");
}
#[test]
fn unit() {
multiple!((), (), "[null,null,null]");
single!((), (), "null");
}
#[test]
fn strct() {
#[derive(Debug, Deserialize, PartialEq, Serialize)]
struct TestStruct {
test: u8,
}
multiple!(
TestStruct,
TestStruct { test: 0 },
"[{\"test\":0},{\"test\":0},{\"test\":0}]"
);
single!(TestStruct, TestStruct { test: 0 }, "{\"test\":0}");
}
#[test]
fn seq() {
multiple!(
Vec<&str>,
vec!["a", "b", "c"],
"[[\"a\",\"b\",\"c\"],[\"a\",\"b\",\"c\"],[\"a\",\"b\",\"c\"]]"
);
single!(Vec<&str>, vec!["a", "b", "c"], "[\"a\",\"b\",\"c\"]");
}
#[test]
fn enm() {
#[derive(Debug, Deserialize, PartialEq, Serialize)]
enum TestEnum {
One,
Two,
}
multiple!(TestEnum, TestEnum::Two, "[\"Two\",\"Two\",\"Two\"]");
single!(TestEnum, TestEnum::One, "\"One\"");
}
#[test]
fn rec() {
multiple!(
SingleOrVec<'_, &str>,
SingleOrVec::new(vec!["a", "b", "c"]),
"[[\"a\",\"b\",\"c\"],[\"a\",\"b\",\"c\"],[\"a\",\"b\",\"c\"]]"
);
single!(
SingleOrVec<'_, &str>,
SingleOrVec::new(vec!["a", "b", "c"]),
"[\"a\",\"b\",\"c\"]"
);
single!(SingleOrVec<'_, &str>, SingleOrVec::new(vec!["a"]), "\"a\"");
}
#[test]
fn empty() {
single!(
SingleOrVec<'_, &str>,
SingleOrVec::new(vec![]),
"[]"
);
}
}