Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 months ago.
Improve this question
I need to document a piece of code that is 3-fold. I have an enum element, an associated constructor and a method that uses the enum to do work. Here is a minimal example:
use regex::{Error, Regex};
pub enum Element {
And {
lhs: Box<Element>,
rhs: Box<Element>,
},
Value {
regex: Regex,
},
}
impl Element {
pub fn new_and(lhs: Element, rhs: Element) -> Self {
Element::And {
lhs: Box::new(lhs),
rhs: Box::new(rhs),
}
}
pub fn new_value(regex: &str) -> Result<Self, Error> {
let regex = Regex::new(regex)?;
Ok(Element::Value { regex })
}
pub fn is_match(&self, values: &Vec<String>) -> bool {
match self {
Element::And { lhs, rhs } => lhs.is_match(values) && rhs.is_match(values),
Element::Value { regex } => {
for value in values {
if regex.is_match(value) {
return true;
}
}
false
}
}
}
}
fn main() {}
There definitely needs to be a comment on new_value() to document the possible error. But where should I put information on how the actual element is evaluated?
Put this also in the comment of new_value() to have all in one place?
Put it in a comment for Element::Value and is_match() only says that elements are
evaluated as documented there?
Put all evaluation information for all enum values in the comment for is_match() and leave Element::Value empty?
Repeat the evaluation information in all 3 locations?
Disclaimer: A lot of this will come down to personal preference and taste, there's not really any hard and fast rules
That being said, I like to look at the standard library's documentation for inspiration.
Generally, if a function returns a Result, some explanation of when it returns an error is probably a good idea. For example: Returns an error if the regex fails to parse. You could also look at the docs for Regex::new to see what they say about it.
When documenting the behaviour of is_match, you should probably put the comment on is_match.
But I'd also suggest putting a more comprehensive comment (preferably with a usage example) either in the module (with //! at the top) or on pub enum Element. Examples are really underrated IMO, and even a simple one can really help a reader to understand the purpose of this type.
For example, the docs for String (https://doc.rust-lang.org/std/string/struct.String.html) have quite a lot of detail on various uses of String as doc comments on the String struct itself.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 14 hours ago.
Improve this question
I have this class:
#[derive(MyDerive)]
pub struct Streamers {
#[pk]
pub login: String,
pub display_name: Option<String>,
pub watched: Option<bool>,
}
and in that derive I have a method that looks something like this (inside an impl block in a trait):
quote::quote! {
fn get_pk_value(&self) -> #pk_ty {
self.#pk_ident.clone()
}
}
the #pk_ident is just 'login' and #pk_ty 'String'
the macro should just expand to this:
fn get_pk_value(&self) -> String {
self.login.clone()
}
and it does, at least in my cargo expand output, so why does the build fail?
When I type that code just normally it works but the build fails with this message:
error[E0507]: cannot move out of self.login which is behind a shared
reference
move occurs because self.login has type String, which does not
implement the Copy trait
shouldn't the clone remove that problem?
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 months ago.
Improve this question
Is there an elegant way to save a variable/s so that a state is reflected between executions. I think reading and updating a config file (yaml) is a pretty good solution but for just a couple of variables it seems a bit of a hastle. Any thoughts?
I think you misuse term runtimes, I think what you mean is executions. But I think I get what you are trying to ask. This is not Rust-specific. Executables in general are stateless, they do not store any information between executions.
So if you want to persist state between executions, you need to store it somewhere. The options are many. The most common ones are files or databases.
If it's really just a couple of variables the easiest way would probably be json via the awesome serde_json library. With it, you can convert normal Rust structs into human readable ASCII text and store it in file.
You could even wrap it in a struct that can load/store the state.
Although you have to be careful with concurrent access then.
Here is a somewhat simple example of a struct that can persists its state in a file:
use serde::{Deserialize, Serialize};
use std::{fs::File, io::BufReader, path::Path};
const STATE_FILENAME: &'static str = "state.json";
#[derive(Serialize, Deserialize)]
struct PersistentState {
counter: u32,
}
impl PersistentState {
fn load() -> Self {
let path = Path::new(STATE_FILENAME);
if path.exists() && path.is_file() {
let file = File::open(path).unwrap();
serde_json::from_reader(BufReader::new(file)).unwrap()
} else {
Self::default()
}
}
fn store(&self) {
let file = File::create(STATE_FILENAME).unwrap();
serde_json::to_writer(file, self).unwrap();
}
}
impl Default for PersistentState {
fn default() -> Self {
Self { counter: 0 }
}
}
fn main() {
let mut state = PersistentState::load();
state.counter += 1;
println!("Counter: {}", state.counter);
state.store();
}
First execution:
Counter: 1
Second execution:
Counter: 2
state.json file:
{"counter":2}
Of course don't just copy-paste the code into your project but instead think about your usecase and adapt it to your needs.
Pitfalls
Not all types are losslessly storable in json. Most are, like strings, integers and booleans, but floats are not. Floats are stored in human readable decimal, but handled in binary, and there is always a small rounding error in the conversion. But unless you are doing scientific calculations, that is most likely irrelevant.
If you don't like json, serde supports a bunch of other types as well.
This question already has answers here:
How to filter a vector of custom structs?
(1 answer)
How do I conditionally check if an enum is one variant or another?
(2 answers)
Closed 2 years ago.
I can filter the active classes as follows, but how can I achieve bringing all the classes where their status is not Online? Status for not active can be Cancelled, Deferred, or Optional.
pub enum Status {
Online,
Cancelled,
Deferred,
Optional,
}
pub struct CustomFilter {
pub status: Option<Status>,
}
fn example() {
let mut custom_filter = CustomFilter::default();
custom_filter.status = Some(Status::Online);
let online_classes = self.get_classes_with_filter(custom_filter).await?;
// where Status -> Cancelled, Deferred, Optional
let non_active_classes = todo!("??");
}
How about something along the lines of:
let foo: Vec<_> = whatever;
let active_classes: Vec<_> = foo.iter().filter(|x| x.status == Status::Active).collect();
let non_active_classes: Vec<_> = foo.iter().filter(|x| x.status != Status::Active).collect();
Not sure if this is what you intended.
If your question is "Can I store !Active or Cancelled | Deferred | Optional in an Status?" then the answer is no. Maybe if your enum worked like bitflags but that doesn't appear to be the case here.
You'd have to store them individually in a Vec or something more complicated like:
enum StatusFilter {
Include(Vec<Status>),
Exclude(Vec<Status>),
}
pub struct CustomFilter {
pub status: StatusFilter,
}
custom_filter.status = StatusFilter::Exclude(vec![Status::Active]);
I'd recommend not doing this and use functor-based filtering like #Luke has suggested if at all possible. Its much more straightforward, more flexible to use and implement, and it follows conventions in the standard library.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I'm using crossbeam-epoch to write a lock-free data structure in rust. crossbeam-epoch uses a guard to load the heap-allocated atomic pointer. One example of the data structure's interface is:
fn get(&self, index: IndexType, guard: &'guard Guard) -> Option<&'guard Value>
This method requires a guard which has the same lifetime with the returned value's reference.
Now, I want to wrap this method without providing a Guard. For example:
struct ReturnType<'guard, Value> {
guard: Guard,
value: Option<&'guard Value>
}
impl<'guard, Value> MyDataStructure<Value> {
fn my_get(&self, index: IndexType) -> ReturnType<'guard, Value> {
let guard = pin();
let value = self.get(index, &guard);
ReturnType {
guard: guard,
value: value
}
}
}
But the compiler won't allow me to do this.
My question is how to implement the method my_get?
This question needs some improvement. You should always add a minimal reproducable example and you haven't shown what the compiler error was either.
Anyways, in your code, you just forget to specify what the lifetime should be linked to. If the guard at least lives as long as self, then you should declare your method with:
fn my_get<'guard>(&'guard self, index: IndexType) -> ReturnType<'guard, Value> {
&'guard self tells the compiler to link 'guard to self.
If the guard should live longer than the struct then you have to move the Value or if you want to share the reference use Arc<Value> (Documentation)
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I am still pretty new to Rust and I have this function:
Edit: Here is a newer version of the function with the same issue as far as I can tell
pub fn new_from_file_path(path: &str) -> Parser {
let path_buf: PathBuf = PathBuf::from(path);
let absolute_path: PathBuf = std::fs::canonicalize(path_buf).unwrap();
let data: String = std::fs::read_to_string(absolute_path).unwrap();
let clone = data.clone();
let s_slice: &str = &clone[..];
return Parser::new_from_string_data(s_slice);
}
Here is the implementation of the new_from_string_data() function
pub fn new_from_string_data(data: &str) -> Parser {
let parser = Parser::new(data.chars());
return parser;
}
This is the struct definition for parser :
pub struct Parser<'a> {
tokenizer: Tokenizer<'a>,
}
Here is a screenshot of the error message I am getting
Any help would be greatly appreciated, please also let me know if more information is needed.
new_from_string_data function returns a Parser with the same lifetime as it's input argument data.
In the case of new_from_file_path, data is s_slice which is a slice of the string clone owned by the function new_from_file_path. Hence the returned Parser would reference clone which is destroyed when returning from the function new_from_file_path
str::chars() returns an iterator struct that requires an explicit lifetime as it (presumably, I haven't read the full struct definition myself) references the data passed to chars() (pub struct Chars<'a> { /* fields omitted */ }), just like your Parser struct, and you are generating the referenced variable(s) inside of new_from_file_path in the statement let clone = data.clone();.
I'd suggest simply adding a lifetime annotation to the function header so it reads as follows:
pub fn new_from_file_path<'a>(path: &'a str) -> Parser<'a> {...}
This wont complicate calling the function and tells the compiler that the returned Parser struct and its refrences should have the same lifetime as the data passed to the function.