toml crate how to structure dependencies-like struct - serialization

I have a toml file in form of:
[general]
loaded=true
can_reload=true
[dependencies]
The dependencies section works essentially the same way as Cargo.toml dependencies, each dependency is listed on a separate line.
The problem is, that when using the toml crate to serialize/deserialize it, I'm not sure how to specify a section that can have any number of entries with any name below it.
My structure currently looks like:
#[derive(Debug, Serialize, Deserialize)]
pub struct Configuration {
general: ConfigurationGeneral,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ConfigurationGeneral {
loaded: bool,
can_reload: bool,
}
I saw on the documentation that you can use Option but that's still just for a single value. There's no way I can know the names of the dependencies and how many there will be to add them to a struct.

Represent dependencies with a HashMap:
use std::collections::HashMap;
use serde::{Serialize, Deserialize}; // 1.0.126
use toml; // 0.5.8
#[derive(Debug, Serialize, Deserialize)]
pub struct Configuration {
general: ConfigurationGeneral,
dependencies: HashMap<String, String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ConfigurationGeneral {
loaded: bool,
can_reload: bool,
}
fn main() {
let config: Configuration = toml::from_str(r#"
[general]
loaded = true
can_reload = true
[dependencies]
toml = "1.4"
"#).unwrap();
println!("{:#?}", config);
}
See it on the playground.
Here I'm just parsing the dependencies with the values as Strings but they can of course be more complex structures as well.

Related

How to implement From trait for custom error types?

I am currently trying to write a custom error type for my CLI application. Now I want to write an implementation of the From trait so my custom error type can wrap all third party library errors that can occur.
The error enum:
#[derive(Debug)] // Allow the use of "{:?}" format specifier
pub enum CustomError {
Git(git2::Error),
Other
}
Now I want to implement the From Trait for the git2::Error from the git2 library to use the ? operator in my functions.
impl From<(git2::Error)> for CustomError {
fn from(cause: git2::Error) -> Self {
CustomError::Git(cause)
}
}
But when I try to use my custom error to map an error like this:
let repo = Repository::open(path).map_err(|err| CustomError::Git)?;
I am getting the following error message:
the trait `std::convert::From<fn(git2::error::Error) -> error::CustomError {error::CustomError::Git}>` is not implemented for `error::CustomError `
Can anyone help me to understand why I am getting this error and how to solve this problem ?
Any help is appreciated
You've mixed up a whole bunch of concepts; let's see if we can walk through this together and hopefully clarify all of it.
The git2 crate has its own error type, that you no doubt have discovered. Your definition of custom errors is fine as well.
The issue is twofold:
Your implementation of From<_>
From<E> allows you to transform a type from one type to another by providing the translation function (from()).
Your implementation of this was the following:
impl From<(git2::Error)> for CustomError {
fn from(cause: git2::Error) -> Self {
CustomError::Git(cause)
}
}
Brackets in rust aren't added where they should not be, and this is precisely one of the cases where this is the case. By doing this, you've actually defined From<(T)>, not From<T>. That's mistake #1.
The correct implementation simply drops the brackets:
impl From<git2::Error> for CustomError {
fn from(cause) -> Self {
CustomError::Git(cause)
}
}
Your actual conversion
Not an error per se, but a completely unnecessary operation as the ? operator handles it for you. There is no need for the map_err(), and if there was you'd be using into() rather than hard-calling the type (which should already be defined as a type in your function).
Remember, the whole point of conversion traits is to define them so you don't have to explicitly call them.
A final "demo" version of the code in working order could look like this:
extern crate git2;
use git2::Repository;
#[derive(Debug)] // Allow the use of "{:?}" format specifier
pub enum CustomError {
Git(git2::Error),
Other
}
impl From<(git2::Error)> for CustomError {
fn from(cause: git2::Error) -> Self {
CustomError::Git(cause)
}
}
fn test() -> Result<(), CustomError> {
let path = "foo";
let output = Repository::open(path)?;
Ok(())
}
fn main() {
println!("Hello, world!");
}

error[E0277]: the trait bound `my_struct::MyStruct: my_trait::MyTrait` is not satisfied

I am writing projects in Rust to help me learn it, but am having trouble implementing a trait and then using a function required by that trait when a type implementing it is passed to a function.
To try and narrow down the problem, I've created an MVCE. Here is the error message and code:
error message
error[E0277]: the trait bound `my_struct::MyStruct: my_trait::MyTrait` is not satisfied
--> src\main.rs:12:5
|
12 | invoke_print_i32(&MyStruct { });
| ^^^^^^^^^^^^^^^^ the trait `my_trait::MyTrait` is not implemented for `my_struct::MyStruct`
|
note: required by `invoke_print_i32`
--> src\main.rs:7:1
|
7 | fn invoke_print_i32<T: MyTrait>(instance: &T) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
my_trait.rs
pub trait MyTrait {
fn print_i32(&self, n: i32);
}
my_struct.rs
#[path = "my_trait.rs"]
mod my_trait;
use my_trait::MyTrait;
pub struct MyStruct { }
impl MyTrait for MyStruct {
fn print_i32(&self, n: i32) {
println!("n: {}", n);
}
}
main.rs
mod my_trait;
use my_trait::MyTrait;
mod my_struct;
use my_struct::MyStruct;
fn invoke_print_i32<T: MyTrait>(instance: &T) {
instance.print_i32(42);
}
fn main() {
invoke_print_i32(&MyStruct { });
}
My attempts at researching the problem mostly found people trying to implement fairly standard Rust traits, for example:
How can I implement Rust's Copy trait?
The trait bound is not satisfied in Rust
The trait bound is not satisfied
I also read somewhere that I needed to reimplement the trait for variables such as &MyStruct, but my attempts to do so didn't resolve the issue.
extra info
rustc -V outputs rustc 1.36.0 (a53f9df32 2019-07-03)
cargo -V outputs cargo 1.36.0 (c4fcfb725 2019-05-15)
Platform/OS is Windows 10 Pro (x86_64)
question
What am I doing wrong; how can I correctly implement the trait?
You have declared the module my_trait twice, so there are actually two different traits called MyTrait: crate::my_trait and crate::my_struct::my_trait.
You don't need to declare the module in the my_struct module. Instead, use the module that is declared in the crate root, with:
use crate::my_trait::MyTrait;
Or
use super::my_trait::MyTrait;

Including a file from another that is not main.rs nor lib.rs

(I'm a Rust beginner) I have three files : main.rs, board.rs and case.rs.
I want to include case.rs into board.rs, and board.rs into main.rs, so the board uses the case, and we can access the board in main.
I've successfully added the board into main, but the way I did doesn't seem to work for the second part.
I've tried to encapsulate every file's content into "mod {}" but it doesn't change the problem.
Also I tried every combinations of "mod" and "use".
Every file is in the folder src/, and I'd like them not to move from there if possible.
main.rs
mod board;
fn main() {
let mut b: Board = Board::new();
}
board.rs
mod case;
pub struct Board {
board: [ Case; 9 ]
}
// There is also the impl part of course, let's keep it short
case.rs
pub enum Case { Empty, Full(Player) }
Using VSCode with the Rust plugin, the "case" word on the first line of the board.rs file is underlined red, and it says :
"src/case.rs
file not found for module case
help: name the file either board\case.rs or board\case\mod.rs inside the directory "src""
Why doesn't it search in the current directory?
Your files could look like as follows:
case.rs:
#[derive(Clone, Copy, Debug)]
struct Player;
#[derive(Clone, Copy, Debug)]
pub enum Case {
Empty,
Full(Player)
}
board.rs:
use crate::case::Case;
#[derive(Debug)]
pub struct Board {
board: [ Case; 9 ]
}
impl Board {
pub fn new() -> Self {
Self { board: [Case::Empty; 9] }
}
}
main.rs:
mod case;
mod board;
use crate::board::Board;
fn main() {
println!("{:?}", Board::new());
}
Basically you create a crate (a binary one, because of your main.rs) and that crate can have modules. A module can be a file, or it can be a folder as well (if it happens to have a mod.rs). (And for the sake of completeness, it could also be an inline module without direct relation to the file system.)
Your mod statements (the ones which are indicating files and folders, not the ones which you use to create inline modules) should either be placed at the top level of your crate (e.g. in your main.rs or lib.rs) or at the module levels (in your mod.rs files) depending on the desired structure.
For further info on this, please read the The Rust Programming Language book's relevant chapter: Packages and Crates.

Rust Can't import Singleton From global space into another module in another file

Using the lazy_static library to create a singleton. I am unable to access that singleton in a module in another file. If the module is defined below the main function I can access it fine.
Given a main file such as the following, test_stuff can access gamedata fine:
extern crate gamedata;
#[macro_use]
extern crate lazy_static;
lazy_static! {
pub static ref GAMEDATA: &'static str = "I am a test STrings";
}
fn main() {
println!("Game Data:{}",*GAMEDATA);
let obj = gamedata::readinginstatic::readinginstatic {
structure:"working".to_string()
};
obj.print_static();
}
mod test_stuff {
use ::GAMEDATA;
fn printthing() {
println!("herenow:{}", *GAMEDATA);
}
}
With a lib.rs file such as:
pub mod readinginstatic;
And a module in another file readinginstatic.rs as described below:
use ::GAMEDATA;
pub struct readinginstatic {
pub structure:String,
}
impl readinginstatic {
pub fn print_static(&self) {
println!("In Print static width:{}", *::GAMEDATA);
}
}
I get the error:
not found in the crate root
When trying to import GAMEDATA.
Is it possible to access a lazy_static singleton in another module if it is defined in another file?
To insure I have provided a Minimal, Complete, and Verifiable example here is my whole example code on GitHub: https://github.com/camccar/moduleError
::GAMEDATA refers to some value called GAMEDATA in the crate root of the gamedata crate. However where you defined GAMEDATA was not in that crate, it was in your main.rs file which has gamedata as a dependency.
So what you're trying to do here is reach out of a crate use something from the crate that is depending on you, which I'm not sure but I don't think is allowed.
You could consider inverting this and instead initialising GAMEDATA inside your gamedata crate instead and if you need to use it in main you can just use it normally:
extern crate gamedata;
use gamedata::GAMEDATA;
fn main(){
println!("Game Data:{}", *GAMEDATA);
...
}
Alternatively if GAMEDATA is not something your game data crate should know how to define, you could construct it inside main and pass it to some function in the gamedata crate as a parameter.

`Decodable` customization

I want to deserialize a configuration structure like this:
#[deriving(Clone, PartialEq, Decodable, Show)]
pub struct Config {
network1: Network,
network2: Network
}
#[deriving(Clone, PartialEq, Decodable, Show)]
pub struct Network {
interface: Option<String>,
prefer: Option<AddressPreference>,
address: Option<String>,
port: u16
}
#[deriving(Clone, PartialEq, Show)]
pub enum AddressPreference {
IPv4, IPv6, Any
}
It forms a tree of structs and enums. But the decoder I want to use does not support enums, so I thought that I will be able to represent the enum as a string by implementing Decodable for the enum which matches on strings. But I don't know how to do it properly.
The main problem is that I don't know how to write Decodable implementation which handles errors correctly. If I write
impl<E, D: Decoder<E>> Decodable<D, E> for AddressPreference { ... }
the only way I can indicate parsing error is fail!() - I don't know actual error type, so I can't create its instance. This is unacceptable.
Buf if I write
impl Decodable<toml::Decoder, toml::Error> for AddressPreference { ... }
that is, binding Decodable instance to concrete decoder type (which is fine for me), I lose automatic deriving of outer structures, because they are implemented for generic decoder and error:
src/sfc/config.rs:11:30: 11:39 error: expected serialize::serialize::Decodable<__D,__E>, but found serialize::serialize::Decodable<rust-toml::Decoder,rust-toml::Error> (expected type parameter but found struct rust-toml::Decoder)
src/sfc/config.rs:11 #[deriving(Clone, PartialEq, Decodable, Show)]
What should I do in this case? I guess, the proper answer in this particular case is submitting a pull request to the library enabling support for enums serialization, but I think that the question is more broad. What it the library supported enums, but I wanted to customize decoding nonetheless?