Loading page…
Rust walkthroughs
Loading page…
{"args":{"content":"# What is the purpose of serde::de::IntoDeserializer and how does it enable deserializing from non-standard types?
IntoDeserializer is a trait that converts a value into a Deserializer, enabling that value to be used as a deserialization source without implementing the full Deserializer trait manually. This allows non-collection types to be deserialized from—for example, deserializing a struct from a String value, or deserializing from a serde_json::Value without writing custom deserialization logic. The trait bridges the gap between having a value and needing a Deserializer, making it possible to use existing values as deserialization sources for derived types. Use IntoDeserializer when you need to deserialize one type into another related type, when working with dynamic values, or when implementing custom deserialization that delegates to simpler types.
use serde::de::IntoDeserializer;
use serde::Deserialize;
fn main() -> Result<(), serde_json::Error> {
// String implements IntoDeserializer
let value = \"hello\".to_string();
let deserializer = value.into_deserializer();
// Can deserialize the String into any type that expects a string
let result: String = String::deserialize(deserializer)?;
println!(\"Deserialized: {}\", result);
Ok(())
}into_deserializer() converts a value into a Deserializer for that value's type.
use serde::de::IntoDeserializer;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct UserId(String);
fn main() -> Result<(), serde_json::Error> {
// String can deserialize into types expecting strings
let id_string = \"user-123\".to_string();
let deserializer = id_string.into_deserializer();
// Deserialize String into UserId
let user_id: UserId = UserId::deserialize(deserializer)?;
println!(\"User ID: {:?}\", user_id);
Ok(())
}IntoDeserializer enables converting primitive types into derived types.
use serde::de::IntoDeserializer;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Config {
name: String,
value: i32,
}
fn main() -> Result<(), serde_json::Error> {
// serde_json::Value implements IntoDeserializer
let json_value = serde_json::json!({
\"name\": \"test\",
\"value\": 42
});
// Deserialize Value directly into Config
let deserializer = json_value.into_deserializer();
let config: Config = Config::deserialize(deserializer)?;
println!(\"Config: {:?}\", config);
Ok(())
}serde_json::Value implements IntoDeserializer, enabling direct deserialization.
use serde::de::IntoDeserializer;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
#[serde(transparent)]
struct PositiveInt(u64);
fn main() -> Result<(), serde_json::Error> {
// i32 can be deserialized into u64 (if value fits)
let small_int: i32 = 100;
let deserializer = small_int.into_deserializer();
let positive: PositiveInt = PositiveInt::deserialize(deserializer)?;
println!(\"Positive int: {:?}\", positive);
// Note: deserializing negative i32 into u64 would fail
// This is type conversion via deserialization
Ok(())
}IntoDeserializer enables numeric type conversions through deserialization.
use serde::de::IntoDeserializer;
use serde::Deserialize;
use std::collections::HashMap;
#[derive(Debug, Deserialize)]
struct Person {
name: String,
age: u32,
}
fn main() -> Result<(), serde_json::Error> {
// HashMap can be used as a deserializer source
let mut map = HashMap::new();
map.insert(\"name\", \"Alice\");
map.insert(\"age\", \"30\"); // String values
// This requires more complex handling - IntoDeserializer
// for HashMap values gives string deserializers
let deserializer = map.into_deserializer();
// Note: This doesn't directly work because HashMap<String, &str>
// deserializes differently than a struct
// More common: use serde_json::Value or similar
let json_map = serde_json::json!({
\"name\": \"Bob\",
\"age\": 25
});
let person: Person = Person::deserialize(json_map.into_deserializer())?;
println!(\"Person: {:?}\", person);
Ok(())
}IntoDeserializer works with collection types that implement it.
use serde::de::IntoDeserializer;
use serde::Deserialize;
#[derive(Debug)]
struct RawData(String);
#[derive(Debug, Deserialize)]
struct ParsedData {
id: u32,
name: String,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let raw = RawData(\"123:Alice\".to_string());
// Parse RawData into ParsedData
// First, parse the string, then deserialize
let parts: Vec<&str> = raw.0.split(':').collect();
let json_value = serde_json::json!({
\"id\": parts[0].parse::<u32>()?,
\"name\": parts[1]
});
let parsed: ParsedData = ParsedData::deserialize(json_value.into_deserializer())?;
println!(\"Parsed: {:?}\", parsed);
Ok(())
}IntoDeserializer bridges custom types through intermediate representations.
use serde::de::{IntoDeserializer, Deserializer, Error, Visitor};
use serde::Deserialize;
use std::fmt;
#[derive(Debug, Clone)]
struct UserId(u64);
impl<'de> IntoDeserializer<'de> for UserId {
type Deserializer = UserIdDeserializer;
fn into_deserializer(self) -> Self::Deserializer {
UserIdDeserializer(self.0)
}
}
struct UserIdDeserializer(u64);
impl<'de> Deserializer<'de> for UserIdDeserializer {
type Error = serde::de::value::Error;
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_u64(self.0)
}
// Implement other deserialize methods as needed...
serde::forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 i8 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
}
#[derive(Debug, Deserialize)]
struct User {
id: u64,
}
fn main() -> Result<(), serde::de::value::Error> {
let user_id = UserId(42);
let deserializer = user_id.into_deserializer();
// Can deserialize into types expecting u64
let id: u64 = u64::deserialize(deserializer)?;
println!(\"ID: {}\", id);
Ok(())
}Implementing IntoDeserializer enables custom types as deserialization sources.
use serde::de::IntoDeserializer;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
enum Status {
Active,
Inactive,
Pending,
}
fn main() -> Result<(), serde::de::value::Error> {
// String can be deserialized into enum variants
let status_str = \"Active\";
let deserializer = status_str.into_deserializer();
let status: Status = Status::deserialize(deserializer)?;
println!(\"Status: {:?}\", status);
// Works with variant names
let status_str = \"Inactive\";
let status: Status = Status::deserialize(status_str.into_deserializer())?;
println!(\"Status: {:?}\\", status);
Ok(())
}IntoDeserializer on strings enables enum deserialization.
use serde::de::{IntoDeserializer, value};
use serde::Deserialize;
fn main() -> Result<(), serde::de::value::Error> {
// serde::de::value provides IntoDeserializer implementations
// for primitive types
// String deserializer
let s = value::StrDeserializer::new(\"hello\");
let result: String = String::deserialize(s)?;
println!(\"String: {}\", result);
// Number deserializer
let n = value::U64Deserializer::new(42u64);
let result: u64 = u64::deserialize(n)?;
println!(\"Number: {}\", result);
// Bool deserializer
let b = value::BoolDeserializer::new(true);
let result: bool = bool::deserialize(b)?;
println!(\"Bool: {}\", result);
Ok(())
}serde::de::value provides typed deserializers for primitive values.
use serde::de::{IntoDeserializer, value};
use serde::Deserialize;
fn main() -> Result<(), serde::de::value::Error> {
// Deserialize from a Vec using SeqDeserializer
let items = vec![1u32, 2, 3, 4, 5];
// Create a sequence deserializer
let seq = value::SeqDeserializer::new(items.into_iter());
// Deserialize into Vec
let result: Vec<u32> = Vec::deserialize(seq)?;
println!(\"Vec: {:?}\", result);
// Or into a tuple
let items = vec![10u32, 20];
let seq = value::SeqDeserializer::new(items.into_iter());
let (a, b): (u32, u32) = Deserialize::deserialize(seq)?;
println!(\"Tuple: ({}, {})\", a, b);
Ok(())
}SeqDeserializer enables deserializing from iterators.
use serde::de::{IntoDeserializer, value};
use serde::Deserialize;
use std::collections::HashMap;
#[derive(Debug, Deserialize)]
struct Point {
x: i32,
y: i32,
}
fn main() -> Result<(), serde::de::value::Error> {
// Deserialize from a HashMap
let mut map = HashMap::new();
map.insert(\"x\", 10i32);
map.insert(\"y\", 20i32);
let map_de = value::MapDeserializer::new(map.into_iter());
let point: Point = Point::deserialize(map_de)?;
println!(\"Point: {:?}\", point);
Ok(())
}MapDeserializer enables deserializing structs from key-value pairs.
use serde::de::IntoDeserializer;
use serde::Deserialize;
fn main() {
// Type mismatches cause deserialization errors
let number = \"not a number\".to_string();
let deserializer = number.into_deserializer();
let result: Result<u64, _> = u64::deserialize(deserializer);
match result {
Ok(n) => println!(\"Number: {}\", n),
Err(e) => println!(\"Error: {}\", e),
}
// Enum variant errors
let status = \"Unknown\".to_string();
let deserializer = status.into_deserializer();
#[derive(Debug, Deserialize)]
enum Status {
Active,
Inactive,
}
let result: Result<Status, _> = Status::deserialize(deserializer);
match result {
Ok(s) => println!(\"Status: {:?}\", s),
Err(e) => println!(\"Error: {}\", e),
}
}IntoDeserializer produces errors for type mismatches.
use serde::de::IntoDeserializer;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
#[serde(rename_all = \"SCREAMING_SNAKE_CASE\")]
enum Priority {
HighPriority,
MediumPriority,
LowPriority,
}
fn main() -> Result<(), serde::de::value::Error> {
// IntoDeserializer respects serde attributes
let priority_str = \"HIGH_PRIORITY\";
let deserializer = priority_str.into_deserializer();
let priority: Priority = Priority::deserialize(deserializer)?;
println!(\"Priority: {:?}\", priority);
Ok(())
}IntoDeserializer respects serde attributes like rename_all.
use serde::de::IntoDeserializer;
use serde::Deserialize;
fn main() -> Result<(), serde::de::value::Error> {
// Unit type deserialization
let unit = value::UnitDeserializer::new();
let result: () = <()>::deserialize(unit)?;
println!(\"Unit: {:?}\", result);
// Optional values
let some_value = value::SomeDeserializer::new(value::U64Deserializer::new(42));
let result: Option<u64> = Option::deserialize(some_value)?;
println!(\"Some: {:?}\", result);
let none_value = value::NoneDeserializer::new();
let result: Option<u64> = Option::deserialize(none_value)?;
println!(\"None: {:?}\", result);
Ok(())
}serde::de::value provides deserializers for unit and optional types.
use serde::de::IntoDeserializer;
use serde::Deserialize;
#[derive(Debug, Deserialize, Default)]
struct Config {
host: String,
port: u16,
#[serde(default)]
debug: bool,
}
impl Config {
fn from_json_value(value: serde_json::Value) -> Result<Self, serde_json::Error> {
Config::deserialize(value.into_deserializer())
}
fn from_map(map: std::collections::HashMap<&str, serde_json::Value>) -> Result<Self, serde_json::Error> {
// Convert HashMap to Value then deserialize
let value = serde_json::Value::Object(
map.into_iter()
.map(|(k, v)| (k.to_string(), v))
.collect()
);
Config::deserialize(value.into_deserializer())
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config_value = serde_json::json!({
\"host\": \"localhost\",
\"port\": 8080
});
let config = Config::from_json_value(config_value)?;
println!(\"Config: {:?}\", config);
Ok(())
}IntoDeserializer enables flexible configuration parsing.
IntoDeserializer purpose:
Deserializer instancesDeserializerBuilt-in implementations:
String, &str → StrDeserializeru8, u16, u32, u64, u128 → numeric deserializersi8, i16, i32, i64, i128 → numeric deserializersbool → BoolDeserializerserde_json::Value → JSON deserializer() → UnitDeserializerserde::de::value module:
StrDeserializer::new() for stringsU64Deserializer::new(), I64Deserializer::new(), etc. for numbersBoolDeserializer::new() for booleansSeqDeserializer::new() for sequencesMapDeserializer::new() for mapsUnitDeserializer::new() for unit typesSomeDeserializer::new(), NoneDeserializer::new() for OptionalsUse cases:
From<SomeType> for deserializable typesImplementing IntoDeserializer:
Deserializer typeinto_deserializer() methodDeserializer must implement the Deserializer traitKey insight: IntoDeserializer is the trait that makes values usable as deserialization sources. Instead of implementing the full Deserializer trait (with all its methods), you implement IntoDeserializer which returns a deserializer for your value. This is particularly useful when you have a value of one type and need to deserialize it into another type—like converting a String into a UserId(String) newtype, or a serde_json::Value into a struct. The serde::de::value module provides ready-made deserializers for primitive types, so you can compose them for complex types. This pattern enables type-safe conversions, dynamic deserialization from parsed data, and custom deserialization that delegates to simpler types rather than implementing the full Visitor pattern manually.","path":"/articles/293_serde_into_deserializer.md"},"tool_call":"file.create"}