Having this
#[derive(Debug, PartialEq, Default)]
pub enum CellContent {
Move(Symbol),
#[default]
Empty,
}
pub struct Game {
pub table: [[CellContent; 3]; 3],
}
How can I short this ?
pub fn new() -> Game {
Game {
table: [
[
CellContent::default(),
CellContent::default(),
CellContent::default(),
],
[
CellContent::default(),
CellContent::default(),
CellContent::default(),
],
[
CellContent::default(),
CellContent::default(),
CellContent::default(),
],
],
}
}
| Please, answering, point me to rust book page or other official documentation
NOTE: I am not looking for some advanced trick, but only to syntax sugar, if any
When the type of an array element implements Default, the array type itself does as well, so you can just populate table with Default::default():
pub fn new() -> Game {
Game {
table: Default::default(),
}
}
This will use Default to obtain the initial value for the nested arrays, which will in turn use the Default implementation of CellContent to obtain the initial value for each nested array element.
If your type CellContent derives Copy then you could also use copy-initialization of array elements; the syntax [x; N] creates an array of N elements, copying x to fill all N elements:
pub fn new() -> Game {
Game {
table: [[CellContent::default(); 3]; 3],
}
}
Related
I need to deserialize an array (JSON) of a type let call Foo. I have implemented this and it works well for most stuff, but I have noticed the latest version of the data will sometimes include erroneous empty objects.
Prior to this change, each Foo can be de-serialized to the following enum:
#[derive(Deserialize)]
#[serde(untagged)]
pub enum Foo<'s> {
Error {
// My current workaround is using Option<Cow<'s, str>>
error: Cow<'s, str>,
},
Value {
a: u32,
b: i32,
// etc.
}
}
/// Foo is part of a larger struct Bar.
#[derive(Deserialize)]
#[serde(untagged)]
pub struct Bar<'s> {
foos: Vec<Foo<'s>>,
// etc.
}
This struct may represent one of the following JSON values:
// Valid inputs
[]
[{"a": 34, "b": -23},{"a": 33, "b": -2},{"a": 37, "b": 1}]
[{"error":"Unable to connect to network"}]
[{"a": 34, "b": -23},{"error":"Timeout"},{"a": 37, "b": 1}]
// Possible input for latest versions of data
[{},{},{},{},{},{},{"a": 34, "b": -23},{},{},{},{},{},{},{},{"error":"Timeout"},{},{},{},{},{},{}]
This does not happen very often, but it is enough to cause issues. Normally, the array should include 3 or less entries, but these extraneous empty objects break that convention. There is no meaningful information I can gain from parsing {} and in the worst cases there can be hundreds of them in one array.
I do not want to error on parsing {} as the array still contains other meaningful values, but I do not want to include {} in my parsed data either. Ideally I would also be able to use tinyvec::ArrayVec<[Foo<'s>; 3]> instead of a Vec<Foo<'s>> to save memory and reduce time spent performing allocation during paring, but am unable to due to this issue.
How can I skip {} JSON values when deserializing an array with serde in Rust?
I also put together a Rust Playground with some test cases to try different solutions.
serde_with::VecSkipError provides a way to ignore any elements which fail deserialization, by skipping them. This will ignore any errors and not only the empty object {}. So it might be too permissive.
#[serde_with::serde_as]
#[derive(Deserialize)]
pub struct Bar<'s> {
#[serde_as(as = "serde_with::VecSkipError<_>")]
foos: Vec<Foo<'s>>,
}
Playground
The simplest, but not performant, solution would be to define an enum that captures both the Foo case and the empty case, deserialize into a vector of those, and then filter that vector to get just the nonempty ones.
#[derive(Deserialize, Debug)]
#[serde(untagged)]
pub enum FooDe<'s> {
Nonempty(Foo<'s>),
Empty {},
}
fn main() {
let json = r#"[
{},{},{},{},{},{},
{"a": 34, "b": -23},
{},{},{},{},{},{},{},
{"error":"Timeout"},
{},{},{},{},{},{}
]"#;
let foo_des = serde_json::from_str::<Vec<FooDe>>(json).unwrap();
let foos = foo_des
.into_iter()
.filter_map(|item| {
use FooDe::*;
match item {
Nonempty(foo) => Some(foo),
Empty {} => None,
}
})
.collect();
let bar = Bar { foos };
println!("{:?}", bar);
// Bar { foos: [Value { a: 34, b: -23 }, Error { error: "Timeout" }] }
}
Conceptually this is simple but you're allocating a lot of space for Empty cases that you ultimately don't need. Instead, you can control exactly how deserialization is done by implementing it yourself.
struct BarVisitor<'s> {
marker: PhantomData<fn() -> Bar<'s>>,
}
impl<'s> BarVisitor<'s> {
fn new() -> Self {
BarVisitor {
marker: PhantomData,
}
}
}
// This is the trait that informs Serde how to deserialize Bar.
impl<'de, 's: 'de> Deserialize<'de> for Bar<'s> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
impl<'de, 's: 'de> Visitor<'de> for BarVisitor<'s> {
// The type that our Visitor is going to produce.
type Value = Bar<'s>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a list of objects")
}
fn visit_seq<V>(self, mut access: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
let mut foos = Vec::new();
while let Some(foo_de) = access.next_element::<FooDe>()? {
if let FooDe::Nonempty(foo) = foo_de {
foos.push(foo)
}
}
let bar = Bar { foos };
Ok(bar)
}
}
// Instantiate our Visitor and ask the Deserializer to drive
// it over the input data, resulting in an instance of Bar.
deserializer.deserialize_seq(BarVisitor::new())
}
}
fn main() {
let json = r#"[
{},{},{},{},{},{},
{"a": 34, "b": -23},
{},{},{},{},{},{},{},
{"error":"Timeout"},
{},{},{},{},{},{}
]"#;
let bar = serde_json::from_str::<Bar>(json).unwrap();
println!("{:?}", bar);
// Bar { foos: [Value { a: 34, b: -23 }, Error { error: "Timeout" }] }
}
I have a data model that I would like to be deserialized from "camelCase" to the rust standard "snake_case" when reading from a source, X. But I'd like to leave it in "snake_case" when reading or writing to another source, Y.
For example, the following code,
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Data {
foo_bar: String,
hello_word: String,
}
can only be encoded and decoded in camel case. Even if I manually defined my Serialize and Deserialize implementations, I can't define multiple for the same struct. I could define a second struct that's a copy/paste of the other and then derive but that method would get tedious with multiple large structs. What I would really like to do is specify that rename_all attribute at run-time. But I'm not seeing any way to do that in serde's API.
I think the best way sigh is to just write out one struct Data_ per #[serde(rename_all = ...)], then write one additional struct Data that will be the in-memory representation (which won't be serializable, to remove ambiguity), then implement From in both directions for the Data_s and Data so that they're interconvertible.
Thankfully, we can use a macro so that we only have to specify the fields once. (It is incredibly disgusting nonetheless.)
This playground available here.
use serde::{Deserialize, Serialize}; // 1.0.130
use serde_json; // 1.0.69
macro_rules! interconvertible {
($T:ident <-> $U:ident, $($field_name:ident),*) => {
impl From<$T> for $U {
fn from(t: $T) -> Self {
let $T { $($field_name),* } = t;
Self { $($field_name),* }
}
}
impl From<$U> for $T {
fn from(u: $U) -> Self {
let $U { $($field_name),* } = u;
Self { $($field_name),* }
}
}
};
}
macro_rules! create_data_structs {
($($field_name:ident: $field_type:ty),* $(,)?) => {
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct DataX {
$($field_name: $field_type),*
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "snake_case")]
struct DataY {
$($field_name: $field_type),*
}
#[derive(Debug)]
struct Data {
$($field_name: $field_type),*
}
interconvertible!(DataX <-> Data, $($field_name),*);
interconvertible!(DataY <-> Data, $($field_name),*);
}
}
create_data_structs!(foo_bar: String, hello_world: String);
fn main() -> serde_json::Result<()> {
let x1: DataX = serde_json::from_str(r#"{"fooBar": "a", "helloWorld": "b"}"#)?;
let y1: DataY = serde_json::from_str(r#"{"foo_bar": "a", "hello_world": "b"}"#)?;
println!("{:?}, {:?}", x1, y1);
let x2: Data = x1.into();
let y2: Data = y1.into();
println!("{:?}, {:?}", x2, y2);
let x_string = serde_json::to_string(&DataX::from(x2))?;
let y_string = serde_json::to_string(&DataY::from(y2))?;
println!("{:?}, {:?}", x_string, y_string);
Ok(())
}
The output is:
DataX { foo_bar: "a", hello_world: "b" }, DataY { foo_bar: "a", hello_world: "b" }
[Data { foo_bar: "a", hello_world: "b" }, Data { foo_bar: "a", hello_world: "b" }]
"{\"fooBar\":\"a\",\"helloWorld\":\"b\"}", "{\"foo_bar\":\"a\",\"hello_world\":\"b\"}"
Since I'm only every decoding from source X I can utilize the #[serde(alias = ???)] macro. So my above use case would be
#[derive(Serialize, Deserialize)]
struct Data {
#[serde(alias="fooBar")]
foo_bar: String,
#[serde(alias="helloWorld")]
hello_word: String,
}
It's still a little tedious but better than an intermediate struct. It won't work though if I want to decode or encode to different cases.
(I'm not going to mark this as an answer because it's a work-around for my specific use case. If anyone has a more generic solution feel free to answer.)
I am new to rust and working on a tool which interacts with the Binance API. The API returns a response like so:
{
"lastUpdateId": 1027024,
"bids": [
[
"4.00000000", // PRICE
"431.00000000" // QTY
]
],
"asks": [
[
"4.00000200",
"12.00000000"
]
]
}
Bids and Asks are an array of arrays. I have to declare the struct for the API response.
I currently have
use reqwest::Error;
use serde::Deserialize;
#[derive(Deserialize, Debug)]
struct Depth {
lastUpdateId: u32,
bids: Vec<u64>,
asks: Vec<u64>,
}
#[tokio::main]
pub async fn order_book() -> Result<(), Error> {
let request_url = format!("https://api.binance.us/api/v3/depth?symbol=BTCUSD");
println!("{}", request_url);
let response = reqwest::get(&request_url).await?;
println!("Status: {}", response.status());
let depth: Depth = response.json().await?;
println!("{:?}", depth);
Ok(())
}
I believe I am declaring the type for bids and asks incorrectly but I am unable to determine how to declare an array of arrays. I get a response.status of 200, but I am unable to print out the response.json.
Thank You!
Since it returns an array of arrays, you need to nest the types. bids: Vec<Vec<u64>> should work, but since you know each inner array will have two elements, you can make it more efficient with bids: Vec<[u64; 2]> - a dynamically-sized vector of fixed-size arrays, or bids: Vec<(u64, u64)>, a dynamically-sized vector of tuples. You'd also need to update asks similarly.
Your final code could look something like this:
use reqwest::Error;
use serde::Deserialize;
#[derive(Deserialize, Debug)]
struct Depth {
lastUpdateId: u32,
bids: Vec<(u64, u64)>,
asks: Vec<(u64, u64)>,
}
#[tokio::main]
pub async fn order_book() -> Result<(), Error> {
let request_url = format!("https://api.binance.us/api/v3/depth?symbol=BTCUSD");
println!("{}", request_url);
let response = reqwest::get(&request_url).await?;
println!("Status: {}", response.status());
let depth: Depth = response.json().await?;
println!("{:?}", depth);
Ok(())
}
I have the following data structure which should be able to hold either a String, a u64 value, a boolean value, or a String vector.
#[derive(Serialize, Deserialize)]
pub enum JsonRpcParam {
String(String),
Int(u64),
Bool(bool),
Vec(Vec<String>)
}
The use case for this data structure is to build JSON RPC parameters which can have multiple types, so I would be able to build a parameter list like this:
let mut params : Vec<JsonRpcParam> = Vec::new();
params.push(JsonRpcParam::String("Test".to_string()));
params.push(JsonRpcParam::Bool(true));
params.push(JsonRpcParam::Int(64));
params.push(JsonRpcParam::Vec(vec![String::from("abc"), String::from("cde")]));
My problem is now the serialization. I am using serde_json for the serialization part. The default serialization of the vector posted above yields:
[
{
"String":"Test"
},
{
"Bool":true
},
{
"Int":64
},
{
"Vec":[
"abc",
"cde"
]
}
]
Instead, I would like the serialization to look like this:
[
"Test",
true,
64,
["abc","cde"]
]
I attempted to implement a custom serialize method for this type, but dont't know how to achieve what I want, my attempt looks like this:
impl Serialize for JsonRpcParam {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer {
match *self {
JsonRpcParam::String(x) => serializer.serialize_str(x),
JsonRpcParam::Int(x) => serializer.serialize_u64(x),
JsonRpcParam::Bool(x) => serializer.serialize_bool(x),
JsonRpcParam::Vec(x) => _
}
}
}
Instead of manually implementing Serialize you can instead use #[serde(untagged)].
In your case that will work perfectly fine. However, be warned that if the enum variant isn't unique and can't be clearly identified from the JSON, then it will deserialize into the first variant that matches. In short if you also have e.g. a subsequent JsonRpcParam::OtherString(String), then that will deserialize into JsonRpcParam::String(String).
#[derive(Serialize, Deserialize, Debug)]
#[serde(untagged)]
pub enum JsonRpcParam {
String(String),
Int(u64),
Bool(bool),
Vec(Vec<String>),
}
If you now use e.g. serde_json::to_string_pretty(), then it will yield an output in your desired format:
fn main() {
let mut params: Vec<JsonRpcParam> = Vec::new();
params.push(JsonRpcParam::String("Test".to_string()));
params.push(JsonRpcParam::Bool(true));
params.push(JsonRpcParam::Int(64));
params.push(JsonRpcParam::Vec(vec![
String::from("abc"),
String::from("cde"),
]));
let json = serde_json::to_string_pretty(¶ms).unwrap();
println!("{}", json);
}
Output:
[
"Test",
true,
64,
[
"abc",
"cde"
]
]
Here's where I'm starting from:
#[derive(PartialEq)]
enum ControlItem {
A {
name: &'static str,
},
B {
name: &'static str,
},
}
struct Control {
items: Vec<(ControlItem, bool)>,
}
impl Control {
pub fn set(&mut self, item: ControlItem, is_ok: bool) {
match self.items.iter().position(|ref x| (**x).0 == item) {
Some(idx) => {
self.items[idx].1 = is_ok;
}
None => {
self.items.push((item, is_ok));
}
}
}
pub fn get(&self, item: ControlItem) -> bool {
match self.items.iter().position(|ref x| (**x).0 == item) {
Some(idx) => return self.items[idx].1,
None => return false,
}
}
}
fn main() {
let mut ctrl = Control { items: vec![] };
ctrl.set(ControlItem::A { name: "a" }, true);
assert_eq!(ctrl.get(ControlItem::A { name: "a" }), true);
ctrl.set(ControlItem::B { name: "b" }, false);
assert_eq!(ctrl.get(ControlItem::B { name: "b" }), false);
}
I have a Control type that should save the state of some predefined items and report it back to user.
I have a virtual table in my mind, like this:
|Name in program | Name for user |
|item_1 | Item one bla-bla |
|item_2 | Item two bla-bla |
|item_3 | Item three another-bla-bla|
I want Control to have get / set methods that accept only things with names item_1, item_2, item_3.
I want to hold this virtual table in two crates: "main" and "platform". Most of the implementation of Control should be in the main crate, and definitions of the items (like item_3) should go into the platform crate. I want to register item_3 at compile time.
Any ideas on how achieve this?
It sounds like you should use a trait, not an enum. You could define a trait and implement it like this:
pub trait ControlItem {
fn name(&self) -> &str;
}
struct A(&'static str);
impl ControlItem for A {
fn name(&self) -> &str {
self.0
}
}
// ... similar struct and impl blocks for other items
Then these structs can be moved into separate crates.
You'd need to change Control to store a Vec<(Box<ControlItem>, bool)>, and either change get and set to take a Box<ControlItem>, or to be generic over T: ControlItem.
Read about traits and trait objects for more.