Skip to content

Commit

Permalink
More consistent docs + hide internal fields
Browse files Browse the repository at this point in the history
  • Loading branch information
RReverser committed Dec 9, 2023
1 parent ce7669e commit 455d556
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 16 deletions.
26 changes: 19 additions & 7 deletions src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ impl<'de> de::SeqAccess<'de> for SeqAccess {
}
}

/// Provides [`serde::de::MapAccess`] from any JS iterator that returns `[key, value]` pairs.
/// Provides [`de::MapAccess`] from any JS iterator that returns `[key, value]` pairs.
struct MapAccess {
iter: js_sys::IntoIter,
next_value: Option<Deserializer>,
Expand Down Expand Up @@ -143,7 +143,7 @@ impl<'de> de::SeqAccess<'de> for PreservedValueAccess {
}
}

/// Provides [`serde::de::EnumAccess`] from given JS values for the `tag` and the `payload`.
/// Provides [`de::EnumAccess`] from given JS values for the `tag` and the `payload`.
struct EnumAccess {
tag: Deserializer,
payload: Deserializer,
Expand All @@ -161,7 +161,7 @@ impl<'de> de::EnumAccess<'de> for EnumAccess {
}
}

/// A newtype that allows using any [`JsValue`] as a [`serde::Deserializer`].
/// A newtype that allows using any [`JsValue`] as a [`deserializer`].
pub struct Deserializer {
value: JsValue,
}
Expand Down Expand Up @@ -189,8 +189,6 @@ fn convert_pair(pair: JsValue) -> (Deserializer, Deserializer) {
}

impl Deserializer {
/// Casts the internal value into an object, including support for prototype-less objects.
/// See https://github.com/rustwasm/wasm-bindgen/issues/1366 for why we don't use `dyn_ref`.
fn as_object_entries(&self) -> Option<Array> {
if self.value.is_object() {
Some(Object::entries(self.value.unchecked_ref()))
Expand Down Expand Up @@ -415,6 +413,9 @@ impl<'de> de::Deserializer<'de> for Deserializer {
self.deserialize_from_js_number_unsigned(visitor)
}

/// Supported inputs:
/// - `BigInt` within `i64` boundaries.
/// - number within safe integer boundaries.
fn deserialize_i64<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
if self.value.is_bigint() {
match i64::try_from(self.value) {
Expand All @@ -428,6 +429,9 @@ impl<'de> de::Deserializer<'de> for Deserializer {
}
}

/// Supported inputs:
/// - `BigInt` within `u64` boundaries.
/// - number within safe integer boundaries.
fn deserialize_u64<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
if self.value.is_bigint() {
match u64::try_from(self.value) {
Expand All @@ -441,6 +445,8 @@ impl<'de> de::Deserializer<'de> for Deserializer {
}
}

/// Supported inputs:
/// - `BigInt` within `i128` boundaries.
fn deserialize_i128<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
if self.value.is_bigint() {
match i128::try_from(self.value) {
Expand All @@ -454,6 +460,8 @@ impl<'de> de::Deserializer<'de> for Deserializer {
}
}

/// Supported inputs:
/// - `BigInt` within `u128` boundaries.
fn deserialize_u128<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
if self.value.is_bigint() {
match u128::try_from(self.value) {
Expand All @@ -467,7 +475,7 @@ impl<'de> de::Deserializer<'de> for Deserializer {
}
}

/// Converts a JavaScript string to a Rust char.
/// Converts a JavaScript string to a Rust `char`.
///
/// By default we don't perform detection of single chars because it's pretty complicated,
/// but if we get a hint that they're expected, this methods allows to avoid heap allocations
Expand All @@ -481,6 +489,7 @@ impl<'de> de::Deserializer<'de> for Deserializer {
self.invalid_type(visitor)
}

/// Deserializes `undefined` or `null` into `None` and any other value into `Some(value)`.
// Serde can deserialize `visit_unit` into `None`, but can't deserialize arbitrary value
// as `Some`, so we need to provide own simple implementation.
fn deserialize_option<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
Expand All @@ -491,7 +500,7 @@ impl<'de> de::Deserializer<'de> for Deserializer {
}
}

/// Simply calls `visit_newtype_struct`.
/// Forwards to deserializing newtype contents.
fn deserialize_newtype_struct<V: de::Visitor<'de>>(
self,
_name: &'static str,
Expand All @@ -502,6 +511,7 @@ impl<'de> de::Deserializer<'de> for Deserializer {

/// Supported inputs:
/// - JS iterable (an object with [`[Symbol.iterator]`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator)).
///
/// Supported outputs:
/// - Any Rust sequence from Serde point of view ([`Vec`], [`HashSet`](std::collections::HashSet), etc.)
fn deserialize_seq<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
Expand Down Expand Up @@ -535,6 +545,7 @@ impl<'de> de::Deserializer<'de> for Deserializer {
/// Supported inputs:
/// - A JS iterable that is expected to return `[key, value]` pairs.
/// - A JS object, which will be iterated using [`Object.entries`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries).
///
/// Supported outputs:
/// - A Rust key-value map ([`HashMap`](std::collections::HashMap), [`BTreeMap`](std::collections::BTreeMap), etc.).
/// - A typed Rust structure with `#[derive(Deserialize)]`.
Expand All @@ -550,6 +561,7 @@ impl<'de> de::Deserializer<'de> for Deserializer {

/// Supported inputs:
/// - A plain JS object.
///
/// Supported outputs:
/// - A typed Rust structure with `#[derive(Deserialize)]`.
fn deserialize_struct<V: de::Visitor<'de>>(
Expand Down
55 changes: 47 additions & 8 deletions src/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ use crate::{static_str_to_js, Error, ObjectExt};
type Result<T = JsValue> = super::Result<T>;

/// Wraps other serializers into an enum tagged variant form.
/// Uses {"Variant": ...payload...} for compatibility with serde-json.
///
/// Results in `{"Variant": ...payload...}` for compatibility with serde-json.
pub struct VariantSerializer<S> {
variant: &'static str,
inner: S,
}

impl<S> VariantSerializer<S> {
pub const fn new(variant: &'static str, inner: S) -> Self {
const fn new(variant: &'static str, inner: S) -> Self {
Self { variant, inner }
}

Expand Down Expand Up @@ -64,14 +65,15 @@ impl<S: ser::SerializeStruct<Ok = JsValue, Error = Error>> ser::SerializeStructV
}
}

/// Serializes Rust iterables and tuples into JS arrays.
pub struct ArraySerializer<'s> {
serializer: &'s Serializer,
target: Array,
idx: u32,
}

impl<'s> ArraySerializer<'s> {
pub fn new(serializer: &'s Serializer) -> Self {
fn new(serializer: &'s Serializer) -> Self {
Self {
serializer,
target: Array::new(),
Expand Down Expand Up @@ -126,6 +128,10 @@ pub enum MapResult {
Object(Object),
}

/// Serializes Rust maps into JS `Map` or plain JS objects.
///
/// Plain JS objects are used if `serialize_maps_as_objects` is set to `true`,
/// but then only string keys are supported.
pub struct MapSerializer<'s> {
serializer: &'s Serializer,
target: MapResult,
Expand Down Expand Up @@ -182,6 +188,7 @@ impl ser::SerializeMap for MapSerializer<'_> {
}
}

/// Serializes Rust structs into plain JS objects.
pub struct ObjectSerializer<'s> {
serializer: &'s Serializer,
target: ObjectExt,
Expand Down Expand Up @@ -314,6 +321,11 @@ impl<'s> ser::Serializer for &'s Serializer {
serialize_str(&str);
}

/// Serializes `i64` into a `BigInt` or a JS number.
///
/// If `serialize_large_number_types_as_bigints` is set to `false`,
/// `i64` is serialized as a JS number. But in this mode only numbers
/// within the safe integer range are supported.
fn serialize_i64(self, v: i64) -> Result {
if self.serialize_large_number_types_as_bigints {
return Ok(v.into());
Expand All @@ -334,6 +346,11 @@ impl<'s> ser::Serializer for &'s Serializer {
}
}

/// Serializes `u64` into a `BigInt` or a JS number.
///
/// If `serialize_large_number_types_as_bigints` is set to `false`,
/// `u64` is serialized as a JS number. But in this mode only numbers
/// within the safe integer range are supported.
fn serialize_u64(self, v: u64) -> Result {
if self.serialize_large_number_types_as_bigints {
return Ok(v.into());
Expand All @@ -349,18 +366,24 @@ impl<'s> ser::Serializer for &'s Serializer {
}
}

/// Serializes `i128` into a `BigInt`.
fn serialize_i128(self, v: i128) -> Result {
Ok(JsValue::from(v))
}

/// Serializes `u128` into a `BigInt`.
fn serialize_u128(self, v: u128) -> Result {
Ok(JsValue::from(v))
}

/// Serializes `char` into a JS string.
fn serialize_char(self, v: char) -> Result {
Ok(JsString::from(v).into())
}

/// Serializes `bytes` into a JS `Uint8Array` or a plain JS array.
///
/// If `serialize_bytes_as_arrays` is set to `true`, bytes are serialized as plain JS arrays.
fn serialize_bytes(self, v: &[u8]) -> Result {
// Create a `Uint8Array` view into a Rust slice, and immediately copy it to the JS memory.
//
Expand All @@ -374,14 +397,21 @@ impl<'s> ser::Serializer for &'s Serializer {
}
}

/// Serializes `None` into `undefined` or `null`.
///
/// If `serialize_missing_as_null` is set to `true`, `None` is serialized as `null`.
fn serialize_none(self) -> Result {
self.serialize_unit()
}

/// Serializes `Some(T)` as `T`.
fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result {
value.serialize(self)
}

/// Serializes `()` into `undefined` or `null`.
///
/// If `serialize_missing_as_null` is set to `true`, `()` is serialized as `null`.
fn serialize_unit(self) -> Result {
Ok(if self.serialize_missing_as_null {
JsValue::NULL
Expand All @@ -390,11 +420,12 @@ impl<'s> ser::Serializer for &'s Serializer {
})
}

/// Serializes unit structs into `undefined` or `null`.
fn serialize_unit_struct(self, _name: &'static str) -> Result {
self.serialize_unit()
}

/// For compatibility with serde-json, serialises unit variants as "Variant" strings.
/// For compatibility with serde-json, sserializes unit variants as "Variant" strings.
fn serialize_unit_variant(
self,
_name: &'static str,
Expand All @@ -404,6 +435,7 @@ impl<'s> ser::Serializer for &'s Serializer {
Ok(static_str_to_js(variant).into())
}

/// Serializes newtype structs as their inner values.
fn serialize_newtype_struct<T: ?Sized + Serialize>(
self,
name: &'static str,
Expand All @@ -419,6 +451,7 @@ impl<'s> ser::Serializer for &'s Serializer {
value.serialize(self)
}

/// Serializes newtype variants as their inner values.
fn serialize_newtype_variant<T: ?Sized + Serialize>(
self,
_name: &'static str,
Expand All @@ -429,16 +462,18 @@ impl<'s> ser::Serializer for &'s Serializer {
VariantSerializer::new(variant, self.serialize_newtype_struct(variant, value)?).end(Ok)
}

/// Serialises any Rust iterable into a JS Array.
// TODO: Figure out if there is a way to detect and serialise `Set` differently.
/// Sserializes any Rust iterable as a JS Array.
// TODO: Figure out if there is a way to detect and sserialize `Set` differently.
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
Ok(ArraySerializer::new(self))
}

/// Sserializes Rust tuples as JS arrays.
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
self.serialize_seq(Some(len))
}

/// Sserializes Rust tuple structs as JS arrays.
fn serialize_tuple_struct(
self,
_name: &'static str,
Expand All @@ -447,6 +482,7 @@ impl<'s> ser::Serializer for &'s Serializer {
self.serialize_tuple(len)
}

/// Sserializes Rust tuple variants as `{"Variant": [ ...tuple... ]}`.
fn serialize_tuple_variant(
self,
_name: &'static str,
Expand All @@ -460,16 +496,19 @@ impl<'s> ser::Serializer for &'s Serializer {
))
}

/// Serialises Rust maps into JS `Map` or plain JS objects, depending on configuration of `serialize_maps_as_objects`.
/// Sserializes Rust maps into JS `Map` or plain JS objects.
///
/// See [`MapSerializer`] for more details.
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
Ok(MapSerializer::new(self, self.serialize_maps_as_objects))
}

/// Serialises Rust typed structs into plain JS objects.
/// Sserializes Rust typed structs into plain JS objects.
fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
Ok(ObjectSerializer::new(self))
}

/// Sserializes Rust struct-like variants into `{"Variant": { ...fields... }}`.
fn serialize_struct_variant(
self,
_name: &'static str,
Expand Down
2 changes: 1 addition & 1 deletion tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ fn sequences() {
test_via_json((100, "xyz".to_string(), true));

// Sets are currently indistinguishable from other sequences for
// Serde serialisers, so this will become an array on the JS side.
// Serde sserializers, so this will become an array on the JS side.
test_via_json(hashset! {false, true});
}

Expand Down

0 comments on commit 455d556

Please sign in to comment.