I have the following toml::map::Map object named groups. How can I convert groups to a standard std::collections::HashMap? In other words, I would like to cast toml::map::Map to std::collections::HashMap.
As an added constraint, assume that the keys and values are mutable. This means that the keys may not always be "band" and "mode".
use serde::*;
use std::collections::HashMap;
use toml::value::Value;
use toml::map::Map;
fn main() {
let v1 = Value::String("20m".to_string());
let v2 = Value::String("40m".to_string());
let v3 = Value::String("cw".to_string());
let v4 = Value::String("ssb".to_string());
let band = Value::Array(vec![v1, v2]);
let mode = Value::Array(vec![v3, v4]);
let mut g = Map::new();
g.insert("band".to_string(), band);
g.insert("mode".to_string(), mode);
let groups = Some(g);
dbg!("{:#?}", groups);
}
HashMap::deserialize() can accept a toml::Value::Table. To modify the script above try this:
use serde::*;
use std::collections::HashMap;
use toml::value::Value;
use toml::map::Map;
fn main() {
let v1 = Value::String("20m".to_string());
let v2 = Value::String("40m".to_string());
let v3 = Value::String("cw".to_string());
let v4 = Value::String("ssb".to_string());
let band = Value::Array(vec![v1, v2]);
let mode = Value::Array(vec![v3, v4]);
let mut g = Map::new();
g.insert("band".to_string(), band);
g.insert("mode".to_string(), mode);
let res: HashMap<String, Vec<String>> = HashMap::deserialize(toml::Value::Table(g)).unwrap();
dbg!(res);
}
Rust Playground Run
Related
Why does a peekable iterator return a double reference in an Option?
struct Foo {}
let mut foovec = vec![];
foovec.push(Foo {});
let mut iter = foovec.iter().peekable();
let next = iter.peek();
next is an Option<&&Foo>, not an Option<&Foo>.
How do I get it to be the latter?
I do not want to use .into_iter() because I do not want to consume the vec. I just want a borrowed reference to the Foo struct wrapped in an Option.
peek yields references to whatever you're iterating over. If that's also references, it'll yield double references. You can use the copied Option adapter to remove that level of indirection:
struct Foo {}
let mut foovec = vec![];
foovec.push(Foo {});
let mut iter = foovec.iter().peekable();
// use `copied` here to go from Option<&&_> to Option<&_>
let next = iter.peek().copied();
Alternatively, you can just call next after you checked that you want the peeked value:
struct Foo {}
let mut foovec = vec![];
foovec.push(Foo {});
let mut iter = foovec.iter().peekable();
if is_okay(iter.peek()) {
let next = iter.next(); // `next` has type `&Foo`
}
You could even use pattern matching to remove one level of indirection:
if let Some(&next) = iter.peek() {
// `next` has type `&Foo` in this block
}
I'm using HashSets to find the differences between 2 vectors
let a = vec!["a".to_string(), "b".to_string(), "f".to_string(), "e".to_string()];
let b = vec!["a".to_string(), "c".to_string(), "d".to_string()];
let a_set: HashSet<&String> = HashSet::from_iter(a.iter());
let b_set: HashSet<&String> = HashSet::from_iter(b.iter());
let missing_a = b_set.difference(&a_set).cloned().collect();
let missing_b = a_set.difference(&b_set).cloned().collect();
assert_eq!(missing_a, vec!["c".to_string(), "d".to_string()]);
assert_eq!(missing_b, vec!["f".to_string(), "e".to_string()]);
Currently, the order of missing_a and missing_b is not the same each time it is run, so the test can fail.
How can I make sure that HashSet::difference returns the same output every time?
Hash-based containers typically do not have deterministic ordering. From the documentation for HashSet::iter():
An iterator visiting all elements in arbitrary order.
Just collect the results into a container type that does not take order into account when comparing container values for equality -- such as HashSet:
fn main() {
let a = vec!["a".to_string(), "b".to_string(), "f".to_string(), "e".to_string()];
let b = vec!["a".to_string(), "b".to_string(), "c".to_string(), "d".to_string()];
let a_set: HashSet<&String> = HashSet::from_iter(a.iter());
let b_set: HashSet<&String> = HashSet::from_iter(b.iter());
let missing_a = b_set.difference(&a_set).cloned().collect::<HashSet<_>>();
let missing_b = a_set.difference(&b_set).cloned().collect::<HashSet<_>>();
assert_eq!(missing_a, HashSet::from_iter([&"c".to_string(), &"d".to_string()]));
assert_eq!(missing_b, HashSet::from_iter([&"f".to_string(), &"e".to_string()]));
}
(Playground)
Thanks to #PitaJ, I decided to use a BTreeSet:
let a = vec!["a".to_string(), "b".to_string(), "f".to_string(), "e".to_string()];
let b = vec!["a".to_string(), "c".to_string(), "d".to_string()];
let a_set: BTreeSet<&String> = BTreeSet::from_iter(a.iter());
let b_set: BTreeSet<&String> = BTreeSet::from_iter(b.iter());
let missing_a = b_set.difference(&a_set).cloned().collect();
let missing_b = a_set.difference(&b_set).cloned().collect();
assert_eq!(missing_a, vec!["c".to_string(), "d".to_string()]);
assert_eq!(missing_b, vec!["f".to_string(), "e".to_string()]);
I want to know how to code Closure(function) with Box argument in Rust.
For just , it's simple.
fn main() {
let a = 5;
let double = |x| 2 * x;
let b = double(a); //10
}
now, for Box
fn main() {
let a = Box::new(5);
let double = |x| 2 * x; //how to write?
let b = double(a);
}
I don't know what is the adequate or smart way to code, and for unknown reason, the official document or Google did not help.
Please advise.
Here is an example how you can do that:
fn main() {
let a = Box::new(5);
let double = |x: Box<i32>| 2 * *x;
let b = double(a);
print!("{b}")
}
First, you need to specify the closure parameter type in this case. Instead of Box<i32>, you can also write Box<_>.
Next, you need to get the value owned by the Box via *x.
I am trying to write a GTK4 application in rust that should be compliant with parts of the Extended Window Manager Hints spec, but for that I need to be able to get and set X11 hints. In particular, I want to set _NET_WM_WINDOW_TYPE.
If I were to create a window as follows, how would I get/set X11 window hints?
let app = Application::new(Some("id"), Default::default());
let window = ApplicationWindow::new(app);
After a few days of trial and error, I arrived to the following solution:
use gdk_x11::x11::xlib::{PropModeReplace, XChangeProperty, XInternAtom, XA_ATOM};
fn set_window_props(window: >k::Window, prop_name: &str, prop_values: &Vec<&str>) {
let display = window.display();
let surface = window.surface().unwrap();
let prop_name_cstr = CString::new(prop_name).unwrap();
let prop_values_cstr: Vec<CString> = prop_values
.iter()
.map(|val| CString::new(*val).unwrap())
.collect();
unsafe {
let xid: xlib::Window = surface.unsafe_cast::<X11Surface>().xid();
let xdisplay: *mut xlib::Display = display.unsafe_cast::<X11Display>().xdisplay();
let prop_name_atom = XInternAtom(xdisplay, prop_name_cstr.as_ptr(), xlib::False);
let mut prop_values_atom: Vec<u64> = prop_values_cstr
.into_iter()
.map(|cstr| XInternAtom(xdisplay, cstr.as_ptr(), xlib::False))
.collect();
let num_values = prop_values_atom.len();
let prop_values_c = prop_values_atom.as_mut_ptr();
XChangeProperty(
xdisplay,
xid,
prop_name_atom,
XA_ATOM,
32,
PropModeReplace,
prop_values_c as *const u8,
num_values as i32,
);
}
}
This will set the replace the values of type XA_ATOM of the X11 Window property prop_name with the atom values prop_values.
For setting properties of type utf8, it is much simpler and cleaner to use gdk4_x11::X11Surface::set_utf8_property.
struct Foo{
value: i32
}
impl Foo{
fn get_and_change_value(&mut self) -> i32{
let v = self.value;
self.value = 42;
v
}
}
//glue_code_macro
fn main(){
let mut f1 = Foo{value:1};
let mut f2 = Foo{value:2};
let mut f3 = Foo{value:3};
let v: Vec<i32> = glue_code_macro!(f1,f2,f3);
}
I want to create the glue_code_macro which takes n variables and creates a vector. I don't think that I can achieve this with a normal function because I have a mutable reference and I would be unable to change its content.
In my head it would expand to
let v = {
let v1 = f1.get_and_change_value();
let v2 = f2.get_and_change_value();
let v3 = f3.get_and_change_value();
vec!(v1,v2,v3)
}
Is this possible? If yes how would I do this?
It's possible. Add this to the top of your module:
#![feature(macro_rules)]
macro_rules! glue_code_macro(
($($element:ident),*) => (
vec![$($element.get_and_change_value(),)*]
)
)
The macro guide explains how it works: http://doc.rust-lang.org/guide-macros.html