Json file serialization and deserialization - json

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();

Related

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.
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

Skip empty or faulty rows with Serde

I have a file with valid rows that I'm parsing to a struct using Serde and the csv crate.
#[derive(Debug, Deserialize)]
struct Circle {
x: f32,
y: f32,
radius: f32,
}
fn read_csv(path: &str) -> Result<Vec<Circle>, csv::Error> {
let mut rdr = csv::ReaderBuilder::new().delimiter(b';').from_path(path)?;
let res: Vec<Circle> = rdr
.deserialize()
.map(|record: Result<Circle, csv::Error>| {
record.unwrap_or_else(|err| panic!("There was a problem parsing a row: {}", err))
})
.collect();
Ok(res)
}
This code work for the most times, but sometimes when I get files they contain "empty" rows at the end:
x;y;radius
6398921.770;146523.553;0.13258
6398921.294;146522.452;0.13258
6398914.106;146526.867;0.13258
;;;
This makes the parsing fail with
thread 'main' panicked at 'There was a problem parsing a row: CSV
deserialize error: record 4 (line: 4, byte: 194): field 0: cannot
parse float from empty string', src/main.rs:90:41 note: run with
RUST_BACKTRACE=1 environment variable to display a backtrace
How can I handle faulty rows without manipulating the file contents beforehand?
Thanks!

Seeding rails project with Json file

I'm at a lost and my searches have gotten me nowhere.
In my seeds.rb file I have the following code
require 'json'
jsonfile = File.open 'db/search_result2.json'
jsondata = JSON.load jsonfile
#jsondata = JSON.parse(jsonfile)
jsondata[].each do |data|
Jobpost.create!(post: data['title'],
link: data['link'],
image: data['pagemap']['cse_image']['src'] )
end
Snippet of the json file looks like this:
{
"kind": "customsearch#result",
"title": "Careers Open Positions - Databricks",
"link": "https://databricks.com/company/careers/open-positions",
"pagemap": {
"cse_image": [
{
"src": "https://databricks.com/wp-content/uploads/2020/08/careeers-new-og-image-sept20.jpg"
}
]
}
},
Fixed jsondata[].each to jasondata.each. Now I'm getting the following error:
TypeError: no implicit conversion of String into Integer
jsondata[] says to call the [] method with no arguments on the object in the jsondata variable. Normally [] would take an index like jsondata[0] to get the first element or a start and length like jsondata[0, 5] to get the first five elements.
You want to call the each method on jsondata, so jsondata.each.
So this is very specific to what you have posted:
require 'json'
file = File.open('path_to_file.json').read
json_data = JSON.parse file
p json_data['kind'] #=> "customsearch#result"
# etc for all the other keys
now maybe the json you posted is just the first element in an array:
[
{}, // where each {} is the json you posted
{},
{},
// etc
]
in which case you will indeed have to iterate:
require 'json'
file = File.open('path_to_file.json').read
json_data = JSON.parse file
json_data.each do |data|
p data['kind'] #=> "customsearch#result"
end

Unable to deserialize chrono::DateTime from json

I encounter an interesting issue. For some reason serde is unable to deserialize a chrono::DateTime<Utc> object from a string in the same format it was serialized (but it does if I save a variable with it):
use chrono; // 0.4.11
use serde_json; // 1.0.48
fn main() {
let date = chrono::Utc::now();
println!("{}", date);
let date_str = serde_json::to_string(&date).unwrap();
println!("{}", date_str);
let parsed_date: chrono::DateTime<chrono::Utc> = serde_json::from_str(&date_str).unwrap();
println!("{}", parsed_date);
assert_eq!(date, parsed_date);
let date = "2020-03-28T16:29:04.644008111Z";
let _: chrono::DateTime<chrono::Utc> = serde_json::from_str(&date).unwrap();
}
Here is the playground link
Which outputs:
Compiling playground v0.0.1 (/playground)
Finished dev [unoptimized + debuginfo] target(s) in 1.01s
Running `target/debug/playground`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error("invalid type: integer `2020`, expected a formatted date and time string or a unix timestamp", line: 1, column: 4)', src/main.rs:17:44
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Standard Output
2020-03-28 17:57:04.222452521 UTC
"2020-03-28T17:57:04.222452521Z"
2020-03-28 17:57:04.222452521 UTC
Why is this happening? How should I be doing it?
You need to put valid json, don't forget double quote:
let date = "\"2020-03-28T16:29:04.644008111Z\"";
You can see it with println!("{:?}", date_str);

F# JsonValue example doesn't work

In F# Data: JSON Parser
There is an example showing how to extract data:
let info =
JsonValue.Parse("""
{ "name": "Tomas", "born": 1985,
"siblings": [ "Jan", "Alexander" ] } """)
open FSharp.Data.JsonExtensions
// Print name and birth year
let n = info?name
printfn "%s (%d)" (info?name.AsString()) (info?born.AsInteger())
// Print names of all siblings
for sib in info?siblings do
printfn "%s" (sib.AsString())
I copied and pasted this code to try it out, but it won't compile, I get the error:
Error 53 The field, constructor or member 'AsString' is not defined
Is there something missing in the example code?
This can't work with VS 2012 because it lacks the ability to handle extensions for F#