-
Notifications
You must be signed in to change notification settings - Fork 314
Issue287: create random password from a set of allowed characters #372
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
src/basics.md
Outdated
|
|
||
| [![rand-badge]][rand] [![cat-text-processing-badge]][cat-text-processing] | ||
|
|
||
| Randomly generates a string of given length ASCII characters in the range `A-Z, a-z, 0-9`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you give more details, such as gen_ascii_chars is the method which a hardcoded range of character.
Plus, I would show the choose method which is a user defined set of allowed characters. Maybe wait for the green flag of @budziq for this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed on both arguments:
- lets add links to key identifiers in the description.
- I'd suggest to add two snippets here the second one being an iterator based in
chooselike the one used to implementgen_ascii_charsbut taking arbitrary bytestring in the constructor, then used in identical fashion as the first trivial snippet. That would be very cool!
budziq
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
few suggestions
src/basics.md
Outdated
| | [Generate random numbers within a range][ex-rand-range] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | | ||
| | [Generate random numbers with given distribution][ex-rand-dist] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | | ||
| | [Generate random values of a custom type][ex-rand-custom] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | | ||
| | [Create random passwords from a set of allowed characters][ex-rand-passwd] | [![rand-badge]][rand] | [![cat-text-processing-badge]][cat-text-processing] | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd remove the "text-processing" category. We are not really doing any processing of input text.
src/basics.md
Outdated
| use rand::{thread_rng, Rng}; | ||
|
|
||
| fn main() { | ||
| let s: String = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets run rustfmt on the snippet
src/basics.md
Outdated
|
|
||
| [![rand-badge]][rand] [![cat-text-processing-badge]][cat-text-processing] | ||
|
|
||
| Randomly generates a string of given length ASCII characters in the range `A-Z, a-z, 0-9`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed on both arguments:
- lets add links to key identifiers in the description.
- I'd suggest to add two snippets here the second one being an iterator based in
chooselike the one used to implementgen_ascii_charsbut taking arbitrary bytestring in the constructor, then used in identical fashion as the first trivial snippet. That would be very cool!
|
r? @budziq @ludwigpacifici I added an example with |
budziq
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @anna-liao ! few suggestions below:
- I would split this example into two separate code snippets.
src/basics.md
Outdated
| [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html | ||
| [`BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html | ||
| [`chain_err`]: https://docs.rs/error-chain/*/error_chain/index.html#chaining-errors | ||
| [`choose`]: https://docs.rs/rand/0.3.18/rand/trait.Rng.html#method.choose |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets use wildcard version numbers
src/basics.md
Outdated
| [`File::try_clone`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.try_clone | ||
| [`File`]: https://doc.rust-lang.org/std/fs/struct.File.html | ||
| [`foreign_links`]: https://docs.rs/error-chain/*/error_chain/#foreign-links | ||
| [`gen_ascii_chars`]: https://docs.rs/rand/0.3.18/rand/trait.Rng.html#method.gen_ascii_chars |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets use wildcard version numbers
src/basics.md
Outdated
| let s: String = thread_rng().gen_ascii_chars().take(30).collect(); | ||
| println!("{}", s); | ||
|
|
||
| let alphanum_bytestring = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest implementing an iterator type like the AsciiGenerator instead that would take an rng in a constructor and for added merrit a "charset" (a hardcoded bytestr for our purposes without anych dynamic generation with ranges and chain) as an argument.
Then it would be used almost identically as the gen_ascii_chars
src/basics.md
Outdated
|
|
||
| let mut rand_bytevec: Vec<u8> = Vec::new(); | ||
|
|
||
| for _ in 0..30 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the iterator approach would be used, pretty much all of this code would be not needed.
src/basics.md
Outdated
| | [Generate random numbers within a range][ex-rand-range] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | | ||
| | [Generate random numbers with given distribution][ex-rand-dist] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | | ||
| | [Generate random values of a custom type][ex-rand-custom] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | | ||
| | [Create random passwords from a set of allowed characters][ex-rand-passwd] | [![rand-badge]][rand] | | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there should be a category here
src/intro.md
Outdated
| | [Generate random numbers within a range][ex-rand-range] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | | ||
| | [Generate random numbers with given distribution][ex-rand-dist] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | | ||
| | [Generate random values of a custom type][ex-rand-custom] | [![rand-badge]][rand] | [![cat-science-badge]][cat-science] | | ||
| | [Create random passwords from a set of allowed characters][ex-rand-passwd] | [![rand-badge]][rand] | | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there should be a category here
src/basics.md
Outdated
| String::from_utf8((b'a'..b'z') | ||
| .chain(b'A'..b'Z') | ||
| .chain(b'0'..b'9') | ||
| //.chain([b'!', b'?', b'%']) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does not work because ranges give you u8 while iterating over slice gives you &u8 so the solution (if we wanted to go with this approach and we do not ;)) would be to clone the iterator contents.
.chain([b'!', b'?', b'%'].iter().cloned()) or even better .chain(b"!?%".iter().cloned()).
On the other hand I would suggest to just go with bytestring literal
const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz\
0123456789)(*&^%$#@!~";
|
@budziq Thanks for the review. I revised the PR based on your suggestions. With the |
budziq
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@anna-liao few suggestions below :)
src/basics.md
Outdated
| use rand::{thread_rng, Rng}; | ||
|
|
||
| fn main() { | ||
| let s: String = thread_rng().gen_ascii_chars().take(30).collect(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets change the variable name to a more descriptive one.
src/basics.md
Outdated
| let mut s = String::new(); | ||
|
|
||
| for _ in 0..30 { | ||
| s.push(*thread_rng().choose(CHARSET).unwrap() as char); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of for loop you can use a relatively simpler functional appproach without a need for manual string append. Also obtaining a thread_rng might be relatively costly so lets reuse one instance througth the generation process.
let mut rng = thread_rng();
let password: String = (0..30)
.map(|_| *rng.choose(CHARSET).unwrap() as char)
.collect();This version might be more readable and concise than separate type approach with CustomGenerator so I'll leave it up to you to chose one.
src/basics.md
Outdated
| } | ||
| } | ||
|
|
||
| fn gen_rand_chars<'a>(&'a mut self) -> CustomGenerator<'a, Self> where Self: Sized { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess that you are trying to emulate the gen_ascii_chars method here but it is not possible to extend the Rng in such way. All we can do is prepare a standard constructor that will take an rng and a charset.
Some along the lines of
impl<'a, R> CustomGenerator<'a, R> {
fn new(rng: R, charset: &'a [u8]) -> Result<Self> {
if charset.len() > 0 {
Some(CustomGenerator {
rng: rng,
charset: charset,
})
} else {
Err(ErrorKind::InvalidCharset.into())
}
}
}
src/basics.md
Outdated
| use rand::{thread_rng, Rng}; | ||
|
|
||
| struct CustomGenerator<'a, R:'a> { | ||
| rng: &'a mut R, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd probably go with owing the rng to make the lifetimes simpler. But I'll leave it up to you :)
We might go with having a refference to some outsude charset
|
@budziq Thanks for the help! I have learned more about idiomatic Rust syntax. I decided to stick with the non-generator case for user-specified charset. I couldn't get the generator case working. I think the generator case would be good as an additional example? |
budziq
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor suggestions in a review
I couldn't get the generator case working.
No problem it is a bit verbose anyway
src/basics.md
Outdated
|
|
||
| let mut rng = thread_rng(); | ||
| let password: String = (0..30) | ||
| .map(|_| *rng.choose(CHARSET).unwrap() as char) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we generally avoid unwrap in the examples, we should either document why the unwrap will be always ok as long as the CHARSET is nonempty or provide a generalized solution like:
let password: Option<String> = (0..30)
.map(|_| Some(*rng.choose(CHARSET)? as char))
.collect();
println!("{:?}", password);There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@budziq Thanks for showing me how to implement the generator case! I have updated the PR as suggested to remove the unwrap() and print an Option instead.
fixes #287 r? @budziq
I categorized this example under
text processing. Do you think that is the appropriate category?