In the following code, I want automatically initialize my array:
struct ColorQueue {
queue: String,
color: String,
}
impl ColorQueue {
pub fn new(queue: &str) -> Self {
Self {
queue: String::from(queue),
color: "".to_string(),
}
}
fn name_colors(&self) {
let colorqueue = [
ColorQueue {
queue: "amig".to_string(),
color: "HRED".to_string(),
},
ColorQueue {
queue: "micmac".to_string(),
color: "GRN".to_string(),
},
ColorQueue {
queue: "ssfa".to_string(),
color: "YEL".to_string(),
},
ColorQueue {
queue: "chrody".to_string(),
color: "BLU".to_string(),
},
ColorQueue {
queue: "ngs".to_string(),
color: "MAG".to_string(),
},
ColorQueue {
queue: "emc2".to_string(),
color: "CYN".to_string(),
},
ColorQueue {
queue: "cryoem".to_string(),
color: "WHT".to_string(),
},
ColorQueue {
queue: "common".to_string(),
color: "BWHT".to_string(),
},
ColorQueue {
queue: "lowprio".to_string(),
color: "RED".to_string(),
},
ColorQueue {
queue: "bim".to_string(),
color: "BCYN".to_string(),
},
ColorQueue {
queue: "runxx".to_string(),
color: "BBLU".to_string(),
},
];
}
pub fn set_queue_name(&mut self, queue: String) {
self.queue = queue;
}
pub fn get_color(&self) -> &String {
for item in 1..self.colorqueue.len() {
if self.queue == self.colorqueue[item].queue {
return &self.colorqueue[item].color;
}
}
}
pub fn get_queue_name(&self) -> &String {
return &self.queue;
}
}
fn main() {
let mut cqueue = ColorQueue::new(&"amig");
ColorQueue::set_queue_name("amig".to_string());
println!("{}", cqueue.get_queue_name());
cqueue.set_queue_name("ngs".to_string());
println!("{}", cqueue.get_queue_name())
}
For now I can assign a queue. What I want is a function get_color(queue) that returns the color field, depending on queue name.
This should return "MAG":
cqueue.set_queue_name("ngs".to_string());
cqueue.get_color();
But I must initialize my array in the object.
In essence you want to get a predefined color for a given queue ID.
First, let's make a place for the default colors.
I'd make a module for that:
pub mod queue_default_colors { ... }
and in there have a private static variable:
static default_colors: &[(&'static str, &'static str)] = &[
("amig", "HRED"),
("micmac", "GRN"),
...
];
And based on that implement your function:
pub fn get(queue_id: &str) -> Option<&'static str> {
default_colors.iter()
.find(|pair| pair.0 == queue_id)
.map(|pair| pair.1)
}
Note that it returns Option, because queue_id can be custom (unmapped).
This can be used like so:
let color = queue_default_colors::get("amig"); // Some("HRED")
It is possible to optimize this if you change default_colors to a HashMap, but then you need to initialize it. See here for the options - https://stackoverflow.com/a/32956193/1009546
Related
I wish that enums in Rust can be used like Haskell's productive type. I want to
access a field's value directly
assign a field's value directly or make a clone with the changing value.
Directly means that not using too long pattern matching code, but just could access like let a_size = a.size.
In Haskell:
data TypeAB = A {size::Int, name::String} | B {size::Int, switch::Bool} deriving Show
main = do
let a = A 1 "abc"
let b = B 1 True
print (size a) -- could access a field's value directly
print (name a) -- could access a field's value directly
print (switch b) -- could access a field's value directly
let aa = a{size=2} -- could make a clone directly with the changing value
print aa
I tried two styles of Rust enum definition like
Style A:
#[derive(Debug)]
enum EntryType {
A(TypeA),
B(TypeB),
}
#[derive(Debug)]
struct TypeA {
size: u32,
name: String,
}
#[derive(Debug)]
struct TypeB {
size: u32,
switch: bool,
}
fn main() {
let mut ta = TypeA {
size: 3,
name: "TAB".to_string(),
};
println!("{:?}", &ta);
ta.size = 2;
ta.name = "TCD".to_string();
println!("{:?}", &ta);
let mut ea = EntryType::A(TypeA {
size: 1,
name: "abc".to_string(),
});
let mut eb = EntryType::B(TypeB {
size: 1,
switch: true,
});
let vec_ab = vec![&ea, &eb];
println!("{:?}", &ea);
println!("{:?}", &eb);
println!("{:?}", &vec_ab);
// Want to do like `ta.size = 2` for ea
// Want to do like `ta.name = "bcd".to_string()` for ea
// Want to do like `tb.switch = false` for eb
// ????
println!("{:?}", &ea);
println!("{:?}", &eb);
println!("{:?}", &vec_ab);
}
Style B:
#[derive(Debug)]
enum TypeCD {
TypeC { size: u32, name: String },
TypeD { size: u32, switch: bool },
}
fn main() {
// NOTE: Rust requires representative struct name before each constructor
// TODO: Check constructor name can be duplicated
let mut c = TypeCD::TypeC {
size: 1,
name: "abc".to_string(),
};
let mut d = TypeCD::TypeD {
size: 1,
switch: true,
};
let vec_cd = vec![&c, &d];
println!("{:?}", &c);
println!("{:?}", &d);
println!("{:?}", &vec_cd);
// Can't access a field's value like
// let c_size = c.size
let c_size = c.size; // [ERROR]: No field `size` on `TypeCD`
let c_name = c.name; // [ERROR]: No field `name` on `TypeCD`
let d_switch = d.switch; // [ERROR]: No field `switch` on `TypeCD`
// Can't change a field's value like
// c.size = 2;
// c.name = "cde".to_string();
// d.switch = false;
println!("{:?}", &c);
println!("{:?}", &d);
println!("{:?}", &vec_cd);
}
I couldn't access/assign values directly in any style. Do I have to implement functions or a trait just to access a field's value? Is there some way of deriving things to help this situation?
What about style C:
#[derive(Debug)]
enum Color {
Green { name: String },
Blue { switch: bool },
}
#[derive(Debug)]
struct Something {
size: u32,
color: Color,
}
fn main() {
let c = Something {
size: 1,
color: Color::Green {
name: "green".to_string(),
},
};
let d = Something {
size: 2,
color: Color::Blue { switch: true },
};
let vec_cd = vec![&c, &d];
println!("{:?}", &c);
println!("{:?}", &d);
println!("{:?}", &vec_cd);
let _ = c.size;
}
If all variant have something in common, why separate them?
Of course, I need to access not common field too.
This would imply that Rust should define what to do when the actual type at runtime doesn't contain the field you required. So, I don't think Rust would add this one day.
You could do it yourself. It will require some lines of code, but that matches the behavior of your Haskell code. However, I don't think this is the best thing to do. Haskell is Haskell, I think you should code in Rust and not try to code Haskell by using Rust. That a general rule, some feature of Rust come directly from Haskell, but what you want here is very odd in my opinion for Rust code.
#[derive(Debug)]
enum Something {
A { size: u32, name: String },
B { size: u32, switch: bool },
}
impl Something {
fn size(&self) -> u32 {
match self {
Something::A { size, .. } => *size,
Something::B { size, .. } => *size,
}
}
fn name(&self) -> &String {
match self {
Something::A { name, .. } => name,
Something::B { .. } => panic!("Something::B doesn't have name field"),
}
}
fn switch(&self) -> bool {
match self {
Something::A { .. } => panic!("Something::A doesn't have switch field"),
Something::B { switch, .. } => *switch,
}
}
fn new_size(&self, size: u32) -> Something {
match self {
Something::A { name, .. } => Something::A {
size,
name: name.clone(),
},
Something::B { switch, .. } => Something::B {
size,
switch: *switch,
},
}
}
// etc...
}
fn main() {
let a = Something::A {
size: 1,
name: "Rust is not haskell".to_string(),
};
println!("{:?}", a.size());
println!("{:?}", a.name());
let b = Something::B {
size: 1,
switch: true,
};
println!("{:?}", b.switch());
let aa = a.new_size(2);
println!("{:?}", aa);
}
I think there is currently no built-in way of accessing size directly on the enum type. Until then, enum_dispatch or a macro-based solution may help you.
I have a struct where I've derived a couple of things.
#[derive(PartialEq, Debug)]
struct Subscriber {
id: u16,
up_speed: u32,
down_speed: u32
}
However, when I try to use PartialEq, I get told it is not implemented.
for (id, subscriber) in &new_hashmap {
let original_subscriber = original_hashmap.get(id).unwrap();
if original_subscriber == None {
changed_hashmap.insert(subscriber.id, subscriber);
} else if subscriber != original_subscriber {
changed_hashmap.insert(subscriber.id, subscriber);
}
}
Here's the compiler error.
error[E0277]: can't compare `&Subscriber` with `Option<_>`
--> src/main.rs:34:32
|
34 | if original_subscriber == None {
| ^^ no implementation for `&Subscriber == Option<_>`
|
= help: the trait `PartialEq<Option<_>>` is not implemented for `&Subscriber`
= help: the trait `PartialEq` is implemented for `Subscriber`
If I rewrite it to not put original_subscriber into its own variable, then it works.
for (id, subscriber) in &new_hashmap {
if original_hashmap.get(id) == None {
changed_hashmap.insert(subscriber.id, subscriber);
} else if subscriber != original_hashmap.get(id).unwrap() {
changed_hashmap.insert(subscriber.id, subscriber);
}
}
The rest of the code is essentially doing the following.
Create HashMap of 2 Subscriber instances.
Create another HashMap of 3 Subscriber instances, 1 of which is new, 1 of which is the same, and 1 of which has the same key but an updated value.
That is original_hashmap HashMap and new_hashmap.
The goal is to get a third HashMap of items in new_hashmap that are new to original_hashmap or have changed values.
your code does not work for 2 reasons.
If you derive PartialEq it will only work for Subscriber == Subscriber checks. You need to implement PartialEq<Type>
You are using a reference when comparing. This means you need to implement PartialEq for &Subscriber and not subscriber
This should do the trick
#[derive(PartialEq, Debug)]
struct Subscriber {
id: u16,
up_speed: u32,
down_speed: u32,
}
let subscriber = Subscriber {
id: 1,
up_speed: 100,
down_speed: 100,
};
impl PartialEq<Option<Subscriber>> for &Subscriber {
fn eq(&self, other: &Option<Subscriber>) -> bool {
match other {
Some(other) => return other == *self,
None => return false,
}
}
}
if &subscriber == None {
println!("None");
} else {
println!("Some");
}
But I am not sure if this is really what you want. I will try to implement the same and edit my answer afterwards
I suppose that's what you want to implement
use std::collections::HashMap;
#[derive(Debug, PartialEq)]
struct Subscriber {
id: u16,
up_speed: u32,
down_speed: u32,
}
impl Subscriber {
fn new(id: u16, up_speed: u32, down_speed: u32) -> Subscriber {
Subscriber {
id,
up_speed,
down_speed,
}
}
}
fn main() {
let mut old_map = HashMap::new();
old_map.insert(1, Subscriber::new(1, 1, 1));
old_map.insert(2, Subscriber::new(2, 2, 2));
let mut new_map = HashMap::new();
new_map.insert(0, Subscriber::new(0, 0, 0)); //new
new_map.insert(1, Subscriber::new(1, 1, 1)); //Same
new_map.insert(2, Subscriber::new(3, 3, 3)); //Same key but different value
let mut changed_map = HashMap::new();
//
for (key, subscriber) in &new_map {
if old_map.contains_key(&key) {
if old_map[&key] != *subscriber {
changed_map.insert(key, subscriber);
}
} else {
changed_map.insert(key, subscriber);
}
}
println!("{:?}", changed_map);
}
It will return
{2: Subscriber { id: 3, up_speed: 3, down_speed: 3 }, 0: Subscriber { id: 0, up_speed: 0, down_speed: 0 }}
I used the deref operator to avoid impl PartialEq<Subscriber> for &Subscriber but you could have done that as well
I'm attempting to parse a simple Rust file that looks like:
use std::result::Result;
fn init() {
}
In my main function, I read the file to a string, parse it, and then create a token stream which I then pass to syn::parse2. This returns an unexpected token error and I'm not sure why.
fn main() {
if let Err(error) = try_main() {
let _ = writeln!(io::stderr(), "{}", error);
process::exit(1);
}
}
fn try_main() -> Result<(), Error> {
let filepath = PathBuf::from("./src/file-to-parse.rs");
let code = fs::read_to_string(&filepath).map_err(Error::ReadFile)?;
let syntax = syn::parse_file(&code).map_err({
|error| Error::ParseFile {
error,
filepath,
source_code: code,
}
})?;
let token_stream = syntax.to_token_stream();
let item: Result<Item, syn::Error> = syn::parse2(token_stream);
match item {
Ok(mut v) => {
println!("success!");
}
Err(error) => {
println!("{:?}", error.to_compile_error());
}
}
}
The full error it returns me is:
TokenStream [Ident { sym: compile_error, span: bytes(56..58) }, Punct { char: '!', spacing: Alone, span: bytes(56..58) }, Group { delimiter: Brace, stream: TokenStream [Literal { lit: "unexpected token", span: bytes(56..58) }], span: bytes(56..58) }]
What's even more confusing to me is that if I remove the import and keep the function, it parses fine. Also if I remove the function and keep the import it parses fine. It's only when I keep both of them that I get an error. Does this mean that it's an issue with the empty line?
The reason your program throws an error is because your input code has two items (use and fn) but you're attempting to parse the whole thing as a single Item with the syn::parse2 line. This also explains why it works if you remove either the use or the fn.
If you want all the top level items in the code, you can already get that from the File struct that syn::parse_file returns:
fn main() {
let code = "use std::result::Result;
fn init() {
}";
let file = syn::parse_file(&code).unwrap();
dbg!(file.items);
}
[src/main.rs:9] file.items = [
Use(
ItemUse {
attrs: [],
vis: Inherited,
use_token: Use,
leading_colon: None,
tree: Path(
UsePath {
ident: Ident {
sym: std,
span: bytes(5..8),
},
colon2_token: Colon2,
tree: Path(
UsePath {
ident: Ident {
sym: result,
span: bytes(10..16),
},
colon2_token: Colon2,
tree: Name(
UseName {
ident: Ident {
sym: Result,
span: bytes(18..24),
},
},
),
},
),
},
),
semi_token: Semi,
},
),
Fn(
ItemFn {
attrs: [],
vis: Inherited,
sig: Signature {
constness: None,
asyncness: None,
unsafety: None,
abi: None,
fn_token: Fn,
ident: Ident {
sym: init,
span: bytes(30..34),
},
generics: Generics {
lt_token: None,
params: [],
gt_token: None,
where_clause: None,
},
paren_token: Paren,
inputs: [],
variadic: None,
output: Default,
},
block: Block {
brace_token: Brace,
stmts: [],
},
},
),
]
Playground
I have a Companion trait that encompasses a base trait for Components such as Health. I store a list of Companion using trait objects because all companions must at least implement the Companion trait. However not all companions will use the subtype Health trait.
Now the heal command only accepts a list of Health traits, so I need to filter out, remap and downcast all the base Companion traits so that it supports the Health traits.
I understand this is bad design. How can I implement the same behavior without having to downcast the trait objects to a specific component? Note: I cannot have a large struct which includes all the subtypes into one type.
Here's the code I have so far:
type CompanionId = Uuid;
fn main() {
let mut companion_storage: HashMap<CompanionId, Box<dyn Companion>> = HashMap::new();
let companion_id: CompanionId = Uuid::new_v4();
companion_storage.insert(
companion_id,
Box::new(Cheetah {
...
}),
);
let mut player = Player {
...,
companions: Vec::new(),
};
player.companions.push(companion_id);
'GameLoop: loop {
let input = poll_input().trim().to_lowercase();
match input.as_str() {
// TODO: Extract healing component here.
"heal" => heal_command(companion_id, companion_storage.into_iter().filter(|(companion_id, companion)| {
// QUESTION: How do I filter out Companions without the Health trait here so they can automatically be downcasted and mapped?
}).collect()),
"q" => {
break 'GameLoop;
}
"s" => {
status_command(&player, &companion_storage); // SAME PROBLEM HERE
}
_ => println!("Unknown command"),
}
}
}
struct Player {
id: u8,
name: String,
companions: Vec<CompanionId>,
}
trait Companion {
...
}
trait Health: Companion {
...
}
trait Status: Health {}
struct Cheetah {
id: CompanionId,
name: String,
current_health: f32,
max_health: f32,
}
impl Companion for Cheetah {
...
}
impl Health for Cheetah {
...
}
fn heal_command(
companion_id: CompanionId,
companion_storage: &mut HashMap<CompanionId, Box<dyn Health>>,
) {
let companion = companion_storage.get_mut(&companion_id).unwrap();
companion.heal_max();
println!("Healed to max.");
}
fn status_command(player: &Player, companion_storage: &mut HashMap<CompanionId, Box<dyn Status>>) {
println!("Status for {}: ", player.name);
println!("===============================");
print!("Companions: ");
for companion_id in &player.companions {
let companion = companion_storage.get(companion_id).unwrap();
print!(
"{} [{}/{}], ",
companion.name(),
companion.health(),
companion.max_health()
);
}
println!();
println!("===============================");
}
Is this code a better alternative?
type CompanionId = Uuid;
fn main() {
let mut companion_storage: HashMap<CompanionId, Companion> = HashMap::new();
let companion_id: CompanionId = Uuid::new_v4();
companion_storage.insert(
companion_id,
Companion {
id: companion_id,
name: "Cheetah".to_string(),
health: Some(Box::new(RegularHealth {
current_health: 50.0,
max_health: 50.0,
})),
},
);
let mut player = Player {
id: 0,
name: "FyiaR".to_string(),
companions: Vec::new(),
};
player.companions.push(companion_id);
'GameLoop: loop {
let input = poll_input().trim().to_lowercase();
match input.as_str() {
// TODO: Extract healing component here.
"heal" => {
let companion = companion_storage.get_mut(&companion_id).unwrap();
match companion.health_mut() {
None => {
println!("The selected companion doesn't have health associated with it.");
}
Some(health) => {
heal_command(health);
println!("{} was healed to max.", companion.name);
}
}
}
"q" => {
break 'GameLoop;
}
"s" => {
status_command(&player, &companion_storage); // SAME PROBLEM HERE
}
_ => println!("Unknown command"),
}
}
}
struct Player {
id: u8,
name: String,
companions: Vec<CompanionId>,
}
struct Companion {
id: CompanionId,
name: String,
health: Option<Box<dyn Health>>,
}
struct RegularHealth {
current_health: f32,
max_health: f32,
}
trait Health {
...
}
impl Companion {
fn health_mut(&mut self) -> Option<&mut dyn Health> {
match self.health.as_mut() {
None => None,
Some(health) => Some(health.as_mut()),
}
}
fn health(&self) -> Option<&dyn Health> {
match self.health.as_ref() {
None => None,
Some(health) => Some(health.as_ref()),
}
}
}
impl Health for RegularHealth {
...
}
fn heal_command(health: &mut dyn Health) {
health.heal_max();
}
fn status_command(player: &Player, companion_storage: &HashMap<CompanionId, Companion>) {
println!("Status for {}: ", player.name);
println!("===============================");
print!("Companions: ");
for companion_id in &player.companions {
let companion = companion_storage.get(companion_id).unwrap();
match companion.health.as_ref() {
None => {}
Some(health) => {
print!(
"{} [{}/{}], ",
companion.name,
health.health(),
health.max_health()
);
}
}
}
println!();
println!("===============================");
}
I'm learning Rust for a few days and honestly some concepts are really difficult to understand and apply. I started to rewrite a small part of a component in order to compare the legendary speed of Rust and learn by a concrete project. It's a component to measure time and monitor the program during the execution. It will be a dynamic library used by another program.
My question :
1) How to create an Option<Box<T>> from &mut self ? (fn add_son)
extern crate winapi;
extern crate user32;
extern crate kernel32;
struct KpiMethod{
element : String,
line : u32,
nb_occ : u32,
counter_start : i64,
counter_end : i64,
total_time: i64,
kpi_fils : Vec<KpiMethod>,
kpi_father : Option<Box<KpiMethod>>
}
impl KpiMethod {
pub fn new(_element: String, _line: u32, _father: Option<Box<KpiMethod>>) -> KpiMethod {
KpiMethod{
element : _element,
line : _line,
nb_occ : 1,
counter_start : get_counter(),
counter_end : 0,
total_time: 0,
kpi_fils : Vec::new(),
kpi_father : _father
}
}
pub fn add_son(&mut self, _element: String, _line: u32) -> KpiMethod{
//How create a Option<Box<KpiMethod>> of an existing KpiMethod (self) ?
let mut kpimet = KpiMethod::new(_element, _line, Some(Box::new(self)));
//Do I need a mutable self to push ?
self.kpi_fils.push(kpimet);
kpimet
}
pub fn find_son(&mut self, _element: String, _line: u32) -> Option<&KpiMethod> {
//which is the good and speed method to find a son with key (element,line) ?
for elem in self.kpi_fils.iter_mut() {
if elem.element == _element && elem.line == _line {
//why do I put a return here to fix error ?
return Some(elem)
}
}
None
}
}
pub struct KpiAgent{
kpi_Method : Vec<KpiMethod>,
current_Method : Option<Box<KpiMethod>>,
counter_start : i64,
counter_end : i64,
date_start : String,
date_end : String,
auto_consommation : u64,
}
impl KpiAgent {
pub fn new() -> KpiAgent {
KpiAgent{
kpi_Method: Vec::new(),
current_Method: None,
counter_start: 0,
counter_end: 0,
date_start: String::from(""),
date_end: String::from(""),
auto_consommation: 0
}
}
pub fn method_start(&mut self, element: String, line: u32){
match self.current_Method {
None => {
self.current_Method = Some(Box::new(KpiMethod::new(element, line, None)));
if self.counter_start == 0 {
self.counter_start = get_counter();
}
},
Some(method) => {
let metfils = method.find_son(element, line);
match metfils {
None => {
self.current_Method = Some(Box::new(method.add_son(element, line)));
},
Some(son) => {
son.nb_occ += 1;
son.counter_start = get_counter();
}
}
},
}
}
pub fn method_end(&mut self, element: String, line: u32){
match self.current_Method{
Some(met) => {
met.counter_end = get_counter();
self.counter_end = met.counter_end;
met.total_time += met.counter_end - met.counter_start;
self.current_Method = met.kpi_father;
}
}
}
}
pub fn get_counter() -> i64 {
let mut counter: i64 = 0;
unsafe{
kernel32::QueryPerformanceCounter(&mut counter);
}
counter
}
pub fn main() {
let mut met = KpiMethod::new("1c".to_string(), 1, None);
met.add_son("2c".to_string(),2);
met.add_son("3c".to_string(),3);
met.add_son("4c".to_string(),4);
let _toto = met.find_son("3c".to_string(),3);
match _toto{
None => println!("Not found"),
Some(x) => println!("{}",x.element),
}
let mut agent = KpiAgent::new();
agent.method_start("test".to_string(),2);
agent.method_end("test".to_string(),10);
}