Is there a way to limit vector/string length for debug output in Rust? - rust

I need to print arbitrary structures in human-readable form. The problem is they may contain very large vectors, so I would like to limit their length up to N elements appended with ellipsis.
What is a simplest way to achieve that without messing around with procedural macros? Some crates that provide that out-of-the-box?

I'm not aware of any crate doing that, but you can easily create a newtype wrapper:
use std::fmt;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct LimitedVec<T>(pub Vec<T>);
const LIMIT: usize = 5;
impl<T: fmt::Debug> fmt::Debug for LimitedVec<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.0.iter().take(LIMIT)).finish()
}
}
Playground.

Chayim Friedman's answer doesn't include adding the ellipsis.
Tweaking the implementation of fmt::Debug further to support this is not too tricky. I did it by adjusting their code to wrap the iterated values into an enum with a More value. The code can probably be cleaned up a bit.
use core::fmt::Formatter;
use std::fmt;
enum OrMore<T> {
Value(T),
More,
}
impl<T: fmt::Debug> fmt::Debug for OrMore<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
OrMore::Value(t) => fmt::Debug::fmt(t, f),
OrMore::More => write!(f, "..."),
}
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct LimitedVec<T>(pub Vec<T>);
const LIMIT: usize = 5;
impl<T: fmt::Debug> fmt::Debug for LimitedVec<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.0.len() <= LIMIT {
f.debug_list().entries(self.0.iter().take(LIMIT)).finish()
} else {
f.debug_list()
.entries(
self.0
.iter()
.take(LIMIT)
.map(OrMore::Value)
.chain(vec![OrMore::More].into_iter()),
)
.finish()
}
}
}
fn main() {
let w = LimitedVec(vec![1, 2, 3, 4, 5]);
let v = LimitedVec(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
println!("{:?}", w); // [1, 2, 3, 4, 5]
println!("{:?}", v); // [1, 2, 3, 4, 5, ...]
}
The code might be shorter if we used an explicit loop using write!(f, ...), rather than using the f.debug_list() approach, but IIRC that doesn't play well with the multi-line debug format {:#?}.

Related

A nice version for Vec<Vec<T>>.get?

Is there any comfortable way to get value from Vec<Vec<T>>? I can do it for a normal 1D Vec: vec.get(), but if vec is Vec<Vec>, get returns the Some<Vec<T>>, not the value of T. Is there a nice way to 'get' value from 2D matrix (Vec<Vec<T>>)?
Option::and_then lets you chain optional return values (o.and_then(f) is equivalent to o.map(f).flatten()):
vec.get(i).and_then(|v| v.get(j))
It also easily extends to higher dimensions:
vec
.get(i)
.and_then(|v| v.get(j))
.and_then(|v| v.get(k))
.and_then(|v| v.get(l))
// and so on
#Aplet123 is of course right, that's the way to go and his answer should be marked correct.
But in case you wonder how to make this prettier, you could wrap it in a custom trait for Vec<Vec<T>>:
trait Get2D {
type Val;
fn get2d(&self, i: usize, j: usize) -> Option<&Self::Val>;
fn get2d_mut(&mut self, i: usize, j: usize) -> Option<&mut Self::Val>;
}
impl<T> Get2D for Vec<Vec<T>> {
type Val = T;
fn get2d(&self, i: usize, j: usize) -> Option<&T> {
self.get(i).and_then(|e| e.get(j))
}
fn get2d_mut(&mut self, i: usize, j: usize) -> Option<&mut T> {
self.get_mut(i).and_then(|e| e.get_mut(j))
}
}
fn main() {
let mut data: Vec<Vec<i32>> = vec![vec![1, 2, 3], vec![4, 5, 6]];
println!("{}", data.get2d(1, 1).unwrap());
*data.get2d_mut(0, 1).unwrap() = 42;
println!("{:?}", data);
}
5
[[1, 42, 3], [4, 5, 6]]

How to get fmt::Display from a struct to display it in the fmt::Display of another struct?

Im not sure how to name this question as I am new to Rust so feel free to suggest edits.
I have two structs. One is a Job struct, which contains a few numbers like how long a job takes, etc.
The other is a JobSequence, which contains a Vec() of Jobs.
I implemented the fmt::Display trait for the Job so that it prints out its three number in this way:
(10, 12, 43)
Now, I would like to implement the fmt::Display trait for the JobSequence struct so that it iterates over each Job in the vector and displays them in this way:
(0, 10, 5)
(30, 10, 5)
(0, 10, 5)
(0, 10, 5)
(0, 10, 5)
I think(?) I should reuse the implemented trait of the Job struct and use it so that it simply, in a way, printouts them as a semi-list. This is my current implementation, but i have a feeling that is sloppy and there is a better way:
pub struct JobSequence {
pub job_sequence: Vec<Job>,
}
impl fmt::Display for JobSequence {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut final_output = String::new();
for i in &self.job_sequence {
final_output.push_str(i.to_string().as_str());
final_output.push_str("\n");
}
write!(f, "{}", final_output)
}
}
You can re-use the the Display impl by passing it directly to write! with the {} format string:
impl fmt::Display for JobSequence {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for i in &self.job_sequence {
writeln!(f, "{}", i)?;
}
Ok(())
}
}
You can read more about the different traits used by the formatting macros in the docs. (A plain {} uses std::fmt::Display.)

How do I use Serde to serialize a HashMap with structs as keys to JSON?

I want to serialize a HashMap with structs as keys:
use serde::{Deserialize, Serialize}; // 1.0.68
use std::collections::HashMap;
fn main() {
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash)]
struct Foo {
x: u64,
}
#[derive(Serialize, Deserialize, Debug)]
struct Bar {
x: HashMap<Foo, f64>,
}
let mut p = Bar { x: HashMap::new() };
p.x.insert(Foo { x: 0 }, 0.0);
let serialized = serde_json::to_string(&p).unwrap();
}
This code compiles, but when I run it I get an error:
Error("key must be a string", line: 0, column: 0)'
I changed the code:
#[derive(Serialize, Deserialize, Debug)]
struct Bar {
x: HashMap<u64, f64>,
}
let mut p = Bar { x: HashMap::new() };
p.x.insert(0, 0.0);
let serialized = serde_json::to_string(&p).unwrap();
The key in the HashMap is now a u64 instead of a string. Why does the first code give an error?
You can use serde_as from the serde_with crate to encode the HashMap as a sequence of key-value pairs:
use serde_with::serde_as; // 1.5.1
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
struct Bar {
#[serde_as(as = "Vec<(_, _)>")]
x: HashMap<Foo, f64>,
}
Which will serialize to (and deserialize from) this:
{
"x":[
[{"x": 0}, 0.0],
[{"x": 1}, 0.0],
[{"x": 2}, 0.0]
]
}
There is likely some overhead from converting the HashMap to Vec, but this can be very convenient.
According to JSONs specification, JSON keys must be strings. serde_json uses fmt::Display in here, for some non-string keys, to allow serialization of wider range of HashMaps. That's why HashMap<u64, f64> works as well as HashMap<String, f64> would. However, not all types are covered (Foo's case here).
That's why we need to provide our own Serialize implementation:
impl Display for Foo {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "{}", self.x)
}
}
impl Serialize for Bar {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(Some(self.x.len()))?;
for (k, v) in &self.x {
map.serialize_entry(&k.to_string(), &v)?;
}
map.end()
}
}
(playground)
I've found the bulletproof solution 😃
Extra dependencies not required
Compatible with HashMap, BTreeMap and other iterable types
Works with flexbuffers
The following code converts a field (map) to the intermediate Vec representation:
pub mod vectorize {
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::iter::FromIterator;
pub fn serialize<'a, T, K, V, S>(target: T, ser: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: IntoIterator<Item = (&'a K, &'a V)>,
K: Serialize + 'a,
V: Serialize + 'a,
{
let container: Vec<_> = target.into_iter().collect();
serde::Serialize::serialize(&container, ser)
}
pub fn deserialize<'de, T, K, V, D>(des: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: FromIterator<(K, V)>,
K: Deserialize<'de>,
V: Deserialize<'de>,
{
let container: Vec<_> = serde::Deserialize::deserialize(des)?;
Ok(T::from_iter(container.into_iter()))
}
}
To use it just add the module's name as an attribute:
#[derive(Debug, Serialize, Deserialize)]
struct MyComplexType {
#[serde(with = "vectorize")]
map: HashMap<MyKey, String>,
}
The remained part if you want to check it locally:
use anyhow::Error;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct MyKey {
one: String,
two: u16,
more: Vec<u8>,
}
#[derive(Debug, Serialize, Deserialize)]
struct MyComplexType {
#[serde(with = "vectorize")]
map: HashMap<MyKey, String>,
}
fn main() -> Result<(), Error> {
let key = MyKey {
one: "1".into(),
two: 2,
more: vec![1, 2, 3],
};
let mut map = HashMap::new();
map.insert(key.clone(), "value".into());
let instance = MyComplexType { map };
let serialized = serde_json::to_string(&instance)?;
println!("JSON: {}", serialized);
let deserialized: MyComplexType = serde_json::from_str(&serialized)?;
let expected_value = "value".to_string();
assert_eq!(deserialized.map.get(&key), Some(&expected_value));
Ok(())
}
And on the Rust playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=bf1773b6e501a0ea255ccdf8ce37e74d
While all provided answers will fulfill the goal of serializing your HashMap to json they are ad hoc or hard to maintain.
One correct way to allow a specific data structure to be serialized with serde as keys in a map, is the same way serde handles integer keys in HashMaps (which works): They serialize the value to String. This has a few advantages; namely
Intermediate data-structure omitted,
no need to clone the entire HashMap,
easier maintained by applying OOP concepts, and
serialization usable in more complex structures such as MultiMap.
This can be done by manually implementing Serialize and Deserialize for your data-type.
I use composite ids for maps.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct Proj {
pub value: u64,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct Doc {
pub proj: Proj,
pub value: u32,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct Sec {
pub doc: Doc,
pub value: u32,
}
So now manually implementing serde serialization for them is kind of a hassle, so instead we delegate the implementation to the FromStr and From<Self> for String (Into<String> blanket) traits.
impl From<Doc> for String {
fn from(val: Doc) -> Self {
format!("{}{:08X}", val.proj, val.value)
}
}
impl FromStr for Doc {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match parse_doc(s) {
Ok((_, p)) => Ok(p),
Err(e) => Err(e.to_string()),
}
}
}
In order to parse the Doc we make use of nom. The parse functionality below is explained in their examples.
fn is_hex_digit(c: char) -> bool {
c.is_digit(16)
}
fn from_hex8(input: &str) -> Result<u32, std::num::ParseIntError> {
u32::from_str_radix(input, 16)
}
fn parse_hex8(input: &str) -> IResult<&str, u32> {
map_res(take_while_m_n(8, 8, is_hex_digit), from_hex8)(input)
}
fn parse_doc(input: &str) -> IResult<&str, Doc> {
let (input, proj) = parse_proj(input)?;
let (input, value) = parse_hex8(input)?;
Ok((input, Doc { value, proj }))
}
Now we need to hook up self.to_string() and str::parse(&str) to serde we can do this using a simple macro.
macro_rules! serde_str {
($type:ty) => {
impl Serialize for $type {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let s: String = self.clone().into();
serializer.serialize_str(&s)
}
}
impl<'de> Deserialize<'de> for $type {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
paste! {deserializer.deserialize_string( [<$type Visitor>] {})}
}
}
paste! {struct [<$type Visitor>] {}}
impl<'de> Visitor<'de> for paste! {[<$type Visitor>]} {
type Value = $type;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("\"")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match str::parse(v) {
Ok(id) => Ok(id),
Err(_) => Err(serde::de::Error::custom("invalid format")),
}
}
}
};
}
Here we are using paste to interpolate the names. Beware that now the struct will always serialize as defined above. Never as a struct, always as a string.
It is important to implement fn visit_str instead of fn visit_string because visit_string defers to visit_str.
Finally, we have to call the macro for our custom structs
serde_str!(Sec);
serde_str!(Doc);
serde_str!(Proj);
Now the specified types can be serialized to and from string with serde.

How to cast slice to reference of array in rust [duplicate]

I have an array of an unknown size, and I would like to get a slice of that array and convert it to a statically sized array:
fn pop(barry: &[u8]) -> [u8; 3] {
barry[0..3] // expected array `[u8; 3]`, found slice `[u8]`
}
How would I do this?
You can easily do this with the TryInto trait (which was stabilized in Rust 1.34):
// Before Rust 2021, you need to import the trait:
// use std::convert::TryInto;
fn pop(barry: &[u8]) -> [u8; 3] {
barry.try_into().expect("slice with incorrect length")
}
But even better: there is no need to clone/copy your elements! It is actually possible to get a &[u8; 3] from a &[u8]:
fn pop(barry: &[u8]) -> &[u8; 3] {
barry.try_into().expect("slice with incorrect length")
}
As mentioned in the other answers, you probably don't want to panic if the length of barry is not 3, but instead handle this error gracefully.
This works thanks to these impls of the related trait TryFrom (before Rust 1.47, these only existed for arrays up to length 32):
impl<'_, T, const N: usize> TryFrom<&'_ [T]> for [T; N]
where
T: Copy,
impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N]
impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N]
Thanks to #malbarbo we can use this helper function:
use std::convert::AsMut;
fn clone_into_array<A, T>(slice: &[T]) -> A
where
A: Default + AsMut<[T]>,
T: Clone,
{
let mut a = A::default();
<A as AsMut<[T]>>::as_mut(&mut a).clone_from_slice(slice);
a
}
to get a much neater syntax:
fn main() {
let original = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let e = Example {
a: clone_into_array(&original[0..4]),
b: clone_into_array(&original[4..10]),
};
println!("{:?}", e);
}
as long as T: Default + Clone.
If you know your type implements Copy, you can use this form:
use std::convert::AsMut;
fn copy_into_array<A, T>(slice: &[T]) -> A
where
A: Default + AsMut<[T]>,
T: Copy,
{
let mut a = A::default();
<A as AsMut<[T]>>::as_mut(&mut a).copy_from_slice(slice);
a
}
Both variants will panic! if the target array and the passed-in slice do not have the same length.
I recommend using the crate arrayref, which has a handy macro for doing just this.
Note that, using this crate, you create a reference to an array, &[u8; 3], because it doesn't clone any data!
If you do want to clone the data, then you can still use the macro, but call clone at the end:
#[macro_use]
extern crate arrayref;
fn pop(barry: &[u8]) -> &[u8; 3] {
array_ref!(barry, 0, 3)
}
or
#[macro_use]
extern crate arrayref;
fn pop(barry: &[u8]) -> [u8; 3] {
array_ref!(barry, 0, 3).clone()
}
You can manually create the array and return it.
Here is a function that can easily scale if you want to get more (or less) than 3 elements.
Note that if the slice is too small, the end terms of the array will be 0's.
fn pop(barry: &[u8]) -> [u8; 3] {
let mut array = [0u8; 3];
for (&x, p) in barry.iter().zip(array.iter_mut()) {
*p = x;
}
array
}
Here's a function that matches the type signature you asked for.
fn pop(barry: &[u8]) -> [u8; 3] {
[barry[0], barry[1], barry[2]]
}
But since barry could have fewer than three elements, you may want to return an Option<[u8; 3]> rather than a [u8; 3].
fn pop(barry: &[u8]) -> Option<[u8; 3]> {
if barry.len() < 3 {
None
} else {
Some([barry[0], barry[1], barry[2]])
}
}
I was unhappy with other answers because I needed several functions that return varying length fixed u8 arrays. I wrote a macro that produces functions specific for the task. Hope it helps someone.
#[macro_export]
macro_rules! vec_arr_func {
($name:ident, $type:ty, $size:expr) => {
pub fn $name(data: std::vec::Vec<$type>) -> [$type; $size] {
let mut arr = [0; $size];
arr.copy_from_slice(&data[0..$size]);
arr
}
};
}
//usage - pass in a name for the fn, type of array, length
vec_arr_func!(v32, u8, 32);
v32(data); //where data is std::vec::Vec<u8>
The nice common thing between Vec, 'Slice' and Array is Iter, so you can zip and map both together, as simple as:
let x = vec![1, 2, 3];
let mut y: [u8; 3] = [Default::default(); 3];
println!("y at startup: {:?}", y);
x.iter().zip(y.iter_mut()).map(|(&x, y)| *y = x).count();
println!("y copied from vec: {:?}", y);
This is as the array is 1 dimensional array.
To test all together, vec, slice and array, here you go:
let a = [1, 2, 3, 4, 5];
let slice = &a[1..4];
let mut x: Vec<u8> = vec![Default::default(); 3];
println!("X at startup: {:?}", x);
slice.iter().zip(x.iter_mut()).map(|(&s, x)| *x = s).count();
println!("X copied from vec: {:?}", x);
Another option which should be faster than byte-by-byte copy is:
y[..x.len()].copy_from_slice(&x);
Which is applicable for all, below is example:
let a = [1, 2, 3, 4, 5];
let mut b: Vec<u8> = vec![Default::default(); 5];
b[..a.len()].copy_from_slice(&a);
println!("Copy array a into vector b: {:?}", b);
let x: Vec<u8> = vec![1, 2, 3, 4, 5];
let mut y: [u8; 5] = [Default::default(); 5];
y[..x.len()].copy_from_slice(&x);
println!("Copy vector x into array y: {:?}", y);

How to implement PartialEq on Vector for my own structs?

I have the following definition:
pub struct List<T> {
memory: Vec<T>,
}
I would get the equivalent of #[derive(PartialEq)] for this type like describe in How can I implement PartialEq?
I use a match expression, like:
impl<T: PartialEq> PartialEq for List<T> {
fn eq(&self, other: &List<T>) -> bool {
self.memory == other.memory
}
}
impl<T: fmt::Debug> fmt::Debug for List<T> where T:Display {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "["));
for (count, v) in self.memory.iter().enumerate() {
if count != 0 { try!(write!(f, ", ")); }
try!(write!(f, "{}", v));
}
write!(f, "]")
}
}
impl<T> List<T> {
pub fn new() -> Self {
List {
memory: Vec::new(),
}
}
// push() add to end of list
pub fn push(&mut self, value: T) {
self.memory.push(value);
}
}
But the compiler gives me these errors:
error: mismatched types [E0308]
if ! ( * left_val == * right_val ) {
note: in this expansion of assert_eq!
help: run rustc --explain E0308 to see a detailed explanation
note: expected type librusty_data_structures::List<u32>
note: found type [_; 4]
main.rs that produce compile errors
let mut listex: List<u32> = List::new();
listex.push(17);
listex.push(18);
listex.push(19);
listex.push(20);
assert_eq!(listex, [17, 18, 19, 20]);
I don't understand why that matters. Why is it even looking at that type?
listex and [17, 18, 19, 20] have different types (List<u32> and [_; 4]) , so you cannot check for their equality. You need to change the type of one of the arguments of assert_eq!() so the types match. The simplest option would be to reference listex's memory:
assert_eq!(&listex.memory[0..4], [17, 18, 19, 20]);
Or you can convert [17, 18, 19, 20] to a List<u32> so that the PartialEq implementation for List<T> can be put into action.
If you were to compare listex with another List<32>, your PartialEq implementation would allow checks for equality (though you would need the List<T> to derive Debug in order to do perform assert_eq!() on them).
Edit: as for your question "Why is it even looking at that type?", notice that in your implementation of PartialEq:
fn eq(&self, other: &List<T>)
You specify that eq works only for two arguments of type &List<T> (&self points to List<T>).
Here is the solution, following cuviper response on The Rust Programming Language Forum
impl<T, U> PartialEq<U> for List<T>
where Vec<T>: PartialEq<U>
{
fn eq(&self, other: &U) -> bool {
self.memory.eq(other)
}
}
To test :
let mut listex: List<u32> = List::new();
listex.push(17);
listex.push(18);
listex.push(19);
listex.push(20);
println!("{}", listex == [17, 18, 19, 20]);

Resources