Skip to content

Commit

Permalink
chore: move serde impls to module (#62)
Browse files Browse the repository at this point in the history
  • Loading branch information
robjtede authored Feb 9, 2025
1 parent bb37433 commit ffbc6ab
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 105 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ version = "1.3.0"
authors = ["Hyunsik Choi <hyunsik.choi@gmail.com>", "MrCroxx <mrcroxx@outlook.com>"]
keywords = ["byte", "byte-size", "utility", "human-readable", "format"]
categories = ["development-tools", "filesystem"]
repository = "https://github.com/hyunsik/bytesize"
repository = "https://github.com/bytesize-rs/bytesize"
license = "Apache-2.0"
edition = "2021"
rust-version = "1.65"
Expand Down
105 changes: 1 addition & 104 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,8 @@
//! ```
mod parse;

#[cfg(feature = "arbitrary")]
extern crate arbitrary;
#[cfg(feature = "serde")]
extern crate serde;
#[cfg(feature = "serde")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
#[cfg(feature = "serde")]
use std::convert::TryFrom;
mod serde;

use std::fmt::{self, Debug, Display, Formatter};
use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
Expand Down Expand Up @@ -342,70 +335,6 @@ where
}
}

#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for ByteSize {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct ByteSizeVisitor;

impl de::Visitor<'_> for ByteSizeVisitor {
type Value = ByteSize;

fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("an integer or string")
}

fn visit_i64<E: de::Error>(self, value: i64) -> Result<Self::Value, E> {
if let Ok(val) = u64::try_from(value) {
Ok(ByteSize(val))
} else {
Err(E::invalid_value(
de::Unexpected::Signed(value),
&"integer overflow",
))
}
}

fn visit_u64<E: de::Error>(self, value: u64) -> Result<Self::Value, E> {
Ok(ByteSize(value))
}

fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
if let Ok(val) = value.parse() {
Ok(val)
} else {
Err(E::invalid_value(
de::Unexpected::Str(value),
&"parsable string",
))
}
}
}

if deserializer.is_human_readable() {
deserializer.deserialize_any(ByteSizeVisitor)
} else {
deserializer.deserialize_u64(ByteSizeVisitor)
}
}
}

#[cfg(feature = "serde")]
impl Serialize for ByteSize {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if serializer.is_human_readable() {
<str>::serialize(self.to_string().as_str(), serializer)
} else {
self.0.serialize(serializer)
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -537,36 +466,4 @@ mod tests {
fn test_to_string() {
assert_to_string("609.0 PB", ByteSize::pb(609), false);
}

#[cfg(feature = "serde")]
#[test]
fn test_serde() {
#[derive(Serialize, Deserialize)]
struct S {
x: ByteSize,
}

let s: S = serde_json::from_str(r#"{ "x": "5 B" }"#).unwrap();
assert_eq!(s.x, ByteSize(5));

let s: S = serde_json::from_str(r#"{ "x": 1048576 }"#).unwrap();
assert_eq!(s.x, "1 MiB".parse::<ByteSize>().unwrap());

let s: S = toml::from_str(r#"x = "2.5 MiB""#).unwrap();
assert_eq!(s.x, "2.5 MiB".parse::<ByteSize>().unwrap());

// i64 MAX
let s: S = toml::from_str(r#"x = "9223372036854775807""#).unwrap();
assert_eq!(s.x, "9223372036854775807".parse::<ByteSize>().unwrap());
}

#[test]
#[cfg(feature = "serde")]
fn test_serde_json() {
let json = serde_json::to_string(&ByteSize::mib(1)).unwrap();
assert_eq!(json, "\"1.0 MiB\"");

let deserialized: ByteSize = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized.0, 1048576);
}
}
103 changes: 103 additions & 0 deletions src/serde.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use std::fmt;

use serde::{de, Deserialize, Deserializer, Serialize, Serializer};

use crate::ByteSize;

impl<'de> Deserialize<'de> for ByteSize {
fn deserialize<D>(de: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct ByteSizeVisitor;

impl de::Visitor<'_> for ByteSizeVisitor {
type Value = ByteSize;

fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("an integer or string")
}

fn visit_i64<E: de::Error>(self, value: i64) -> Result<Self::Value, E> {
if let Ok(val) = u64::try_from(value) {
Ok(ByteSize(val))
} else {
Err(E::invalid_value(
de::Unexpected::Signed(value),
&"integer overflow",
))
}
}

fn visit_u64<E: de::Error>(self, value: u64) -> Result<Self::Value, E> {
Ok(ByteSize(value))
}

fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
if let Ok(val) = value.parse() {
Ok(val)
} else {
Err(E::invalid_value(
de::Unexpected::Str(value),
&"parsable string",
))
}
}
}

if de.is_human_readable() {
de.deserialize_any(ByteSizeVisitor)
} else {
de.deserialize_u64(ByteSizeVisitor)
}
}
}

impl Serialize for ByteSize {
fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if ser.is_human_readable() {
<str>::serialize(self.to_string().as_str(), ser)
} else {
self.0.serialize(ser)
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_serde() {
#[derive(Serialize, Deserialize)]
struct S {
x: ByteSize,
}

let s = serde_json::from_str::<S>(r#"{ "x": "5 B" }"#).unwrap();
assert_eq!(s.x, ByteSize(5));

let s = serde_json::from_str::<S>(r#"{ "x": 1048576 }"#).unwrap();
assert_eq!(s.x, "1 MiB".parse::<ByteSize>().unwrap());

let s = toml::from_str::<S>(r#"x = "2.5 MiB""#).unwrap();
assert_eq!(s.x, "2.5 MiB".parse::<ByteSize>().unwrap());

// i64 MAX
let s = toml::from_str::<S>(r#"x = "9223372036854775807""#).unwrap();
assert_eq!(s.x, "9223372036854775807".parse::<ByteSize>().unwrap());
}

#[test]

fn test_serde_json() {
let json = serde_json::to_string(&ByteSize::mib(1)).unwrap();
assert_eq!(json, "\"1.0 MiB\"");

let deserialized = serde_json::from_str::<ByteSize>(&json).unwrap();
assert_eq!(deserialized.0, 1048576);
}
}

0 comments on commit ffbc6ab

Please sign in to comment.