1 //! Coerce a `Value` into some concrete types. 2 //! 3 //! These operations are cheap when the captured value is a simple primitive, 4 //! but may end up executing arbitrary caller code if the value is complex. 5 //! They will also attempt to downcast erased types into a primitive where possible. 6 7 use std::any::TypeId; 8 use std::fmt; 9 10 use super::{Erased, Inner, Primitive, Visitor}; 11 use crate::kv::value::{Error, Value}; 12 13 impl<'v> Value<'v> { 14 /// Try get a `usize` from this value. 15 /// 16 /// This method is cheap for primitive types, but may call arbitrary 17 /// serialization implementations for complex ones. to_usize(&self) -> Option<usize>18 pub fn to_usize(&self) -> Option<usize> { 19 self.inner 20 .cast() 21 .into_primitive() 22 .into_u64() 23 .map(|v| v as usize) 24 } 25 26 /// Try get a `u8` from this value. 27 /// 28 /// This method is cheap for primitive types, but may call arbitrary 29 /// serialization implementations for complex ones. to_u8(&self) -> Option<u8>30 pub fn to_u8(&self) -> Option<u8> { 31 self.inner 32 .cast() 33 .into_primitive() 34 .into_u64() 35 .map(|v| v as u8) 36 } 37 38 /// Try get a `u16` from this value. 39 /// 40 /// This method is cheap for primitive types, but may call arbitrary 41 /// serialization implementations for complex ones. to_u16(&self) -> Option<u16>42 pub fn to_u16(&self) -> Option<u16> { 43 self.inner 44 .cast() 45 .into_primitive() 46 .into_u64() 47 .map(|v| v as u16) 48 } 49 50 /// Try get a `u32` from this value. 51 /// 52 /// This method is cheap for primitive types, but may call arbitrary 53 /// serialization implementations for complex ones. to_u32(&self) -> Option<u32>54 pub fn to_u32(&self) -> Option<u32> { 55 self.inner 56 .cast() 57 .into_primitive() 58 .into_u64() 59 .map(|v| v as u32) 60 } 61 62 /// Try get a `u64` from this value. 63 /// 64 /// This method is cheap for primitive types, but may call arbitrary 65 /// serialization implementations for complex ones. to_u64(&self) -> Option<u64>66 pub fn to_u64(&self) -> Option<u64> { 67 self.inner.cast().into_primitive().into_u64() 68 } 69 70 /// Try get a `isize` from this value. 71 /// 72 /// This method is cheap for primitive types, but may call arbitrary 73 /// serialization implementations for complex ones. to_isize(&self) -> Option<isize>74 pub fn to_isize(&self) -> Option<isize> { 75 self.inner 76 .cast() 77 .into_primitive() 78 .into_i64() 79 .map(|v| v as isize) 80 } 81 82 /// Try get a `i8` from this value. 83 /// 84 /// This method is cheap for primitive types, but may call arbitrary 85 /// serialization implementations for complex ones. to_i8(&self) -> Option<i8>86 pub fn to_i8(&self) -> Option<i8> { 87 self.inner 88 .cast() 89 .into_primitive() 90 .into_i64() 91 .map(|v| v as i8) 92 } 93 94 /// Try get a `i16` from this value. 95 /// 96 /// This method is cheap for primitive types, but may call arbitrary 97 /// serialization implementations for complex ones. to_i16(&self) -> Option<i16>98 pub fn to_i16(&self) -> Option<i16> { 99 self.inner 100 .cast() 101 .into_primitive() 102 .into_i64() 103 .map(|v| v as i16) 104 } 105 106 /// Try get a `i32` from this value. 107 /// 108 /// This method is cheap for primitive types, but may call arbitrary 109 /// serialization implementations for complex ones. to_i32(&self) -> Option<i32>110 pub fn to_i32(&self) -> Option<i32> { 111 self.inner 112 .cast() 113 .into_primitive() 114 .into_i64() 115 .map(|v| v as i32) 116 } 117 118 /// Try get a `i64` from this value. 119 /// 120 /// This method is cheap for primitive types, but may call arbitrary 121 /// serialization implementations for complex ones. to_i64(&self) -> Option<i64>122 pub fn to_i64(&self) -> Option<i64> { 123 self.inner.cast().into_primitive().into_i64() 124 } 125 126 /// Try get a `f32` from this value. 127 /// 128 /// This method is cheap for primitive types, but may call arbitrary 129 /// serialization implementations for complex ones. to_f32(&self) -> Option<f32>130 pub fn to_f32(&self) -> Option<f32> { 131 self.inner 132 .cast() 133 .into_primitive() 134 .into_f64() 135 .map(|v| v as f32) 136 } 137 138 /// Try get a `f64` from this value. 139 /// 140 /// This method is cheap for primitive types, but may call arbitrary 141 /// serialization implementations for complex ones. to_f64(&self) -> Option<f64>142 pub fn to_f64(&self) -> Option<f64> { 143 self.inner.cast().into_primitive().into_f64() 144 } 145 146 /// Try get a `bool` from this value. 147 /// 148 /// This method is cheap for primitive types, but may call arbitrary 149 /// serialization implementations for complex ones. to_bool(&self) -> Option<bool>150 pub fn to_bool(&self) -> Option<bool> { 151 self.inner.cast().into_primitive().into_bool() 152 } 153 154 /// Try get a `char` from this value. 155 /// 156 /// This method is cheap for primitive types, but may call arbitrary 157 /// serialization implementations for complex ones. to_char(&self) -> Option<char>158 pub fn to_char(&self) -> Option<char> { 159 self.inner.cast().into_primitive().into_char() 160 } 161 162 /// Try get a `str` from this value. 163 /// 164 /// This method is cheap for primitive types. It won't allocate an owned 165 /// `String` if the value is a complex type. to_borrowed_str(&self) -> Option<&str>166 pub fn to_borrowed_str(&self) -> Option<&str> { 167 self.inner.cast().into_primitive().into_borrowed_str() 168 } 169 } 170 171 impl<'v> Inner<'v> { 172 /// Cast the inner value to another type. cast(self) -> Cast<'v>173 fn cast(self) -> Cast<'v> { 174 struct CastVisitor<'v>(Cast<'v>); 175 176 impl<'v> Visitor<'v> for CastVisitor<'v> { 177 fn debug(&mut self, _: &dyn fmt::Debug) -> Result<(), Error> { 178 Ok(()) 179 } 180 181 fn u64(&mut self, v: u64) -> Result<(), Error> { 182 self.0 = Cast::Primitive(Primitive::Unsigned(v)); 183 Ok(()) 184 } 185 186 fn i64(&mut self, v: i64) -> Result<(), Error> { 187 self.0 = Cast::Primitive(Primitive::Signed(v)); 188 Ok(()) 189 } 190 191 fn f64(&mut self, v: f64) -> Result<(), Error> { 192 self.0 = Cast::Primitive(Primitive::Float(v)); 193 Ok(()) 194 } 195 196 fn bool(&mut self, v: bool) -> Result<(), Error> { 197 self.0 = Cast::Primitive(Primitive::Bool(v)); 198 Ok(()) 199 } 200 201 fn char(&mut self, v: char) -> Result<(), Error> { 202 self.0 = Cast::Primitive(Primitive::Char(v)); 203 Ok(()) 204 } 205 206 fn borrowed_str(&mut self, v: &'v str) -> Result<(), Error> { 207 self.0 = Cast::Primitive(Primitive::Str(v)); 208 Ok(()) 209 } 210 211 #[cfg(not(feature = "std"))] 212 fn str(&mut self, _: &str) -> Result<(), Error> { 213 Ok(()) 214 } 215 216 #[cfg(feature = "std")] 217 fn str(&mut self, v: &str) -> Result<(), Error> { 218 self.0 = Cast::String(v.into()); 219 Ok(()) 220 } 221 222 fn none(&mut self) -> Result<(), Error> { 223 self.0 = Cast::Primitive(Primitive::None); 224 Ok(()) 225 } 226 227 #[cfg(feature = "kv_unstable_sval")] 228 fn sval(&mut self, v: &dyn super::sval::Value) -> Result<(), Error> { 229 self.0 = super::sval::cast(v); 230 Ok(()) 231 } 232 } 233 234 // Try downcast an erased value first 235 // It also lets us avoid the Visitor infrastructure for simple primitives 236 let primitive = match self { 237 Inner::Primitive(value) => Some(value), 238 Inner::Fill(value) => value.downcast_primitive(), 239 Inner::Debug(value) => value.downcast_primitive(), 240 Inner::Display(value) => value.downcast_primitive(), 241 242 #[cfg(feature = "sval")] 243 Inner::Sval(value) => value.downcast_primitive(), 244 }; 245 246 primitive.map(Cast::Primitive).unwrap_or_else(|| { 247 // If the erased value isn't a primitive then we visit it 248 let mut cast = CastVisitor(Cast::Primitive(Primitive::None)); 249 let _ = self.visit(&mut cast); 250 cast.0 251 }) 252 } 253 } 254 255 pub(super) enum Cast<'v> { 256 Primitive(Primitive<'v>), 257 #[cfg(feature = "std")] 258 String(String), 259 } 260 261 impl<'v> Cast<'v> { into_primitive(self) -> Primitive<'v>262 fn into_primitive(self) -> Primitive<'v> { 263 match self { 264 Cast::Primitive(value) => value, 265 #[cfg(feature = "std")] 266 _ => Primitive::None, 267 } 268 } 269 } 270 271 impl<'v> Primitive<'v> { into_borrowed_str(self) -> Option<&'v str>272 fn into_borrowed_str(self) -> Option<&'v str> { 273 if let Primitive::Str(value) = self { 274 Some(value) 275 } else { 276 None 277 } 278 } 279 into_u64(self) -> Option<u64>280 fn into_u64(self) -> Option<u64> { 281 match self { 282 Primitive::Unsigned(value) => Some(value), 283 Primitive::Signed(value) => Some(value as u64), 284 Primitive::Float(value) => Some(value as u64), 285 _ => None, 286 } 287 } 288 into_i64(self) -> Option<i64>289 fn into_i64(self) -> Option<i64> { 290 match self { 291 Primitive::Signed(value) => Some(value), 292 Primitive::Unsigned(value) => Some(value as i64), 293 Primitive::Float(value) => Some(value as i64), 294 _ => None, 295 } 296 } 297 into_f64(self) -> Option<f64>298 fn into_f64(self) -> Option<f64> { 299 match self { 300 Primitive::Float(value) => Some(value), 301 Primitive::Unsigned(value) => Some(value as f64), 302 Primitive::Signed(value) => Some(value as f64), 303 _ => None, 304 } 305 } 306 into_char(self) -> Option<char>307 fn into_char(self) -> Option<char> { 308 if let Primitive::Char(value) = self { 309 Some(value) 310 } else { 311 None 312 } 313 } 314 into_bool(self) -> Option<bool>315 fn into_bool(self) -> Option<bool> { 316 if let Primitive::Bool(value) = self { 317 Some(value) 318 } else { 319 None 320 } 321 } 322 } 323 324 impl<'v, T: ?Sized + 'static> Erased<'v, T> { 325 // NOTE: This function is a perfect candidate for memoization 326 // The outcome could be stored in a `Cell<Primitive>` downcast_primitive(self) -> Option<Primitive<'v>>327 fn downcast_primitive(self) -> Option<Primitive<'v>> { 328 macro_rules! type_ids { 329 ($($value:ident : $ty:ty => $cast:expr,)*) => {{ 330 struct TypeIds; 331 332 impl TypeIds { 333 fn downcast_primitive<'v, T: ?Sized>(&self, value: Erased<'v, T>) -> Option<Primitive<'v>> { 334 $( 335 if TypeId::of::<$ty>() == value.type_id { 336 let $value = unsafe { value.downcast_unchecked::<$ty>() }; 337 return Some(Primitive::from($cast)); 338 } 339 )* 340 341 None 342 } 343 } 344 345 TypeIds 346 }}; 347 } 348 349 let type_ids = type_ids![ 350 value: usize => *value as u64, 351 value: u8 => *value as u64, 352 value: u16 => *value as u64, 353 value: u32 => *value as u64, 354 value: u64 => *value, 355 356 value: isize => *value as i64, 357 value: i8 => *value as i64, 358 value: i16 => *value as i64, 359 value: i32 => *value as i64, 360 value: i64 => *value, 361 362 value: f32 => *value as f64, 363 value: f64 => *value, 364 365 value: char => *value, 366 value: bool => *value, 367 368 value: &str => *value, 369 ]; 370 371 type_ids.downcast_primitive(self) 372 } 373 } 374 375 #[cfg(feature = "std")] 376 mod std_support { 377 use super::*; 378 379 use std::borrow::Cow; 380 381 impl<'v> Value<'v> { 382 /// Try get a `usize` from this value. 383 /// 384 /// This method is cheap for primitive types, but may call arbitrary 385 /// serialization implementations for complex ones. If the serialization 386 /// implementation produces a short lived string it will be allocated. to_str(&self) -> Option<Cow<str>>387 pub fn to_str(&self) -> Option<Cow<str>> { 388 self.inner.cast().into_str() 389 } 390 } 391 392 impl<'v> Cast<'v> { into_str(self) -> Option<Cow<'v, str>>393 pub(super) fn into_str(self) -> Option<Cow<'v, str>> { 394 match self { 395 Cast::Primitive(Primitive::Str(value)) => Some(value.into()), 396 Cast::String(value) => Some(value.into()), 397 _ => None, 398 } 399 } 400 } 401 402 #[cfg(test)] 403 mod tests { 404 use crate::kv::ToValue; 405 406 #[test] primitive_cast()407 fn primitive_cast() { 408 assert_eq!( 409 "a string", 410 "a string" 411 .to_owned() 412 .to_value() 413 .to_borrowed_str() 414 .expect("invalid value") 415 ); 416 assert_eq!( 417 "a string", 418 &*"a string".to_value().to_str().expect("invalid value") 419 ); 420 assert_eq!( 421 "a string", 422 &*"a string" 423 .to_owned() 424 .to_value() 425 .to_str() 426 .expect("invalid value") 427 ); 428 } 429 } 430 } 431 432 #[cfg(test)] 433 mod tests { 434 use crate::kv::ToValue; 435 436 #[test] primitive_cast()437 fn primitive_cast() { 438 assert_eq!( 439 "a string", 440 "a string" 441 .to_value() 442 .to_borrowed_str() 443 .expect("invalid value") 444 ); 445 assert_eq!( 446 "a string", 447 Some("a string") 448 .to_value() 449 .to_borrowed_str() 450 .expect("invalid value") 451 ); 452 453 assert_eq!(1u8, 1u64.to_value().to_u8().expect("invalid value")); 454 assert_eq!(1u16, 1u64.to_value().to_u16().expect("invalid value")); 455 assert_eq!(1u32, 1u64.to_value().to_u32().expect("invalid value")); 456 assert_eq!(1u64, 1u64.to_value().to_u64().expect("invalid value")); 457 assert_eq!(1usize, 1u64.to_value().to_usize().expect("invalid value")); 458 459 assert_eq!(-1i8, -1i64.to_value().to_i8().expect("invalid value")); 460 assert_eq!(-1i16, -1i64.to_value().to_i16().expect("invalid value")); 461 assert_eq!(-1i32, -1i64.to_value().to_i32().expect("invalid value")); 462 assert_eq!(-1i64, -1i64.to_value().to_i64().expect("invalid value")); 463 assert_eq!(-1isize, -1i64.to_value().to_isize().expect("invalid value")); 464 465 assert!(1f32.to_value().to_f32().is_some(), "invalid value"); 466 assert!(1f64.to_value().to_f64().is_some(), "invalid value"); 467 468 assert_eq!(1u32, 1i64.to_value().to_u32().expect("invalid value")); 469 assert_eq!(1i32, 1u64.to_value().to_i32().expect("invalid value")); 470 assert!(1f32.to_value().to_i32().is_some(), "invalid value"); 471 472 assert_eq!('a', 'a'.to_value().to_char().expect("invalid value")); 473 assert_eq!(true, true.to_value().to_bool().expect("invalid value")); 474 } 475 } 476