// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. use std::any::TypeId; use std::mem::transmute_copy; use crate::BigInt; use crate::ByteString; use crate::U16String; use crate::ZeroCopyBuf; /// Serializable exists to allow boxing values as "objects" to be serialized later, /// this is particularly useful for async op-responses. This trait is a more efficient /// replacement for erased-serde that makes less allocations, since it's specific to serde_v8 /// (and thus doesn't have to have generic outputs, etc...) pub trait Serializable { fn to_v8<'a>( &mut self, scope: &mut v8::HandleScope<'a>, ) -> Result, crate::Error>; } /// Allows all implementors of `serde::Serialize` to implement Serializable impl Serializable for T { fn to_v8<'a>( &mut self, scope: &mut v8::HandleScope<'a>, ) -> Result, crate::Error> { crate::to_v8(scope, self) } } /// SerializablePkg exists to provide a fast path for op returns, /// allowing them to avoid boxing primtives (ints/floats/bool/unit/...) pub enum SerializablePkg { Primitive(Primitive), Serializable(Box), } impl SerializablePkg { pub fn to_v8<'a>( &mut self, scope: &mut v8::HandleScope<'a>, ) -> Result, crate::Error> { match self { Self::Primitive(x) => crate::to_v8(scope, x), Self::Serializable(x) => x.to_v8(scope), } } } /// Primitive serves as a lightweight serializable wrapper around primitives /// so that we can use them for async values pub enum Primitive { Unit, Bool(bool), Int8(i8), Int16(i16), Int32(i32), Int64(i64), UInt8(u8), UInt16(u16), UInt32(u32), UInt64(u64), Float32(f32), Float64(f64), String(String), ZeroCopyBuf(ZeroCopyBuf), ByteString(ByteString), U16String(U16String), BigInt(BigInt), } impl serde::Serialize for Primitive { fn serialize(&self, s: S) -> Result where S: serde::Serializer, { match self { Self::Unit => ().serialize(s), Self::Bool(x) => x.serialize(s), Self::Int8(x) => x.serialize(s), Self::Int16(x) => x.serialize(s), Self::Int32(x) => x.serialize(s), Self::Int64(x) => x.serialize(s), Self::UInt8(x) => x.serialize(s), Self::UInt16(x) => x.serialize(s), Self::UInt32(x) => x.serialize(s), Self::UInt64(x) => x.serialize(s), Self::Float32(x) => x.serialize(s), Self::Float64(x) => x.serialize(s), Self::String(x) => x.serialize(s), Self::ZeroCopyBuf(x) => x.serialize(s), Self::ByteString(x) => x.serialize(s), Self::U16String(x) => x.serialize(s), Self::BigInt(x) => x.serialize(s), } } } impl From for SerializablePkg { fn from(x: T) -> Self { #[inline(always)] fn tc(src: T) -> U { // SAFETY: the caller has ensured via the TypeId that the T and U types // are the same. let x = unsafe { transmute_copy(&src) }; std::mem::forget(src); x } let tid = TypeId::of::(); if tid == TypeId::of::<()>() { Self::Primitive(Primitive::Unit) } else if tid == TypeId::of::() { Self::Primitive(Primitive::Bool(tc(x))) } else if tid == TypeId::of::() { Self::Primitive(Primitive::Int8(tc(x))) } else if tid == TypeId::of::() { Self::Primitive(Primitive::Int16(tc(x))) } else if tid == TypeId::of::() { Self::Primitive(Primitive::Int32(tc(x))) } else if tid == TypeId::of::() { Self::Primitive(Primitive::Int64(tc(x))) } else if tid == TypeId::of::() { Self::Primitive(Primitive::UInt8(tc(x))) } else if tid == TypeId::of::() { Self::Primitive(Primitive::UInt16(tc(x))) } else if tid == TypeId::of::() { Self::Primitive(Primitive::UInt32(tc(x))) } else if tid == TypeId::of::() { Self::Primitive(Primitive::UInt64(tc(x))) } else if tid == TypeId::of::() { Self::Primitive(Primitive::Float32(tc(x))) } else if tid == TypeId::of::() { Self::Primitive(Primitive::Float64(tc(x))) } else if tid == TypeId::of::() { Self::Primitive(Primitive::String(tc(x))) } else if tid == TypeId::of::() { Self::Primitive(Primitive::ZeroCopyBuf(tc(x))) } else if tid == TypeId::of::() { Self::Primitive(Primitive::ByteString(tc(x))) } else if tid == TypeId::of::() { Self::Primitive(Primitive::U16String(tc(x))) } else if tid == TypeId::of::() { Self::Primitive(Primitive::BigInt(tc(x))) } else { Self::Serializable(Box::new(x)) } } }