Search code examples
jsonrustreturn-typegeneric-type-parameters

Returns an unknown type in Rust


From a deserialized JSON file into structures,

{
   "infos": {
       "info_example": {
           "title": {
               "en": "Title for example",
               "fr": "Titre pour l'exemple"
           },
           "message": {
               "en": "Message for example"
           }
       }    
   },
   "errors": {}
}
#[derive(Debug, Deserialize)]
struct Logs {
    infos: Infos,
    errors: Errors,
}

#[derive(Debug, Deserialize)]
struct Infos {
    info_example: Log,
}

#[derive(Debug, Deserialize)]
struct Errors {}

#[derive(Debug, Deserialize)]
struct Log {
    title: MultiString,
    message: MultiString,
}

#[derive(Debug, Deserialize)]
struct MultiString {
   en: String,
   fr: Option<String>,
   de: Option<String>
}

I would like to create a function working like this :

logs_manager.get("infos.info_example.message.en")
struct LogsManager {
    logs: Logs
}

impl LogsManager {
    fn get(&self, element: &str) -> T {
        let splitted: Vec<&str> = element.split(".").collect();

        // Later it will be a loop, but for now I'm just gonna take the first part
        match splitted[0] {
            "infos" => {
                &self.logs.infos
            },
            "errors" => {
                &self.logs.errors
            }
            _ => panic!()
        }
    }
}

When I try to compile, I'm getting these errors :

   Compiling so_question_return_type v0.1.0 (/run/media/anton/data120/Documents/testa)
error[E0308]: mismatched types
  --> src/main.rs:26:17
   |
20 |     fn get<T>(&self, element: &str) -> &T {
   |            - this type parameter       -- expected `&T` because of return type
...
26 |                 &self.logs.infos
   |                 ^^^^^^^^^^^^^^^^ expected type parameter `T`, found struct `Infos`
   |
   = note: expected reference `&T`
              found reference `&Infos`

error[E0308]: mismatched types
  --> src/main.rs:29:17
   |
20 |     fn get<T>(&self, element: &str) -> &T {
   |            - this type parameter       -- expected `&T` because of return type
...
29 |                 &self.logs.errors
   |                 ^^^^^^^^^^^^^^^^^ expected type parameter `T`, found struct `Errors`
   |
   = note: expected reference `&T`
              found reference `&Errors`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `so_question_return_type` due to 2 previous errors

try compile by yourself thanks to this file : https://gist.github.com/antoninhrlt/feee9ec4da1cb0edd0e7f426a6c744b0

So, I've tried to create an enum variant to avoid the type return problem.

enum LogObject<'a> {
    Logs(Logs),
    Infos(Infos),
    Errors(Errors),
    Log(Log),
    MultiString(MultString)
}

Then I wrap the object I want to return into a LogObject. See :

           "infos" => {
                StringsObject::Logs(&self.logs.infos)
            }

It works. But I would like to easily retrieve the value inside the enum object.

impl<'a> LogsObject<'a> {
    fn retrieve_object<T>(&self) -> &T {
        match *self {
            Self::Logs(object) => object,
            Self::Infos(object) => object,
            Self::Errors(object) => object,
            Self::Log(object) => object,
            Self::MultiString(object) => object,
        }
    }
}

But this gives me another error :

error[E0308]: mismatched types
  --> crates/strings/src/manager.rs:63:44
   |
61 |     fn retrieve_object<T>(&self) -> &T {
   |                        -            -- expected `&T` because of return type
   |                        |
   |                        this type parameter
62 |         match *self {
63 |             Self::Logs(object) => object,
   |                                   ^^^^^^ expected type parameter `T`, found struct `structured::Logs`
   |
   = note: expected reference `&T`
              found reference `&structured::Logs`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `strings` due to previous error

I'm lost, I don't know how to implement that. So after searching for a while, I'm asking to you. Does anyone know how to do this ?

PS : I'm using serde for deserialization.


Solution

  • Making a get function was a bad idea.

    Now, I'm simply doing something like that :

    logs_manager.logs.info_example.message.en
    

    Other thing, I'm including the json file into the binary thanks to include_str!

    Thank you the reply, but I think it's better to abandon my first idea