What is the purpose of serde::de::DeserializeSeed for context-aware deserialization?

serde::de::DeserializeSeed is a trait that enables passing external context into the deserialization process, allowing types to be deserialized with access to data that isn't present in the serialized form. While standard Deserialize creates values solely from serialized data, DeserializeSeed carries a "seed" value that deserializers can use to construct types that require additional information—such as registry lookups, configuration data, or references to existing structures. This mechanism is essential for deserializing trait objects, implementing dependency injection during deserialization, and building types that need runtime context not stored in the serialized format.

Basic DeserializeSeed Trait

use serde::de::{DeserializeSeed, Deserializer, Visitor, Error};
use std::marker::PhantomData;
 
// A simple seed that provides context during deserialization
struct ContextualSeed<'a, T> {
    context: &'a str,
    _marker: PhantomData<T>,
}
 
impl<'de, 'a, T> DeserializeSeed<'de> for ContextualSeed<'a, T>
where
    T: serde::Deserialize<'de>,
{
    type Value = (T, &'a str);
    
    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        // First deserialize the value normally
        let value: T = T::deserialize(deserializer)?;
        // Then combine with context
        Ok((value, self.context))
    }
}
 
fn main() {
    let json = "42";
    let seed = ContextualSeed::<i32> {
        context: "my_context",
        _marker: PhantomData,
    };
    
    let result: (i32, &str) = seed.deserialize(&mut serde_json::Deserializer::from_str(json)).unwrap();
    println!("Value: {}, Context: {}", result.0, result.1);
}

DeserializeSeed defines an associated Value type and receives a deserializer to produce a value.

Motivating Use Case: Registry Lookup

use serde::{Deserialize, de::{DeserializeSeed, Deserializer, Visitor, Error}};
use std::collections::HashMap;
 
// A registry of item creators
type ItemCreator = fn(serde_json::Value) -> Result<Box<dyn Item>, String>;
 
trait Item {
    fn name(&self) -> &str;
    fn as_any(&self) -> &dyn std::any::Any;
}
 
#[derive(Deserialize)]
struct ItemDef {
    #[serde(rename = "type")]
    item_type: String,
    data: serde_json::Value,
}
 
// Seed that uses a registry to create items
struct ItemSeed {
    registry: HashMap<String, ItemCreator>,
}
 
impl<'de> DeserializeSeed<'de> for ItemSeed {
    type Value = Box<dyn Item>;
    
    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        let def = ItemDef::deserialize(deserializer)?;
        
        let creator = self.registry.get(&def.item_type)
            .ok_or_else(|| D::Error::custom(format!("Unknown type: {}", def.item_type)))?;
        
        creator(def.data).map_err(D::Error::custom)
    }
}
 
// Concrete item types
struct Sword { name: String, damage: u32 }
impl Item for Sword {
    fn name(&self) -> &str { &self.name }
    fn as_any(&self) -> &dyn std::any::Any { self }
}
 
struct Potion { name: String, healing: u32 }
impl Item for Potion {
    fn name(&self) -> &str { &self.name }
    fn as_any(&self) -> &dyn std::any::Any { self }
}
 
fn main() {
    let mut registry: HashMap<String, ItemCreator> = HashMap::new();
    
    registry.insert("sword".to_string(), |data| {
        let name = data["name"].as_str().unwrap().to_string();
        let damage = data["damage"].as_u64().unwrap() as u32;
        Ok(Box::new(Sword { name, damage }))
    });
    
    registry.insert("potion".to_string(), |data| {
        let name = data["name"].as_str().unwrap().to_string();
        let healing = data["healing"].as_u64().unwrap() as u32;
        Ok(Box::new(Potion { name, healing }))
    });
    
    let json = r#"{"type": "sword", "data": {"name": "Excalibur", "damage": 50}}"#;
    
    let seed = ItemSeed { registry };
    let item: Box<dyn Item> = seed.deserialize(
        &mut serde_json::Deserializer::from_str(json)
    ).unwrap();
    
    println!("Item: {}", item.name());
}

The seed provides a registry that maps type names to constructors.

Context for Referenced Data

use serde::{Deserialize, de::{DeserializeSeed, Deserializer, Error}};
use std::collections::HashMap;
 
// User data that references a shared configuration
#[derive(Debug)]
struct User {
    id: u32,
    name: String,
    config_ref: String,
    config: &'static Config,
}
 
#[derive(Debug, Clone)]
struct Config {
    theme: String,
    language: String,
}
 
// Seed provides the config registry
struct UserSeed {
    configs: HashMap<String, &'static Config>,
}
 
impl<'de> DeserializeSeed<'de> for UserSeed {
    type Value = User;
    
    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        // Temp struct to deserialize from JSON
        #[derive(Deserialize)]
        struct UserDef {
            id: u32,
            name: String,
            config_ref: String,
        }
        
        let def = UserDef::deserialize(deserializer)?;
        
        // Look up config from registry
        let config = self.configs.get(&def.config_ref)
            .ok_or_else(|| D::Error::custom(format!("Unknown config: {}", def.config_ref)))?;
        
        Ok(User {
            id: def.id,
            name: def.name,
            config_ref: def.config_ref,
            config: *config,
        })
    }
}
 
fn main() {
    // In real code, configs would be leaked or stored elsewhere
    let config1 = Box::leak(Box::new(Config {
        theme: "dark".to_string(),
        language: "en".to_string(),
    }));
    
    let mut configs: HashMap<String, &'static Config> = HashMap::new();
    configs.insert("default".to_string(), config1);
    
    let json = r#"{"id": 1, "name": "Alice", "config_ref": "default"}"#;
    
    let seed = UserSeed { configs };
    let user: User = seed.deserialize(
        &mut serde_json::Deserializer::from_str(json)
    ).unwrap();
    
    println!("User: {} (theme: {})", user.name, user.config.theme);
}

Deserialized structures can reference external data not stored in the serialized format.

Seed Cloning for Collections

use serde::de::{DeserializeSeed, Deserializer, Visitor, SeqAccess, Error};
use std::marker::PhantomData;
 
// Context that needs to be passed to each element
struct Context {
    multiplier: f64,
}
 
#[derive(Debug)]
struct ValueWithContext {
    value: f64,
    result: f64,
}
 
// Seed that clones context for each element
struct ValueSeed {
    context: Context,
}
 
impl<'de> DeserializeSeed<'de> for ValueSeed {
    type Value = ValueWithContext;
    
    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        let value: f64 = f64::deserialize(deserializer)?;
        Ok(ValueWithContext {
            value,
            result: value * self.context.multiplier,
        })
    }
}
 
// Clone-capable seed for collections
struct SeqSeed {
    context: Context,
}
 
impl<'de> DeserializeSeed<'de> for SeqSeed {
    type Value = Vec<ValueWithContext>;
    
    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct SeqVisitor {
            context: Context,
        }
        
        impl<'de> Visitor<'de> for SeqVisitor {
            type Value = Vec<ValueWithContext>;
            
            fn expecting(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
                write!(fmt, "a sequence")
            }
            
            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
            where
                A: SeqAccess<'de>,
            {
                let mut values = Vec::new();
                while let Some(value) = seq.next_element_seed(ValueSeed {
                    context: Context { multiplier: self.context.multiplier },
                })? {
                    values.push(value);
                }
                Ok(values)
            }
        }
        
        deserializer.deserialize_seq(SeqVisitor {
            context: self.context,
        })
    }
}
 
fn main() {
    let json = "[1.0, 2.0, 3.0, 4.0, 5.0]";
    let seed = SeqSeed {
        context: Context { multiplier: 10.0 },
    };
    
    let values: Vec<ValueWithContext> = seed.deserialize(
        &mut serde_json::Deserializer::from_str(json)
    ).unwrap();
    
    for v in values {
        println!("{} * 10 = {}", v.value, v.result);
    }
}

Collections require the seed to be cloned or passed to each element during deserialization.

In-place Deserialization with Seed

use serde::de::{DeserializeSeed, Deserializer, Visitor, MapAccess, Error};
 
// Deserializing into existing structure with context
struct Config {
    defaults: Defaults,
    values: std::collections::HashMap<String, String>,
}
 
struct Defaults {
    host: String,
    port: u16,
}
 
struct ConfigSeed {
    defaults: Defaults,
}
 
impl<'de> DeserializeSeed<'de> for ConfigSeed {
    type Value = Config;
    
    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct ConfigVisitor {
            defaults: Defaults,
        }
        
        impl<'de> Visitor<'de> for ConfigVisitor {
            type Value = Config;
            
            fn expecting(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
                write!(fmt, "a config map")
            }
            
            fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
            where
                M: MapAccess<'de>,
            {
                let mut values = std::collections::HashMap::new();
                
                while let Some(key) = map.next_key::<String>()? {
                    let value = map.next_value::<String>()?;
                    values.insert(key, value);
                }
                
                Ok(Config {
                    defaults: self.defaults,
                    values,
                })
            }
        }
        
        deserializer.deserialize_map(ConfigVisitor {
            defaults: self.defaults,
        })
    }
}
 
fn main() {
    let json = r#"{"host": "localhost", "port": "8080", "mode": "debug"}"#;
    
    let seed = ConfigSeed {
        defaults: Defaults {
            host: "0.0.0.0".to_string(),
            port: 3000,
        },
    };
    
    let config: Config = seed.deserialize(
        &mut serde_json::Deserializer::from_str(json)
    ).unwrap();
    
    println!("Defaults: {}:{}", config.defaults.host, config.defaults.port);
    println!("Values: {:?}", config.values);
}

Context can provide defaults that complement the deserialized values.

Recursive Types with Seed

use serde::de::{DeserializeSeed, Deserializer, Visitor, MapAccess, SeqAccess, Error};
use std::collections::HashMap;
 
// Expression tree with variable resolution
#[derive(Debug)]
enum Expr {
    Var(String),
    Const(i64),
    Add(Box<Expr>, Box<Expr>),
    Mul(Box<Expr>, Box<Expr>),
}
 
struct ExprSeed {
    variables: HashMap<String, i64>,
}
 
impl Clone for ExprSeed {
    fn clone(&self) -> Self {
        ExprSeed {
            variables: self.variables.clone(),
        }
    }
}
 
impl<'de> DeserializeSeed<'de> for ExprSeed {
    type Value = Expr;
    
    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct ExprVisitor {
            variables: HashMap<String, i64>,
        }
        
        impl<'de> Visitor<'de> for ExprVisitor {
            type Value = Expr;
            
            fn expecting(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
                write!(fmt, "an expression")
            }
            
            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
            where
                E: Error,
            {
                // Variable reference or constant
                if v.starts_with('$') {
                    Ok(Expr::Var(v[1..].to_string()))
                } else {
                    v.parse::<i64>()
                        .map(Expr::Const)
                        .map_err(|_| E::custom("invalid number"))
                }
            }
            
            fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
            where
                M: MapAccess<'de>,
            {
                let mut op: Option<String> = None;
                let mut args: Vec<Expr> = Vec::new();
                
                while let Some(key) = map.next_key::<String>()? {
                    match key.as_str() {
                        "op" => op = Some(map.next_value()?),
                        "args" => {
                            let seed = ExprSeed {
                                variables: self.variables.clone(),
                            };
                            // Deserialize args as sequence with seed
                            // (simplified for example)
                            while let Some(arg) = map.next_value_seed(ExprSeed {
                                variables: self.variables.clone(),
                            })? {
                                args.push(arg);
                            }
                        }
                        _ => { map.next_value::<serde::de::Ignored>()?; }
                    }
                }
                
                let op = op.ok_or_else(|| M::Error::custom("missing op"))?;
                
                match op.as_str() {
                    "add" => {
                        let left = args.into_iter().next()
                            .ok_or_else(|| M::Error::custom("need 2 args"))?;
                        // Simplified - would need proper 2-arg handling
                        Ok(Expr::Const(0))
                    }
                    "mul" => {
                        Ok(Expr::Const(0))
                    }
                    _ => Err(M::Error::custom("unknown op")),
                }
            }
        }
        
        deserializer.deserialize_any(ExprVisitor {
            variables: self.variables,
        })
    }
}
 
fn main() {
    let mut vars = HashMap::new();
    vars.insert("x".to_string(), 10);
    vars.insert("y".to_string(), 20);
    
    let json = r#""$x""#; // Simple variable reference
    let seed = ExprSeed { variables: vars };
    let expr: Expr = seed.deserialize(
        &mut serde_json::Deserializer::from_str(json)
    ).unwrap();
    
    println!("Expr: {:?}", expr);
}

Complex recursive structures can propagate context through nested seeds.

Seed for Deserializing Trait Objects

use serde::de::{DeserializeSeed, Deserializer, Error};
use std::collections::HashMap;
 
// Trait object deserialization requires type registry
trait Animal {
    fn speak(&self) -> &str;
}
 
struct Dog { name: String }
impl Animal for Dog {
    fn speak(&self) -> &str { "woof" }
}
 
struct Cat { name: String }
impl Animal for Cat {
    fn speak(&self) -> &str { "meow" }
}
 
#[derive(serde::Deserialize)]
struct AnimalDef {
    #[serde(rename = "type")]
    animal_type: String,
    name: String,
}
 
type AnimalFactory = fn(String) -> Box<dyn Animal>;
 
struct AnimalSeed {
    registry: HashMap<String, AnimalFactory>,
}
 
impl<'de> DeserializeSeed<'de> for AnimalSeed {
    type Value = Box<dyn Animal>;
    
    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        let def = AnimalDef::deserialize(deserializer)?;
        
        let factory = self.registry.get(&def.animal_type)
            .ok_or_else(|| D::Error::custom(format!("Unknown animal: {}", def.animal_type)))?;
        
        Ok(factory(def.name))
    }
}
 
fn create_dog(name: String) -> Box<dyn Animal> {
    Box::new(Dog { name })
}
 
fn create_cat(name: String) -> Box<dyn Animal> {
    Box::new(Cat { name })
}
 
fn main() {
    let mut registry: HashMap<String, AnimalFactory> = HashMap::new();
    registry.insert("dog".to_string(), create_dog);
    registry.insert("cat".to_string(), create_cat);
    
    let json = r#"{"type": "dog", "name": "Buddy"}"#;
    
    let seed = AnimalSeed { registry };
    let animal: Box<dyn Animal> = seed.deserialize(
        &mut serde_json::Deserializer::from_str(json)
    ).unwrap();
    
    println!("Animal says: {}", animal.speak());
}

Trait objects require a registry mapping type identifiers to constructors.

Seed with Lifetime Context

use serde::de::{DeserializeSeed, Deserializer, Error};
 
// Deserializing data that references external resources
struct Resource {
    id: u32,
    name: String,
    data_ref: &'static str, // References external data
}
 
struct ResourceSeed {
    data_store: &'static HashMap<u32, &'static str>,
}
 
impl<'de> DeserializeSeed<'de> for ResourceSeed {
    type Value = Resource;
    
    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        #[derive(serde::Deserialize)]
        struct ResourceDef {
            id: u32,
            name: String,
            data_id: u32,
        }
        
        let def = ResourceDef::deserialize(deserializer)?;
        
        let data_ref = self.data_store.get(&def.data_id)
            .ok_or_else(|| D::Error::custom(format!("Unknown data id: {}", def.data_id)))?;
        
        Ok(Resource {
            id: def.id,
            name: def.name,
            data_ref: *data_ref,
        })
    }
}
 
fn main() {
    let data: HashMap<u32, &'static str> = [
        (1, "static data 1"),
        (2, "static data 2"),
    ].into_iter().map(|(k, v)| (k, Box::leak(v.into_boxed_str()))).collect();
    
    // Leak for static lifetime
    let static_data: &'static HashMap<u32, &'static str> = Box::leak(Box::new(data));
    
    let json = r#"{"id": 1, "name": "Resource A", "data_id": 1}"#;
    
    let seed = ResourceSeed { data_store: static_data };
    let resource: Resource = seed.deserialize(
        &mut serde_json::Deserializer::from_str(json)
    ).unwrap();
    
    println!("Resource: {} - {}", resource.name, resource.data_ref);
}

Seeds can provide references to external data structures with appropriate lifetimes.

Comparing Deserialize and DeserializeSeed

use serde::{Deserialize, de::{DeserializeSeed, Deserializer}};
 
// Standard Deserialize: no external context
#[derive(Deserialize, Debug)]
struct Point {
    x: f64,
    y: f64,
}
 
// DeserializeSeed: with external context
struct PointWithScale {
    point: Point,
    scale: f64,
}
 
struct PointSeed {
    scale: f64,
}
 
impl<'de> DeserializeSeed<'de> for PointSeed {
    type Value = PointWithScale;
    
    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        let point: Point = Point::deserialize(deserializer)?;
        Ok(PointWithScale {
            point,
            scale: self.scale,
        })
    }
}
 
impl std::fmt::Display for PointWithScale {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "Point({}, {}) scaled by {}", self.point.x, self.point.y, self.scale)
    }
}
 
fn main() {
    // Standard Deserialize
    let json = r#"{"x": 10.0, "y": 20.0}"#;
    let point: Point = serde_json::from_str(json).unwrap();
    println!("Standard deserialize: {:?}", point);
    
    // With DeserializeSeed
    let seed = PointSeed { scale: 2.0 };
    let scaled: PointWithScale = seed.deserialize(
        &mut serde_json::Deserializer::from_str(json)
    ).unwrap();
    println!("With seed: {}", scaled);
}

Deserialize creates values from serialized data alone; DeserializeSeed adds context.

SeqAccess with Seed

use serde::de::{DeserializeSeed, Deserializer, Visitor, SeqAccess, Error};
 
// Deserialize each element with context
struct Item {
    id: u32,
    name: String,
    computed: String, // Derived from context + data
}
 
struct ItemSeed {
    prefix: String,
}
 
impl<'de> DeserializeSeed<'de> for ItemSeed {
    type Value = Item;
    
    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        #[derive(serde::Deserialize)]
        struct ItemDef {
            id: u32,
            name: String,
        }
        
        let def = ItemDef::deserialize(deserializer)?;
        Ok(Item {
            id: def.id,
            name: def.name.clone(),
            computed: format!("{}-{}", self.prefix, def.name),
        })
    }
}
 
struct ItemsSeed {
    prefix: String,
}
 
impl<'de> DeserializeSeed<'de> for ItemsSeed {
    type Value = Vec<Item>;
    
    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct ItemsVisitor {
            prefix: String,
        }
        
        impl<'de> Visitor<'de> for ItemsVisitor {
            type Value = Vec<Item>;
            
            fn expecting(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
                write!(fmt, "a sequence of items")
            }
            
            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
            where
                A: SeqAccess<'de>,
            {
                let mut items = Vec::new();
                let prefix = self.prefix;
                
                while let Some(item) = seq.next_element_seed(ItemSeed {
                    prefix: prefix.clone(),
                })? {
                    items.push(item);
                }
                
                Ok(items)
            }
        }
        
        deserializer.deserialize_seq(ItemsVisitor {
            prefix: self.prefix,
        })
    }
}
 
fn main() {
    let json = r#"[{"id": 1, "name": "apple"}, {"id": 2, "name": "banana"}]"#;
    
    let seed = ItemsSeed {
        prefix: "fruit".to_string(),
    };
    
    let items: Vec<Item> = seed.deserialize(
        &mut serde_json::Deserializer::from_str(json)
    ).unwrap();
    
    for item in items {
        println!("{}: {} -> {}", item.id, item.name, item.computed);
    }
}

SeqAccess::next_element_seed deserializes each element with its own seed.

MapAccess with Seed

use serde::de::{DeserializeSeed, Deserializer, Visitor, MapAccess, Error};
 
struct KeyValueWithContext {
    key: String,
    value: String,
    namespace: String,
}
 
struct MapSeed {
    namespace: String,
}
 
impl<'de> DeserializeSeed<'de> for MapSeed {
    type Value = Vec<KeyValueWithContext>;
    
    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct MapVisitor {
            namespace: String,
        }
        
        impl<'de> Visitor<'de> for MapVisitor {
            type Value = Vec<KeyValueWithContext>;
            
            fn expecting(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
                write!(fmt, "a map")
            }
            
            fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
            where
                A: MapAccess<'de>,
            {
                let mut entries = Vec::new();
                
                while let Some(key) = map.next_key::<String>()? {
                    let value = map.next_value::<String>()?;
                    entries.push(KeyValueWithContext {
                        key,
                        value,
                        namespace: self.namespace.clone(),
                    });
                }
                
                Ok(entries)
            }
        }
        
        deserializer.deserialize_map(MapVisitor {
            namespace: self.namespace,
        })
    }
}
 
fn main() {
    let json = r#"{"key1": "value1", "key2": "value2"}"#;
    
    let seed = MapSeed {
        namespace: "config".to_string(),
    };
    
    let entries: Vec<KeyValueWithContext> = seed.deserialize(
        &mut serde_json::Deserializer::from_str(json)
    ).unwrap();
    
    for entry in entries {
        println!("[{}] {} = {}", entry.namespace, entry.key, entry.value);
    }
}

Map keys and values can be deserialized with context using MapAccess.

Practical Use: Dependency Injection

use serde::de::{DeserializeSeed, Deserializer, Error};
use std::collections::HashMap;
 
// Services registry for dependency injection
trait Service {
    fn name(&self) -> &str;
}
 
struct Database { name: String }
impl Service for Database {
    fn name(&self) -> &str { &self.name }
}
 
struct Cache { name: String }
impl Service for Database {
    fn name(&self) -> &str { &self.name }
}
 
impl Service for Cache {
    fn name(&self) -> &str { &self.name }
}
 
#[derive(serde::Deserialize)]
struct ServiceRef {
    service_type: String,
    service_name: String,
}
 
struct ServiceSeed {
    services: HashMap<String, Box<dyn Service>>,
}
 
impl<'de> DeserializeSeed<'de> for ServiceSeed {
    type Value = Box<dyn Service>;
    
    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        let ref_def = ServiceRef::deserialize(deserializer)?;
        
        // In a real implementation, you'd look up or construct the service
        // based on the type and name
        
        Err(D::Error::custom("Service lookup not implemented in example"))
    }
}
 
fn main() {
    // Example demonstrates the pattern - actual implementation would
    // need proper service construction logic
    
    let mut services: HashMap<String, Box<dyn Service>> = HashMap::new();
    services.insert("db_main".to_string(), Box::new(Database {
        name: "main_db".to_string(),
    }));
    services.insert("cache_local".to_string(), Box::new(Cache {
        name: "local_cache".to_string(),
    }));
    
    // JSON would reference services by name
    // {"service_type": "database", "service_name": "main"}
}

DeserializeSeed enables service locator patterns during deserialization.

Synthesis

DeserializeSeed vs Deserialize:

Aspect Deserialize DeserializeSeed
Context None Seed value
Use case Self-contained data Context-dependent data
Trait method deserialize<D> deserialize_seed<D, S>
Value type Self Self::Value

Key use cases:

Use Case What Seed Provides
Registry lookup Type → constructor mapping
Defaults Default values for missing fields
References External data structures
Context Runtime configuration
Validation External validators

Seed lifecycle:

Create seed with context
   ↓
Call seed.deserialize(deserializer)
   ↓
Seed uses context during deserialization
   ↓
Returns constructed value

Collection deserialization:

Method Purpose
next_element_seed Deserialize element with seed
next_value_seed Deserialize map value with seed
next_key_seed Deserialize map key with seed

Key insight: serde::de::DeserializeSeed bridges the gap between serialized data and runtime context, enabling deserialization that requires information not present in the serialized format. This is essential for implementing type registries (deserializing trait objects), resolving references (IDs to external objects), providing defaults (configuration inheritance), and implementing dependency injection during deserialization. The seed pattern requires implementing DeserializeSeed with an associated Value type, then using SeqAccess::next_element_seed and MapAccess::next_value_seed to propagate the seed through nested structures. Unlike standard Deserialize which creates values purely from serialized bytes, DeserializeSeed produces values that incorporate external context, making it the foundation for advanced deserialization patterns in complex systems.