mirror of
https://gitee.com/openharmony/third_party_rust_log
synced 2024-11-23 07:40:08 +00:00
Rework structured value casting (#396)
Also adds a const-fn based mechanism for pulling concrete values out of generic ones
This commit is contained in:
parent
ca54ac75ce
commit
803a23b15e
30
benches/value.rs
Normal file
30
benches/value.rs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#![cfg(feature = "kv_unstable")]
|
||||||
|
#![feature(test)]
|
||||||
|
|
||||||
|
extern crate log;
|
||||||
|
extern crate test;
|
||||||
|
|
||||||
|
use log::kv::Value;
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn u8_to_value(b: &mut test::Bencher) {
|
||||||
|
b.iter(|| Value::from(1u8))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn u8_to_value_debug(b: &mut test::Bencher) {
|
||||||
|
b.iter(|| Value::from_debug(&1u8))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn str_to_value_debug(b: &mut test::Bencher) {
|
||||||
|
b.iter(|| Value::from_debug(&"a string"))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn custom_to_value_debug(b: &mut test::Bencher) {
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct A;
|
||||||
|
|
||||||
|
b.iter(|| Value::from_debug(&A))
|
||||||
|
}
|
61
build.rs
61
build.rs
@ -2,13 +2,72 @@
|
|||||||
//! atomics and sets `cfg` flags accordingly.
|
//! atomics and sets `cfg` flags accordingly.
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::str::{self, FromStr};
|
||||||
|
|
||||||
|
#[cfg(feature = "kv_unstable")]
|
||||||
|
#[path = "src/kv/value/internal/cast/primitive.rs"]
|
||||||
|
mod primitive;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let target = env::var("TARGET").unwrap();
|
let minor = match rustc_minor_version() {
|
||||||
|
Some(minor) => minor,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let target = match rustc_target() {
|
||||||
|
Some(target) => target,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
// If the target isn't thumbv6 then we can use atomic CAS
|
||||||
if !target.starts_with("thumbv6") {
|
if !target.starts_with("thumbv6") {
|
||||||
println!("cargo:rustc-cfg=atomic_cas");
|
println!("cargo:rustc-cfg=atomic_cas");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the Rust version is at least 1.46.0 then we can use type ids at compile time
|
||||||
|
if minor >= 47 {
|
||||||
|
println!("cargo:rustc-cfg=const_type_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate sorted type id lookup
|
||||||
|
#[cfg(feature = "kv_unstable")]
|
||||||
|
primitive::generate();
|
||||||
|
|
||||||
|
println!("cargo:rustc-cfg=srcbuild");
|
||||||
println!("cargo:rerun-if-changed=build.rs");
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rustc_target() -> Option<String> {
|
||||||
|
env::var("TARGET").ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
// From the `serde` build script
|
||||||
|
fn rustc_minor_version() -> Option<u32> {
|
||||||
|
let rustc = match env::var_os("RUSTC") {
|
||||||
|
Some(rustc) => rustc,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let output = match Command::new(rustc).arg("--version").output() {
|
||||||
|
Ok(output) => output,
|
||||||
|
Err(_) => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let version = match str::from_utf8(&output.stdout) {
|
||||||
|
Ok(version) => version,
|
||||||
|
Err(_) => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut pieces = version.split('.');
|
||||||
|
if pieces.next() != Some("rustc 1") {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let next = match pieces.next() {
|
||||||
|
Some(next) => next,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
u32::from_str(next).ok()
|
||||||
|
}
|
||||||
|
@ -2,17 +2,17 @@
|
|||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use super::internal::{Erased, Inner, Visitor};
|
use super::internal::{Inner, Visitor};
|
||||||
use super::{Error, Value};
|
use super::{Error, Value};
|
||||||
|
|
||||||
impl<'v> Value<'v> {
|
impl<'v> Value<'v> {
|
||||||
/// Get a value from a fillable slot.
|
/// Get a value from a fillable slot.
|
||||||
pub fn from_fill<T>(value: &'v T) -> Self
|
pub fn from_fill<T>(value: &'v T) -> Self
|
||||||
where
|
where
|
||||||
T: Fill + 'static,
|
T: Fill,
|
||||||
{
|
{
|
||||||
Value {
|
Value {
|
||||||
inner: Inner::Fill(unsafe { Erased::new_unchecked::<T>(value) }),
|
inner: Inner::Fill(value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,24 +7,6 @@ use std::fmt;
|
|||||||
|
|
||||||
use super::{Primitive, ToValue, Value};
|
use super::{Primitive, ToValue, Value};
|
||||||
|
|
||||||
macro_rules! impl_into_owned {
|
|
||||||
($($into_ty:ty => $convert:ident,)*) => {
|
|
||||||
$(
|
|
||||||
impl ToValue for $into_ty {
|
|
||||||
fn to_value(&self) -> Value {
|
|
||||||
Value::from(*self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'v> From<$into_ty> for Value<'v> {
|
|
||||||
fn from(value: $into_ty) -> Self {
|
|
||||||
Value::from_primitive(value as $convert)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'v> ToValue for &'v str {
|
impl<'v> ToValue for &'v str {
|
||||||
fn to_value(&self) -> Value {
|
fn to_value(&self) -> Value {
|
||||||
Value::from(*self)
|
Value::from(*self)
|
||||||
@ -67,25 +49,25 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_into_owned! [
|
macro_rules! impl_to_value_primitive {
|
||||||
usize => u64,
|
($($into_ty:ty,)*) => {
|
||||||
u8 => u64,
|
$(
|
||||||
u16 => u64,
|
impl ToValue for $into_ty {
|
||||||
u32 => u64,
|
fn to_value(&self) -> Value {
|
||||||
u64 => u64,
|
Value::from(*self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
isize => i64,
|
impl<'v> From<$into_ty> for Value<'v> {
|
||||||
i8 => i64,
|
fn from(value: $into_ty) -> Self {
|
||||||
i16 => i64,
|
Value::from_primitive(value)
|
||||||
i32 => i64,
|
}
|
||||||
i64 => i64,
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
f32 => f64,
|
impl_to_value_primitive![usize, u8, u16, u32, u64, isize, i8, i16, i32, i64, f32, f64, char, bool,];
|
||||||
f64 => f64,
|
|
||||||
|
|
||||||
char => char,
|
|
||||||
bool => bool,
|
|
||||||
];
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
mod std_support {
|
mod std_support {
|
||||||
|
@ -4,12 +4,23 @@
|
|||||||
//! but may end up executing arbitrary caller code if the value is complex.
|
//! but may end up executing arbitrary caller code if the value is complex.
|
||||||
//! They will also attempt to downcast erased types into a primitive where possible.
|
//! They will also attempt to downcast erased types into a primitive where possible.
|
||||||
|
|
||||||
use std::any::TypeId;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use super::{Erased, Inner, Primitive, Visitor};
|
use super::{Inner, Primitive, Visitor};
|
||||||
use crate::kv::value::{Error, Value};
|
use crate::kv::value::{Error, Value};
|
||||||
|
|
||||||
|
mod primitive;
|
||||||
|
|
||||||
|
/// Attempt to capture a primitive from some generic value.
|
||||||
|
///
|
||||||
|
/// If the value is a primitive type, then cast it here, avoiding needing to erase its value
|
||||||
|
/// This makes `Value`s produced by `Value::from_*` more useful
|
||||||
|
pub(super) fn try_from_primitive<'v, T: 'static>(value: &'v T) -> Option<Value<'v>> {
|
||||||
|
primitive::from_any(value).map(|primitive| Value {
|
||||||
|
inner: Inner::Primitive(primitive),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
impl<'v> Value<'v> {
|
impl<'v> Value<'v> {
|
||||||
/// Try get a `usize` from this value.
|
/// Try get a `usize` from this value.
|
||||||
///
|
///
|
||||||
@ -203,8 +214,9 @@ impl<'v> Inner<'v> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn borrowed_str(&mut self, v: &'v str) -> Result<(), Error> {
|
#[cfg(feature = "std")]
|
||||||
self.0 = Cast::Primitive(Primitive::Str(v));
|
fn str(&mut self, s: &str) -> Result<(), Error> {
|
||||||
|
self.0 = Cast::String(s.to_owned());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,9 +225,8 @@ impl<'v> Inner<'v> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
fn borrowed_str(&mut self, v: &'v str) -> Result<(), Error> {
|
||||||
fn str(&mut self, v: &str) -> Result<(), Error> {
|
self.0 = Cast::Primitive(Primitive::Str(v));
|
||||||
self.0 = Cast::String(v.into());
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,24 +242,14 @@ impl<'v> Inner<'v> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try downcast an erased value first
|
if let Inner::Primitive(value) = self {
|
||||||
// It also lets us avoid the Visitor infrastructure for simple primitives
|
Cast::Primitive(value)
|
||||||
let primitive = match self {
|
} else {
|
||||||
Inner::Primitive(value) => Some(value),
|
|
||||||
Inner::Fill(value) => value.downcast_primitive(),
|
|
||||||
Inner::Debug(value) => value.downcast_primitive(),
|
|
||||||
Inner::Display(value) => value.downcast_primitive(),
|
|
||||||
|
|
||||||
#[cfg(feature = "sval")]
|
|
||||||
Inner::Sval(value) => value.downcast_primitive(),
|
|
||||||
};
|
|
||||||
|
|
||||||
primitive.map(Cast::Primitive).unwrap_or_else(|| {
|
|
||||||
// If the erased value isn't a primitive then we visit it
|
// If the erased value isn't a primitive then we visit it
|
||||||
let mut cast = CastVisitor(Cast::Primitive(Primitive::None));
|
let mut cast = CastVisitor(Cast::Primitive(Primitive::None));
|
||||||
let _ = self.visit(&mut cast);
|
let _ = self.visit(&mut cast);
|
||||||
cast.0
|
cast.0
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -321,57 +322,6 @@ impl<'v> Primitive<'v> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'v, T: ?Sized + 'static> Erased<'v, T> {
|
|
||||||
// NOTE: This function is a perfect candidate for memoization
|
|
||||||
// The outcome could be stored in a `Cell<Primitive>`
|
|
||||||
fn downcast_primitive(self) -> Option<Primitive<'v>> {
|
|
||||||
macro_rules! type_ids {
|
|
||||||
($($value:ident : $ty:ty => $cast:expr,)*) => {{
|
|
||||||
struct TypeIds;
|
|
||||||
|
|
||||||
impl TypeIds {
|
|
||||||
fn downcast_primitive<'v, T: ?Sized>(&self, value: Erased<'v, T>) -> Option<Primitive<'v>> {
|
|
||||||
$(
|
|
||||||
if TypeId::of::<$ty>() == value.type_id {
|
|
||||||
let $value = unsafe { value.downcast_unchecked::<$ty>() };
|
|
||||||
return Some(Primitive::from($cast));
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeIds
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
let type_ids = type_ids![
|
|
||||||
value: usize => *value as u64,
|
|
||||||
value: u8 => *value as u64,
|
|
||||||
value: u16 => *value as u64,
|
|
||||||
value: u32 => *value as u64,
|
|
||||||
value: u64 => *value,
|
|
||||||
|
|
||||||
value: isize => *value as i64,
|
|
||||||
value: i8 => *value as i64,
|
|
||||||
value: i16 => *value as i64,
|
|
||||||
value: i32 => *value as i64,
|
|
||||||
value: i64 => *value,
|
|
||||||
|
|
||||||
value: f32 => *value as f64,
|
|
||||||
value: f64 => *value,
|
|
||||||
|
|
||||||
value: char => *value,
|
|
||||||
value: bool => *value,
|
|
||||||
|
|
||||||
value: &str => *value,
|
|
||||||
];
|
|
||||||
|
|
||||||
type_ids.downcast_primitive(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
mod std_support {
|
mod std_support {
|
||||||
use super::*;
|
use super::*;
|
195
src/kv/value/internal/cast/primitive.rs
Normal file
195
src/kv/value/internal/cast/primitive.rs
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
This module generates code to try efficiently convert some arbitrary `T: 'static` into
|
||||||
|
a `Primitive`. It's used by both the `build.rs` script and by the source itself. There
|
||||||
|
are currently two implementations here:
|
||||||
|
|
||||||
|
- When the compiler version is less than `1.46.0` we check type ids at runtime. This
|
||||||
|
means generating a pre-sorted list of type ids at compile time using the `build.rs`
|
||||||
|
and matching them at runtime.
|
||||||
|
- When the compiler version is at least `1.46.0` we use const evaluation to check type ids
|
||||||
|
at compile time. There's no generated code from `build.rs` involved.
|
||||||
|
|
||||||
|
In the future when `min_specialization` is stabilized we could use it instead and avoid needing
|
||||||
|
the `'static` bound altogether.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Use consts to match a type with a conversion fn
|
||||||
|
#[cfg(all(srcbuild, const_type_id))]
|
||||||
|
pub(super) fn from_any<'v, T: ?Sized + 'static>(
|
||||||
|
value: &'v T,
|
||||||
|
) -> Option<crate::kv::value::internal::Primitive<'v>> {
|
||||||
|
use std::any::TypeId;
|
||||||
|
|
||||||
|
use crate::kv::value::internal::Primitive;
|
||||||
|
|
||||||
|
macro_rules! to_primitive {
|
||||||
|
($($ty:ty : ($const_ident:ident, $option_ident:ident),)*) => {
|
||||||
|
trait ToPrimitive
|
||||||
|
where
|
||||||
|
Self: 'static,
|
||||||
|
{
|
||||||
|
const CALL: fn(&Self) -> Option<Primitive> = {
|
||||||
|
$(
|
||||||
|
const $const_ident: TypeId = TypeId::of::<$ty>();
|
||||||
|
const $option_ident: TypeId = TypeId::of::<Option<$ty>>();
|
||||||
|
);*
|
||||||
|
|
||||||
|
match TypeId::of::<Self>() {
|
||||||
|
$(
|
||||||
|
$const_ident => |v| Some(Primitive::from(unsafe { *(v as *const Self as *const $ty) })),
|
||||||
|
$option_ident => |v| Some({
|
||||||
|
let v = unsafe { *(v as *const Self as *const Option<$ty>) };
|
||||||
|
match v {
|
||||||
|
Some(v) => Primitive::from(v),
|
||||||
|
None => Primitive::None,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)*
|
||||||
|
|
||||||
|
_ => |_| None,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fn to_primitive(&self) -> Option<Primitive> {
|
||||||
|
(Self::CALL)(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + 'static> ToPrimitive for T {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: The types here *must* match the ones used below when `const_type_id` is not available
|
||||||
|
to_primitive![
|
||||||
|
usize: (USIZE, OPTION_USIZE),
|
||||||
|
u8: (U8, OPTION_U8),
|
||||||
|
u16: (U16, OPTION_U16),
|
||||||
|
u32: (U32, OPTION_U32),
|
||||||
|
u64: (U64, OPTION_U64),
|
||||||
|
|
||||||
|
isize: (ISIZE, OPTION_ISIZE),
|
||||||
|
i8: (I8, OPTION_I8),
|
||||||
|
i16: (I16, OPTION_I16),
|
||||||
|
i32: (I32, OPTION_I32),
|
||||||
|
i64: (I64, OPTION_I64),
|
||||||
|
|
||||||
|
f32: (F32, OPTION_F32),
|
||||||
|
f64: (F64, OPTION_F64),
|
||||||
|
|
||||||
|
char: (CHAR, OPTION_CHAR),
|
||||||
|
bool: (BOOL, OPTION_BOOL),
|
||||||
|
&'static str: (STR, OPTION_STR),
|
||||||
|
];
|
||||||
|
|
||||||
|
value.to_primitive()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(not(src_build), const_type_id))]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn generate() {}
|
||||||
|
|
||||||
|
// Use a build-time generated set of type ids to match a type with a conversion fn
|
||||||
|
#[cfg(all(srcbuild, not(const_type_id)))]
|
||||||
|
pub(super) fn from_any<'v>(
|
||||||
|
value: &'v (dyn std::any::Any + 'static),
|
||||||
|
) -> Option<crate::kv::value::internal::Primitive<'v>> {
|
||||||
|
// The set of type ids that map to primitives are generated at build-time
|
||||||
|
// by the contents of `sorted_type_ids.expr`. These type ids are pre-sorted
|
||||||
|
// so that they can be searched efficiently. See the `sorted_type_ids.expr.rs`
|
||||||
|
// file for the set of types that appear in this list
|
||||||
|
let type_ids = include!(concat!(env!("OUT_DIR"), "/into_primitive.rs"));
|
||||||
|
|
||||||
|
if let Ok(i) = type_ids.binary_search_by_key(&value.type_id(), |&(k, _)| k) {
|
||||||
|
Some((type_ids[i].1)(value))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the `src_build` config is not set then we're in the build script
|
||||||
|
#[cfg(all(not(srcbuild), not(const_type_id)))]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn generate() {
|
||||||
|
use std::path::Path;
|
||||||
|
use std::{env, fs};
|
||||||
|
|
||||||
|
macro_rules! type_ids {
|
||||||
|
($($ty:ty,)*) => {
|
||||||
|
[
|
||||||
|
$(
|
||||||
|
(
|
||||||
|
std::any::TypeId::of::<$ty>(),
|
||||||
|
stringify!(
|
||||||
|
(
|
||||||
|
std::any::TypeId::of::<$ty>(),
|
||||||
|
(|value| unsafe {
|
||||||
|
debug_assert_eq!(value.type_id(), std::any::TypeId::of::<$ty>());
|
||||||
|
|
||||||
|
// SAFETY: We verify the value is $ty before casting
|
||||||
|
let value = *(value as *const dyn std::any::Any as *const $ty);
|
||||||
|
crate::kv::value::internal::Primitive::from(value)
|
||||||
|
}) as for<'a> fn(&'a (dyn std::any::Any + 'static)) -> crate::kv::value::internal::Primitive<'a>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)*
|
||||||
|
$(
|
||||||
|
(
|
||||||
|
std::any::TypeId::of::<Option<$ty>>(),
|
||||||
|
stringify!(
|
||||||
|
(
|
||||||
|
std::any::TypeId::of::<Option<$ty>>(),
|
||||||
|
(|value| unsafe {
|
||||||
|
debug_assert_eq!(value.type_id(), std::any::TypeId::of::<Option<$ty>>());
|
||||||
|
|
||||||
|
// SAFETY: We verify the value is Option<$ty> before casting
|
||||||
|
let value = *(value as *const dyn std::any::Any as *const Option<$ty>);
|
||||||
|
if let Some(value) = value {
|
||||||
|
crate::kv::value::internal::Primitive::from(value)
|
||||||
|
} else {
|
||||||
|
crate::kv::value::internal::Primitive::None
|
||||||
|
}
|
||||||
|
}) as for<'a> fn(&'a (dyn std::any::Any + 'static)) -> crate::kv::value::internal::Primitive<'a>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)*
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: The types here *must* match the ones used above when `const_type_id` is available
|
||||||
|
let mut type_ids = type_ids![
|
||||||
|
usize,
|
||||||
|
u8,
|
||||||
|
u16,
|
||||||
|
u32,
|
||||||
|
u64,
|
||||||
|
isize,
|
||||||
|
i8,
|
||||||
|
i16,
|
||||||
|
i32,
|
||||||
|
i64,
|
||||||
|
f32,
|
||||||
|
f64,
|
||||||
|
char,
|
||||||
|
bool,
|
||||||
|
&'static str,
|
||||||
|
];
|
||||||
|
|
||||||
|
type_ids.sort_by_key(|&(k, _)| k);
|
||||||
|
|
||||||
|
let mut ordered_type_ids_expr = String::new();
|
||||||
|
|
||||||
|
ordered_type_ids_expr.push('[');
|
||||||
|
|
||||||
|
for (_, v) in &type_ids {
|
||||||
|
ordered_type_ids_expr.push_str(v);
|
||||||
|
ordered_type_ids_expr.push(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
ordered_type_ids_expr.push(']');
|
||||||
|
|
||||||
|
let path = Path::new(&env::var_os("OUT_DIR").unwrap()).join("into_primitive.rs");
|
||||||
|
fs::write(path, ordered_type_ids_expr).unwrap();
|
||||||
|
}
|
@ -5,28 +5,54 @@
|
|||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use super::{Erased, Inner, Visitor};
|
use super::{cast, Inner, Visitor};
|
||||||
use crate::kv;
|
use crate::kv;
|
||||||
use crate::kv::value::{Error, Slot};
|
use crate::kv::value::{Error, Slot, ToValue};
|
||||||
|
|
||||||
impl<'v> kv::Value<'v> {
|
impl<'v> kv::Value<'v> {
|
||||||
/// Get a value from a debuggable type.
|
/// Get a value from a debuggable type.
|
||||||
pub fn from_debug<T>(value: &'v T) -> Self
|
///
|
||||||
|
/// This method will attempt to capture the given value as a well-known primitive
|
||||||
|
/// before resorting to using its `Debug` implementation.
|
||||||
|
pub fn capture_debug<T>(value: &'v T) -> Self
|
||||||
where
|
where
|
||||||
T: fmt::Debug + 'static,
|
T: fmt::Debug + 'static,
|
||||||
{
|
{
|
||||||
kv::Value {
|
cast::try_from_primitive(value).unwrap_or(kv::Value {
|
||||||
inner: Inner::Debug(unsafe { Erased::new_unchecked::<T>(value) }),
|
inner: Inner::Debug(value),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a value from a debuggable type.
|
||||||
|
pub fn from_debug<T>(value: &'v T) -> Self
|
||||||
|
where
|
||||||
|
T: fmt::Debug,
|
||||||
|
{
|
||||||
|
kv::Value {
|
||||||
|
inner: Inner::Debug(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a value from a displayable type.
|
||||||
|
///
|
||||||
|
/// This method will attempt to capture the given value as a well-known primitive
|
||||||
|
/// before resorting to using its `Display` implementation.
|
||||||
|
pub fn capture_display<T>(value: &'v T) -> Self
|
||||||
|
where
|
||||||
|
T: fmt::Display + 'static,
|
||||||
|
{
|
||||||
|
cast::try_from_primitive(value).unwrap_or(kv::Value {
|
||||||
|
inner: Inner::Display(value),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a value from a displayable type.
|
/// Get a value from a displayable type.
|
||||||
pub fn from_display<T>(value: &'v T) -> Self
|
pub fn from_display<T>(value: &'v T) -> Self
|
||||||
where
|
where
|
||||||
T: fmt::Display + 'static,
|
T: fmt::Display,
|
||||||
{
|
{
|
||||||
kv::Value {
|
kv::Value {
|
||||||
inner: Inner::Display(unsafe { Erased::new_unchecked::<T>(value) }),
|
inner: Inner::Display(value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -201,24 +227,64 @@ impl<'v> fmt::Display for kv::Value<'v> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'v> ToValue for dyn fmt::Debug + 'v {
|
||||||
|
fn to_value(&self) -> kv::Value {
|
||||||
|
kv::Value::from(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'v> ToValue for dyn fmt::Display + 'v {
|
||||||
|
fn to_value(&self) -> kv::Value {
|
||||||
|
kv::Value::from(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'v> From<&'v (dyn fmt::Debug)> for kv::Value<'v> {
|
||||||
|
fn from(value: &'v (dyn fmt::Debug)) -> kv::Value<'v> {
|
||||||
|
kv::Value {
|
||||||
|
inner: Inner::Debug(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'v> From<&'v (dyn fmt::Display)> for kv::Value<'v> {
|
||||||
|
fn from(value: &'v (dyn fmt::Display)) -> kv::Value<'v> {
|
||||||
|
kv::Value {
|
||||||
|
inner: Inner::Display(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use kv::value::test::Token;
|
||||||
|
|
||||||
use crate::kv::value::ToValue;
|
use crate::kv::value::ToValue;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fmt_capture() {
|
||||||
|
assert_eq!(kv::Value::capture_debug(&1u16).to_token(), Token::U64(1));
|
||||||
|
assert_eq!(kv::Value::capture_display(&1u16).to_token(), Token::U64(1));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
kv::Value::capture_debug(&Some(1u16)).to_token(),
|
||||||
|
Token::U64(1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fmt_cast() {
|
fn fmt_cast() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
42u32,
|
42u32,
|
||||||
kv::Value::from_debug(&42u64)
|
kv::Value::capture_debug(&42u64)
|
||||||
.to_u32()
|
.to_u32()
|
||||||
.expect("invalid value")
|
.expect("invalid value")
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"a string",
|
"a string",
|
||||||
kv::Value::from_display(&"a string")
|
kv::Value::capture_display(&"a string")
|
||||||
.to_borrowed_str()
|
.to_borrowed_str()
|
||||||
.expect("invalid value")
|
.expect("invalid value")
|
||||||
);
|
);
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
//! This implementation isn't intended to be public. It may need to change
|
//! This implementation isn't intended to be public. It may need to change
|
||||||
//! for optimizations or to support new external serialization frameworks.
|
//! for optimizations or to support new external serialization frameworks.
|
||||||
|
|
||||||
use std::any::TypeId;
|
|
||||||
|
|
||||||
use super::{Error, Fill, Slot};
|
use super::{Error, Fill, Slot};
|
||||||
|
|
||||||
pub(super) mod cast;
|
pub(super) mod cast;
|
||||||
@ -18,27 +16,29 @@ pub(super) enum Inner<'v> {
|
|||||||
/// A simple primitive value that can be copied without allocating.
|
/// A simple primitive value that can be copied without allocating.
|
||||||
Primitive(Primitive<'v>),
|
Primitive(Primitive<'v>),
|
||||||
/// A value that can be filled.
|
/// A value that can be filled.
|
||||||
Fill(Erased<'v, dyn Fill + 'static>),
|
Fill(&'v (dyn Fill)),
|
||||||
/// A debuggable value.
|
/// A debuggable value.
|
||||||
Debug(Erased<'v, dyn fmt::Debug + 'static>),
|
Debug(&'v (dyn fmt::Debug)),
|
||||||
/// A displayable value.
|
/// A displayable value.
|
||||||
Display(Erased<'v, dyn fmt::Display + 'static>),
|
Display(&'v (dyn fmt::Display)),
|
||||||
|
|
||||||
#[cfg(feature = "kv_unstable_sval")]
|
#[cfg(feature = "kv_unstable_sval")]
|
||||||
/// A structured value from `sval`.
|
/// A structured value from `sval`.
|
||||||
Sval(Erased<'v, dyn sval::Value + 'static>),
|
Sval(&'v (dyn sval::Value)),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'v> Inner<'v> {
|
impl<'v> Inner<'v> {
|
||||||
pub(super) fn visit(self, visitor: &mut dyn Visitor<'v>) -> Result<(), Error> {
|
pub(super) fn visit(self, visitor: &mut dyn Visitor<'v>) -> Result<(), Error> {
|
||||||
match self {
|
match self {
|
||||||
Inner::Primitive(value) => value.visit(visitor),
|
Inner::Primitive(value) => value.visit(visitor),
|
||||||
Inner::Fill(value) => value.get().fill(&mut Slot::new(visitor)),
|
|
||||||
Inner::Debug(value) => visitor.debug(value.get()),
|
Inner::Debug(value) => visitor.debug(value),
|
||||||
Inner::Display(value) => visitor.display(value.get()),
|
Inner::Display(value) => visitor.display(value),
|
||||||
|
|
||||||
|
Inner::Fill(value) => value.fill(&mut Slot::new(visitor)),
|
||||||
|
|
||||||
#[cfg(feature = "kv_unstable_sval")]
|
#[cfg(feature = "kv_unstable_sval")]
|
||||||
Inner::Sval(value) => visitor.sval(value.get()),
|
Inner::Sval(value) => visitor.sval(value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,85 +97,114 @@ impl<'v> Primitive<'v> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'v> From<u8> for Primitive<'v> {
|
||||||
|
#[inline]
|
||||||
|
fn from(v: u8) -> Self {
|
||||||
|
Primitive::Unsigned(v as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'v> From<u16> for Primitive<'v> {
|
||||||
|
#[inline]
|
||||||
|
fn from(v: u16) -> Self {
|
||||||
|
Primitive::Unsigned(v as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'v> From<u32> for Primitive<'v> {
|
||||||
|
#[inline]
|
||||||
|
fn from(v: u32) -> Self {
|
||||||
|
Primitive::Unsigned(v as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'v> From<u64> for Primitive<'v> {
|
impl<'v> From<u64> for Primitive<'v> {
|
||||||
|
#[inline]
|
||||||
fn from(v: u64) -> Self {
|
fn from(v: u64) -> Self {
|
||||||
Primitive::Unsigned(v)
|
Primitive::Unsigned(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'v> From<usize> for Primitive<'v> {
|
||||||
|
#[inline]
|
||||||
|
fn from(v: usize) -> Self {
|
||||||
|
Primitive::Unsigned(v as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'v> From<i8> for Primitive<'v> {
|
||||||
|
#[inline]
|
||||||
|
fn from(v: i8) -> Self {
|
||||||
|
Primitive::Signed(v as i64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'v> From<i16> for Primitive<'v> {
|
||||||
|
#[inline]
|
||||||
|
fn from(v: i16) -> Self {
|
||||||
|
Primitive::Signed(v as i64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'v> From<i32> for Primitive<'v> {
|
||||||
|
#[inline]
|
||||||
|
fn from(v: i32) -> Self {
|
||||||
|
Primitive::Signed(v as i64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'v> From<i64> for Primitive<'v> {
|
impl<'v> From<i64> for Primitive<'v> {
|
||||||
|
#[inline]
|
||||||
fn from(v: i64) -> Self {
|
fn from(v: i64) -> Self {
|
||||||
Primitive::Signed(v)
|
Primitive::Signed(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'v> From<isize> for Primitive<'v> {
|
||||||
|
#[inline]
|
||||||
|
fn from(v: isize) -> Self {
|
||||||
|
Primitive::Signed(v as i64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'v> From<f32> for Primitive<'v> {
|
||||||
|
#[inline]
|
||||||
|
fn from(v: f32) -> Self {
|
||||||
|
Primitive::Float(v as f64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'v> From<f64> for Primitive<'v> {
|
impl<'v> From<f64> for Primitive<'v> {
|
||||||
|
#[inline]
|
||||||
fn from(v: f64) -> Self {
|
fn from(v: f64) -> Self {
|
||||||
Primitive::Float(v)
|
Primitive::Float(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'v> From<bool> for Primitive<'v> {
|
impl<'v> From<bool> for Primitive<'v> {
|
||||||
|
#[inline]
|
||||||
fn from(v: bool) -> Self {
|
fn from(v: bool) -> Self {
|
||||||
Primitive::Bool(v)
|
Primitive::Bool(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'v> From<char> for Primitive<'v> {
|
impl<'v> From<char> for Primitive<'v> {
|
||||||
|
#[inline]
|
||||||
fn from(v: char) -> Self {
|
fn from(v: char) -> Self {
|
||||||
Primitive::Char(v)
|
Primitive::Char(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'v> From<&'v str> for Primitive<'v> {
|
impl<'v> From<&'v str> for Primitive<'v> {
|
||||||
|
#[inline]
|
||||||
fn from(v: &'v str) -> Self {
|
fn from(v: &'v str) -> Self {
|
||||||
Primitive::Str(v)
|
Primitive::Str(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'v> From<fmt::Arguments<'v>> for Primitive<'v> {
|
impl<'v> From<fmt::Arguments<'v>> for Primitive<'v> {
|
||||||
|
#[inline]
|
||||||
fn from(v: fmt::Arguments<'v>) -> Self {
|
fn from(v: fmt::Arguments<'v>) -> Self {
|
||||||
Primitive::Fmt(v)
|
Primitive::Fmt(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A downcastable dynamic type.
|
|
||||||
pub(super) struct Erased<'v, T: ?Sized> {
|
|
||||||
type_id: TypeId,
|
|
||||||
inner: &'v T,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'v, T: ?Sized> Clone for Erased<'v, T> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Erased {
|
|
||||||
type_id: self.type_id,
|
|
||||||
inner: self.inner,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'v, T: ?Sized> Copy for Erased<'v, T> {}
|
|
||||||
|
|
||||||
impl<'v, T: ?Sized> Erased<'v, T> {
|
|
||||||
// SAFETY: `U: Unsize<T>` and the underlying value `T` must not change
|
|
||||||
// We could add a safe variant of this method with the `Unsize` trait
|
|
||||||
pub(super) unsafe fn new_unchecked<U>(inner: &'v T) -> Self
|
|
||||||
where
|
|
||||||
U: 'static,
|
|
||||||
T: 'static,
|
|
||||||
{
|
|
||||||
Erased {
|
|
||||||
type_id: TypeId::of::<U>(),
|
|
||||||
inner,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn get(self) -> &'v T {
|
|
||||||
self.inner
|
|
||||||
}
|
|
||||||
|
|
||||||
// SAFETY: The underlying type of `T` is `U`
|
|
||||||
pub(super) unsafe fn downcast_unchecked<U>(self) -> &'v U {
|
|
||||||
&*(self.inner as *const T as *const U)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -7,19 +7,32 @@ extern crate sval;
|
|||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use super::cast::Cast;
|
use super::cast::{self, Cast};
|
||||||
use super::{Erased, Inner, Primitive, Visitor};
|
use super::{Inner, Primitive, Visitor};
|
||||||
use crate::kv;
|
use crate::kv;
|
||||||
use crate::kv::value::{Error, Slot};
|
use crate::kv::value::{Error, Slot, ToValue};
|
||||||
|
|
||||||
impl<'v> kv::Value<'v> {
|
impl<'v> kv::Value<'v> {
|
||||||
/// Get a value from a structured type.
|
/// Get a value from a structured type.
|
||||||
pub fn from_sval<T>(value: &'v T) -> Self
|
///
|
||||||
|
/// This method will attempt to capture the given value as a well-known primitive
|
||||||
|
/// before resorting to using its `Value` implementation.
|
||||||
|
pub fn capture_sval<T>(value: &'v T) -> Self
|
||||||
where
|
where
|
||||||
T: sval::Value + 'static,
|
T: sval::Value + 'static,
|
||||||
|
{
|
||||||
|
cast::try_from_primitive(value).unwrap_or(kv::Value {
|
||||||
|
inner: Inner::Sval(value),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a value from a structured type.
|
||||||
|
pub fn from_sval<T>(value: &'v T) -> Self
|
||||||
|
where
|
||||||
|
T: sval::Value,
|
||||||
{
|
{
|
||||||
kv::Value {
|
kv::Value {
|
||||||
inner: Inner::Sval(unsafe { Erased::new_unchecked::<T>(value) }),
|
inner: Inner::Sval(value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,6 +103,20 @@ impl<'v> sval::Value for kv::Value<'v> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'v> ToValue for dyn sval::Value + 'v {
|
||||||
|
fn to_value(&self) -> kv::Value {
|
||||||
|
kv::Value::from(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'v> From<&'v (dyn sval::Value)> for kv::Value<'v> {
|
||||||
|
fn from(value: &'v (dyn sval::Value)) -> kv::Value<'v> {
|
||||||
|
kv::Value {
|
||||||
|
inner: Inner::Sval(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(in kv::value) use self::sval::Value;
|
pub(in kv::value) use self::sval::Value;
|
||||||
|
|
||||||
pub(super) fn fmt(f: &mut fmt::Formatter, v: &dyn sval::Value) -> Result<(), Error> {
|
pub(super) fn fmt(f: &mut fmt::Formatter, v: &dyn sval::Value) -> Result<(), Error> {
|
||||||
@ -155,30 +182,22 @@ mod tests {
|
|||||||
use kv::value::test::Token;
|
use kv::value::test::Token;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from_sval() {
|
fn sval_capture() {
|
||||||
assert_eq!(kv::Value::from_sval(&42u64).to_token(), Token::Sval);
|
assert_eq!(kv::Value::capture_sval(&42u64).to_token(), Token::U64(42));
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_sval_structured() {
|
|
||||||
let value = kv::Value::from(42u64);
|
|
||||||
let expected = vec![sval::test::Token::Unsigned(42)];
|
|
||||||
|
|
||||||
assert_eq!(sval::test::tokens(value), expected);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sval_cast() {
|
fn sval_cast() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
42u32,
|
42u32,
|
||||||
kv::Value::from_sval(&42u64)
|
kv::Value::capture_sval(&42u64)
|
||||||
.to_u32()
|
.to_u32()
|
||||||
.expect("invalid value")
|
.expect("invalid value")
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"a string",
|
"a string",
|
||||||
kv::Value::from_sval(&"a string")
|
kv::Value::capture_sval(&"a string")
|
||||||
.to_borrowed_str()
|
.to_borrowed_str()
|
||||||
.expect("invalid value")
|
.expect("invalid value")
|
||||||
);
|
);
|
||||||
@ -186,12 +205,20 @@ mod tests {
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"a string",
|
"a string",
|
||||||
kv::Value::from_sval(&"a string")
|
kv::Value::capture_sval(&"a string")
|
||||||
.to_str()
|
.to_str()
|
||||||
.expect("invalid value")
|
.expect("invalid value")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sval_structured() {
|
||||||
|
let value = kv::Value::from(42u64);
|
||||||
|
let expected = vec![sval::test::Token::Unsigned(42)];
|
||||||
|
|
||||||
|
assert_eq!(sval::test::tokens(value), expected);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sval_debug() {
|
fn sval_debug() {
|
||||||
struct TestSval;
|
struct TestSval;
|
||||||
@ -207,4 +234,19 @@ mod tests {
|
|||||||
format!("{:04?}", kv::Value::from_sval(&TestSval)),
|
format!("{:04?}", kv::Value::from_sval(&TestSval)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
mod std_support {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sval_cast() {
|
||||||
|
assert_eq!(
|
||||||
|
"a string",
|
||||||
|
kv::Value::capture_sval(&"a string".to_owned())
|
||||||
|
.to_str()
|
||||||
|
.expect("invalid value")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,11 +34,135 @@ impl<'v> ToValue for Value<'v> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A value in a structured key-value pair.
|
/// A value in a structured key-value pair.
|
||||||
|
///
|
||||||
|
/// # Capturing values
|
||||||
|
///
|
||||||
|
/// There are a few ways to capture a value:
|
||||||
|
///
|
||||||
|
/// - Using the `Value::capture_*` methods.
|
||||||
|
/// - Using the `Value::from_*` methods.
|
||||||
|
/// - Using the `ToValue` trait.
|
||||||
|
/// - Using the standard `From` trait.
|
||||||
|
/// - Using the `Fill` API.
|
||||||
|
///
|
||||||
|
/// ## Using the `Value::capture_*` methods
|
||||||
|
///
|
||||||
|
/// `Value` offers a few constructor methods that capture values of different kinds.
|
||||||
|
/// These methods require a `T: 'static` to support downcasting.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use log::kv::Value;
|
||||||
|
///
|
||||||
|
/// let value = Value::capture_debug(&42i32);
|
||||||
|
///
|
||||||
|
/// assert_eq!(Some(42), value.to_i32());
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Using the `Value::from_*` methods
|
||||||
|
///
|
||||||
|
/// `Value` offers a few constructor methods that capture values of different kinds.
|
||||||
|
/// These methods don't require `T: 'static`, but can't support downcasting.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use log::kv::Value;
|
||||||
|
///
|
||||||
|
/// let value = Value::from_debug(&42i32);
|
||||||
|
///
|
||||||
|
/// assert_eq!(None, value.to_i32());
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Using the `ToValue` trait
|
||||||
|
///
|
||||||
|
/// The `ToValue` trait can be used to capture values generically.
|
||||||
|
/// It's the bound used by `Source`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use log::kv::ToValue;
|
||||||
|
/// let value = 42i32.to_value();
|
||||||
|
///
|
||||||
|
/// assert_eq!(Some(42), value.to_i32());
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use std::fmt::Debug;
|
||||||
|
/// use log::kv::ToValue;
|
||||||
|
///
|
||||||
|
/// let value = (&42i32 as &dyn Debug).to_value();
|
||||||
|
///
|
||||||
|
/// assert_eq!(None, value.to_i32());
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Using the standard `From` trait
|
||||||
|
///
|
||||||
|
/// Standard types that implement `ToValue` also implement `From`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use log::kv::Value;
|
||||||
|
///
|
||||||
|
/// let value = Value::from(42i32);
|
||||||
|
///
|
||||||
|
/// assert_eq!(Some(42), value.to_i32());
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use std::fmt::Debug;
|
||||||
|
/// use log::kv::Value;
|
||||||
|
///
|
||||||
|
/// let value = Value::from(&42i32 as &dyn Debug);
|
||||||
|
///
|
||||||
|
/// assert_eq!(None, value.to_i32());
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Using the `Fill` API
|
||||||
|
///
|
||||||
|
/// The `Fill` trait is a way to bridge APIs that may not be directly
|
||||||
|
/// compatible with other constructor methods.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use log::kv::value::{Value, Slot, Fill, Error};
|
||||||
|
///
|
||||||
|
/// struct FillSigned;
|
||||||
|
///
|
||||||
|
/// impl Fill for FillSigned {
|
||||||
|
/// fn fill(&self, slot: &mut Slot) -> Result<(), Error> {
|
||||||
|
/// slot.fill_any(42i32)
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let value = Value::from_fill(&FillSigned);
|
||||||
|
///
|
||||||
|
/// assert_eq!(Some(42), value.to_i32());
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use std::fmt::Debug;
|
||||||
|
/// use log::kv::value::{Value, Slot, Fill, Error};
|
||||||
|
///
|
||||||
|
/// struct FillDebug;
|
||||||
|
///
|
||||||
|
/// impl Fill for FillDebug {
|
||||||
|
/// fn fill(&self, slot: &mut Slot) -> Result<(), Error> {
|
||||||
|
/// slot.fill_debug(&42i32 as &dyn Debug)
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let value = Value::from_fill(&FillDebug);
|
||||||
|
///
|
||||||
|
/// assert_eq!(None, value.to_i32());
|
||||||
|
/// ```
|
||||||
pub struct Value<'v> {
|
pub struct Value<'v> {
|
||||||
inner: Inner<'v>,
|
inner: Inner<'v>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'v> Value<'v> {
|
impl<'v> Value<'v> {
|
||||||
|
/// Get a value from a type implementing `ToValue`.
|
||||||
|
pub fn from_any<T>(value: &'v T) -> Self
|
||||||
|
where
|
||||||
|
T: ToValue,
|
||||||
|
{
|
||||||
|
value.to_value()
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a value from an internal primitive.
|
/// Get a value from an internal primitive.
|
||||||
fn from_primitive<T>(value: T) -> Self
|
fn from_primitive<T>(value: T) -> Self
|
||||||
where
|
where
|
||||||
|
Loading…
Reference in New Issue
Block a user