Need help with lifetime and borrow checkers for serde-reflection code

Hi, I'm learning rust, and I got stuck with the borrow checker. I start to get a hang on the simpler coding, but in this case when I try to use serde-reflection to create a JSON output explaining "registered" structs I get into problems with the lifetime of the template method T type. It's puzzling as the type really should not need to have any lifetime as I'm not going to pass the instance.

Anyone that happens to know a bit more about the serde-reflection Tracer and how to manage the 'de lifetime in the trace_type method signature?

extern crate serde_json;
use serde_json::json;
use serde_reflection::{Samples, Tracer, TracerConfig};

pub struct TypeRegistry {
    registry: Vec<types::Type>,
    samples: Samples
}

impl TypeRegistry {
    pub fn new() -> TypeRegistry {
        TypeRegistry {
            registry: vec![],
            samples: Samples::new()
        }
    }

    pub fn add<'de, T: serde::Deserialize<'de>>(&mut self) {
        let mut tracer = Tracer::new(TracerConfig::default());
        tracer.trace_type::<T>(&self.samples);
        let registry = tracer.registry().unwrap();

        // TODO: add code to serialize into types::Type structure for Array/Object/Enum
    }

    pub fn to_json_string(&mut self) -> String {
        serde_json::to_string(&self.registry).unwrap()
    }
}

mod types {
    use serde::{Serialize, Deserialize};

    #[derive(Serialize, Deserialize, Debug)]
    pub enum Type {
        Array(Array),
        Object(Object),
        Enum(Enum)
    }

    // Rest of the structs goes here
}

This is the errors I'm getting:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/type_registry.rs:20:32
   |
20 |         tracer.trace_type::<T>(&self.samples);
   |                                ^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 18:5...
  --> src/type_registry.rs:18:5
   |
18 |     pub fn add<'de, T: serde::Deserialize<'de>>(&mut self) {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/type_registry.rs:20:32
   |
20 |         tracer.trace_type::<T>(&self.samples);
   |                                ^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'de` as defined on the method body at 18:16...
  --> src/type_registry.rs:18:16
   |
18 |     pub fn add<'de, T: serde::Deserialize<'de>>(&mut self) {
   |                ^^^
note: ...so that the types are compatible
  --> src/type_registry.rs:20:16
   |
20 |         tracer.trace_type::<T>(&self.samples);
   |                ^^^^^^^^^^
   = note: expected `serde::Deserialize<'_>`
              found `serde::Deserialize<'de>`

error: aborting due to previous error; 3 warnings emitted

When I was using the same trace_type method outside of the struct implementation and with a direct type (without the T template) it works just fine, but I can't seem to find a way to pass the type to the method.

Is there some other better approach to implement a "registry" for some selected struct types so that I can generate a JSON structure describing the types? I was going to use it with JavaScript in a browser to de-serialize binary representations of the structs and I wanted to go even smaller than MessagePack and so on by passing the schemas separately, I also did not want to go into separate languages like Protocol Buffers. My representation is going to look similar to this:

[
  {
    "alias": "Entities",
    "kind": "Array",
    "of": "Entity"
  },
  {
    "alias": "Entity",
    "kind": "Object",
    "properties": [
      {
        "name": "position",
        "alias": "Vector3"
      },
      {
        "name": "rotation",
        "alias": "Vector3"
      },
      {
        "name": "scale",
        "alias": "Vector3"
      }
    ]
  }
]

So, self.samples is required to have a lifetime that outlives the deserializer. You can tell it to do that.

pub fn add<'de, 'self: 'de, T: serde::Deserialize<'de>>(&'self mut self) {

Thanks for the help! Lifetimes takes some time to get used to. :slight_smile: