Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ std = []
# this will have a tighter MSRV before stabilization
kv_unstable = []
kv_unstable_sval = ["kv_unstable", "sval/fmt"]
kv_unstable_const_primitive = []
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just testing different strategies for destructuring.

kv_unstable_spec_primitive = []

[dependencies]
cfg-if = "0.1.2"
Expand Down
38 changes: 38 additions & 0 deletions benches/value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#![cfg(feature = "kv_unstable")]
#![feature(test)]

extern crate test;
extern crate log;

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)
})
}
9 changes: 9 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,21 @@

use std::env;

#[cfg(feature = "kv_unstable")]
#[path = "src/kv/value/internal/cast/primitive.rs"]
mod primitive;

fn main() {
let target = env::var("TARGET").unwrap();

if !target.starts_with("thumbv6") {
println!("cargo:rustc-cfg=atomic_cas");
}

#[cfg(feature = "kv_unstable")]
primitive::generate();

println!("cargo:rustc-cfg=src_build");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m using this so the into_primitive module can tell if it’s in the build script or not. Is there a cfg that exists already for this?


println!("cargo:rerun-if-changed=build.rs");
}
4 changes: 2 additions & 2 deletions src/kv/value/fill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use std::fmt;

use super::internal::{Erased, Inner, Visitor};
use super::internal::{Inner, Visitor};
use super::{Error, Value};

impl<'v> Value<'v> {
Expand All @@ -12,7 +12,7 @@ impl<'v> Value<'v> {
T: Fill + 'static,
{
Value {
inner: Inner::Fill(unsafe { Erased::new_unchecked::<T>(value) }),
inner: Inner::Fill(value),
}
}
}
Expand Down
66 changes: 33 additions & 33 deletions src/kv/value/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,6 @@ use std::fmt;

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 {
fn to_value(&self) -> Value {
Value::from(*self)
Expand Down Expand Up @@ -67,24 +49,42 @@ where
}
}

impl_into_owned! [
usize => u64,
u8 => u64,
u16 => u64,
u32 => u64,
u64 => u64,
macro_rules! impl_to_value_primitive {
($($into_ty:ty,)*) => {
$(
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)
}
}
)*
};
}

impl_to_value_primitive! [
usize,
u8,
u16,
u32,
u64,

isize => i64,
i8 => i64,
i16 => i64,
i32 => i64,
i64 => i64,
isize,
i8,
i16,
i32,
i64,

f32 => f64,
f64 => f64,
f32,
f64,

char => char,
bool => bool,
char,
bool,
];

#[cfg(feature = "std")]
Expand Down
93 changes: 21 additions & 72 deletions src/kv/value/internal/cast.rs → src/kv/value/internal/cast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,23 @@
//! 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.

use std::any::TypeId;
use std::fmt;

use super::{Erased, Inner, Primitive, Visitor};
use super::{Inner, Primitive, Visitor};
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> {
/// Try get a `usize` from this value.
///
Expand Down Expand Up @@ -203,8 +214,8 @@ impl<'v> Inner<'v> {
Ok(())
}

fn borrowed_str(&mut self, v: &'v str) -> Result<(), Error> {
self.0 = Cast::Primitive(Primitive::Str(v));
#[cfg(feature = "std")]
fn str(&mut self, _: &str) -> Result<(), Error> {
Ok(())
}

Expand All @@ -213,9 +224,8 @@ impl<'v> Inner<'v> {
Ok(())
}

#[cfg(feature = "std")]
fn str(&mut self, v: &str) -> Result<(), Error> {
self.0 = Cast::String(v.into());
fn borrowed_str(&mut self, v: &'v str) -> Result<(), Error> {
self.0 = Cast::Primitive(Primitive::Str(v));
Ok(())
}

Expand All @@ -231,24 +241,14 @@ impl<'v> Inner<'v> {
}
}

// Try downcast an erased value first
// It also lets us avoid the Visitor infrastructure for simple primitives
let primitive = match self {
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 let Inner::Primitive(value) = self {
Cast::Primitive(value)
} else {
// If the erased value isn't a primitive then we visit it
let mut cast = CastVisitor(Cast::Primitive(Primitive::None));
let _ = self.visit(&mut cast);
cast.0
})
}
}
}

Expand Down Expand Up @@ -321,57 +321,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")]
mod std_support {
use super::*;
Expand Down
Loading