Returns an unknown type in Rust - json

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.

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

Related

Json file serialization and deserialization

I have a json file:
[
{
"name": "John",
"sirname": "Fogerty",
"age": 77
},
{
"name": "Dave",
"sirname": "Mustaine",
"age": 61
}
]
I want to read the objects of the User structure from it into an array, then add another element to this array and re-write everything to the same file.
My code:
use serde_derive::{Serialize, Deserialize};
use serde_json::json;
use std::fs::File;
#[derive(Serialize, Deserialize, Debug)]
struct User {
name: String,
sirname: String,
age: u8,
}
fn main() {
let f = File::open("info.json").unwrap();
let mut q: Vec<User> = serde_json::from_reader(&f).unwrap();
q.push(User{name: "Daniil".to_string(),
sirname: "Volkov".to_string(),
age: 19,
});
serde_json::to_writer(f, &q).unwrap();
println!("{:?}", q);
}
I get an error when starting:
thread 'main' panicked at 'called Result::unwrap() on an Err value: Error("Access denied. (os error 5)", line: 0, column: 0)', src\main.rs:22:34
note: run with RUST_BACKTRACE=1 environment variable to display a backtrace
error: process didn't exit successfully: target\debug\json.exe (exit code: 101).
What do I need to do?
As noted by #Caesar in comments, you should change the way you open your file. Thus instead of
let f = File::open("info.json").unwrap();
you should put the following:
let mut f = File::options()
.read(true)
.write(true)
.open("info.json")
.unwrap();
But as you read your file your position in that file moves, so before writing to the file (since you are willing to rewrite it, not append) you need to reset the position:
let _ = f.seek(std::io::SeekFrom::Start(0)).unwrap();
right before the following line:
serde_json::to_writer(f, &q).unwrap();

Compile errors when using json::object! tutorial example: expected identifier, found keyword

This example code is copied directly from the json crate commented code:
#[macro_use]
extern crate json;
fn main() {
let mut data = object!{
foo: false,
bar: null,
answer: 42,
list: [null, "world", true]
};
println!("{:?}", data);
}
The toml includes the dependencies:
[dependencies]
json="*"
Result:
error: expected identifier, found keyword `false`
--> src/main.rs:8:14
|
8 | foo: false,
| ^^^^^ expected identifier, found keyword
|
help: you can escape reserved keywords to use them as identifiers
|
8 | foo: r#false,
| ~~~~~~~
error: expected type, found keyword `false`
--> src/main.rs:8:14
|
8 | foo: false,
| - ^^^^^ expected type
| |
| tried to parse a type due to this
|
::: /Users/mackie/.cargo/registry/src/github.com-1ecc6299db9ec823/json-0.11.15/src/lib.rs:317:10
|
317 | { $( $key:expr => $value:expr ),* } => {
| --------- while parsing argument for this `expr` macro fragment
Lesson learned; Never go by what the crate owner is recommending when they say you can use "*" for the version of the crate.
json-rust on crates.io

how to convert from JSON to a parametric nested struct in julia?

stringtest="""{ "struct_A": {
"arg1": {
"arg_B": 90
},
"arg2": 100
}
}"""
jsonDict=JSON.parse(stringtest)
struct struct_B<: myStruct
arg
end
struct struct_A{T<:myStruct}
arg1::T
arg2
function BatteryStorage{T}(arg1,arg2) where {T}
return new{T}(arg1,arg2)
end
end
to_struct=ToStruct.tostruct(struct_A,jsonDict)
why I'm always getting :
LoadError: MethodError: no method matching struct_A(::Dict{String, Any})
caused by: MethodError: Cannot convert an object of type
Dict{String, Any} to an object of type
struct_A
Closest candidates are:
convert(::Type{T}, ::T) where T at essentials.jl:205

How to use multiparameter String functions in Rust?

I want to make a to_string() fn in Rust with &self as parameter, and calling the references of the elements of &self inside the function:
//! # Messages
//!
//! Module that builds and returns messages with user and time stamps.
use time::{Tm};
/// Represents a simple text message.
pub struct SimpleMessage<'a, 'b> {
pub moment: Tm,
pub content: &'b str,
}
impl<'a, 'b> SimpleMessage<'a, 'b> {
/// Gets the elements of a Message and transforms them into a String.
pub fn to_str(&self) -> String {
let mut message_string =
String::from("{}/{}/{}-{}:{} => {}",
&self.moment.tm_mday,
&self.moment.tm_mon,
&self.moment.tm_year,
&self.moment.tm_min,
&self.moment.tm_hour,
&self.content);
return message_string;
}
}
But $ cargo run returns:
error[E0061]: this function takes 1 parameter but 8 parameters were supplied
--> src/messages.rs:70:13
|
70 | / String::from("{}/{}/{}-{}:{}, {}: {}",
71 | | s.moment.tm_mday,
72 | | s.moment.tm_mon,
73 | | s.moment.tm_year,
... |
76 | | s.user.get_nick(),
77 | | s.content);
| |___________________________________^ expected 1 parameter
I really don't understand the problem of this syntax, what am I missing?
You probably meant to use the format! macro:
impl<'b> SimpleMessage<'b> {
/// Gets the elements of a Message and transforms them into a String.
pub fn to_str(&self) -> String {
let message_string =
format!("{}/{}/{}-{}:{} => {}",
&self.moment.tm_mday,
&self.moment.tm_mon,
&self.moment.tm_year,
&self.moment.tm_min,
&self.moment.tm_hour,
&self.content);
return message_string;
}
}
String::from comes from the From trait, which defines a from method that takes a single parameter (hence "this function takes 1 parameter" in the error message).
format! already produces a String, so no conversion is necessary.

F# JSON Type Provider, do not serialize null values

Background
I am using the FSharp.Data JSON Type Provider with a sample that has an array of objects that may have different properties. Here is an illustrative example:
[<Literal>]
let sample = """
{ "input": [
{ "name": "Mickey" },
{ "year": 1928 }
]
}
"""
type InputTypes = JsonProvider< sample >
The JSON Type Provider creates an Input type which has both an Optional Name and an Optional Year property. That works well.
Problem
When I try to pass an instance of this to the web service, I do something like this:
InputTypes.Root(
[|
InputTypes.Input(Some("Mouse"), None)
InputTypes.Input(None, Some(2028))
|]
)
The web service is receiving the following and choking on the nulls.
{
"input": [
{
"name": "Mouse",
"year": null
},
{
"name": null,
"year": 2028
}
]
}
What I Tried
I find that this works:
InputTypes.Root(
[|
InputTypes.Input(JsonValue.Parse("""{ "name": "Mouse" }"""))
InputTypes.Input(JsonValue.Parse("""{ "year": 2028 }"""))
|]
)
It sends this:
{
"input": [
{
"name": "Mouse"
},
{
"year": 2028
}
]
}
However, on my real project, the structures are larger and would require a lot more conditional JSON string building. It kind of defeats the purpose.
Questions
Is there a way to cause the JSON Type Provider to not serialize null properties?
Is there a way to cause the JSON Type Provider to not serialize empty arrays?
As a point of comparison, the Newtonsoft.JSON library has a NullValueHandling attribute.
I don't think there is an easy way to get the JSON formatting in F# Data to drop the null fields - I think the type does not clearly distinguish between what is null and what is missing.
You can fix that by writing a helper function to drop all null fields:
let rec dropNullFields = function
| JsonValue.Record flds ->
flds
|> Array.choose (fun (k, v) ->
if v = JsonValue.Null then None else
Some(k, dropNullFields v) )
|> JsonValue.Record
| JsonValue.Array arr ->
arr |> Array.map dropNullFields |> JsonValue.Array
| json -> json
Now you can do the following and get the desired result:
let json =
InputTypes.Root(
[|
InputTypes.Input(Some("Mouse"), None)
InputTypes.Input(None, Some(2028))
|]
)
json.JsonValue |> dropNullFields |> sprintf "%O"