Systems in Rust
/dev/random, reflect this:Note
A byte is a hardware idea - an ordered collection of 8 bits, which themselves are hardware units either containing, or lacking, some electrical charge. We view them as storing zeros or ones.
+ or - but that perform operations on pairs of bits rather than pairs of numeric values.std in a few places, though there is no formal byte type.u8 is used.
bytes and the data structure Bytes
u8 values.as_bytes, an array of u8 is often used (expressed as [u8]).u8s./dev/random and taking a peek.b format code, to see the individual zeroes and ones of a byte or bytes.:b
$ cargo run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/scratch`
1000111011010011001001000110100010011010101101010111100001010101
$ cargo run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/scratch`
1010101000100001011000111011111111011110010001010010101000111010
$ cargo run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/scratch`
1001110000001001110011100111110010010101110000010111010111110011u8s, just for simplicity.let mut devrnd = std::fs::File::open("/dev/urandom").unwrap();
let mut buffer = [0u8; 2];
std::io::Read::read_exact(&mut devrnd, &mut buffer).unwrap();
let x = buffer[0];
let y = buffer[1];
println!("x = {x:08b}, y = {y:08b}");:b doesn’t render leading zeros, which is fine for numbers but not great for bytes.:08b - where 0 specifies to have leading zeros, and 8 specifies how many digits.$ cargo run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/scratch`
x = 00101010, y = 01100111| Operator | Example | Explanation |
|---|---|---|
! |
!expr |
Bitwise or logical complement |
& |
expr & expr |
Bitwise AND |
<< |
expr << expr |
Left-shift |
>> |
expr >> expr |
Right-shift |
^ |
expr ^ expr |
Bitwise exclusive OR |
| |
expr | expr |
Bitwise OR |
bin or :bx = 00001111, y = 00110011!=# Print a truth table in markdown
print("| x | y | x!=y| x^y |")
print("|-----|-----|-----|-----|")
for left in (True, False):
for rite in (True, False):
print('|{:<5}|{:<5}|{:<5}|{:<5}|'.format(*[str(b) for b in [left, rite, left != rite, left ^ rite]]))from operator import and_, or_ , xor
for op in [and_, or_ , xor]:
print('f({:08b}, {:08b}) = {:08b} for f ='.format(x, y, op(x,y)), op)not is similar but unary.! for not (vs. ~)src/main.rs
fn main() {
let mut devrnd = std::fs::File::open("/dev/urandom").unwrap();
let mut buffer = [0u8; 2];
std::io::Read::read_exact(&mut devrnd, &mut buffer).unwrap();
let x = buffer[0];
let y = buffer[1];
let mut z = x | y;
println!("x = {x:08b}, y = {y:08b}, x | y = {z:08b}");
z = x ^ y;
println!("x = {x:08b}, y = {y:08b}, x ^ y = {z:08b}");
z = x & y;
println!("x = {x:08b}, y = {y:08b}, x & y = {z:08b}");
let y = !buffer[0];
println!("x = {x:08b},!x = {y:08b}");
}$ cargo run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/scratch`
x = 01110000, y = 10001110, x | y = 11111110
x = 01110000, y = 10001110, x ^ y = 11111110
x = 01110000, y = 10001110, x & y = 00000000
x = 01110000,!x = 10001111
$ cargo run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/scratch`
x = 10111111, y = 00110110, x | y = 10111111
x = 10111111, y = 00110110, x ^ y = 10001001
x = 10111111, y = 00110110, x & y = 00110110
x = 10111111,!x = 010000001)0)arr[0] of something before the arr[1] of something.0x1234 followers on Instagram📷stdin and read_line to read in some values.src/main.rs
cargo run -> type some nonsense -> press ENTER$ cargo run
Compiling scratch v0.1.0 (/home/user/tmp/scratch)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.23s
Running `target/debug/scratch`
0x1234
0x
12
34
$ cargo run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/scratch`
0x123
0x
12
3next() to an iterator to read characters..next(), we get an option.
.next() element.fn last(mut cs:std::str::Chars) -> Option<char> {
return match cs.next() {
Some(n) => match last(cs) { // if there's digits here, look for more
Some(m) => Some(m), // if the last is found, return it
None => Some(n), // no more letters - we are last, return n
},
None => None, // required by `rustc` in case we don't input anything
}
}$ cargo run
Compiling scratch v0.1.0 (/home/user/tmp/scratch)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.22s
Running `target/debug/scratch`
0x1234
Some('\n')Some('\n') to Nonefn last(mut cs:std::str::Chars) -> Option<char> {
return match cs.next() {
Some(n) => match last(cs) { // if there's digits here, look for more
Some(m) => {
println!("{n}{m}"); // If last is found, print this then last
Some(m), // if the last is found, return it
None => Some(n), // no more letters - we are last, return n
},
None => None, // required by `rustc` in case we don't input anything
}
}$ cargo run
Compiling scratch v0.1.0 (/home/user/tmp/scratch)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.23s
Running `target/debug/scratch`
0x1234
34
24
14
Some('4')mainNone after printing a pair.last to pairsmain
if let - kind of a single pattern match.src/main.rs
fn pairs(mut cs:std::str::Chars) -> Option<char> {
return match cs.next() {
Some('\n') => None,
Some(n) => match pairs(cs) {
Some(m) => {
println!("{n}{m}");
None
}
None => Some(n),
},
None => None,
}
}
fn main() {
let mut guess = String::new();
std::io::stdin().read_line(&mut guess).unwrap();
let mut cs = guess.chars();
cs.next();
cs.next();
if let Some(n) = pairs(cs) {
println!("{n}");
}
}{n}{m}from_str_radix for e.g. u8.
'1' => 1 instead)<class 'list'> I can’t tell the difference.Strings with String::new()Vec::new() or the macro vec!. Read morepairs to a helper function.pairs but add an argument.fn chars_to_vec(mut cs:std::str::Chars) -> Vec<u8> {
let mut vals = Vec::new();
// from old main
cs.next();
cs.next();
if let Some(n) = pairs(cs, &mut vals) {
vals.push(two_hex('0', n));
}
// "Prints and returns the value of a given
// expression for quick and dirty debugging."
dbg!(&vals);
return vals;
}dbg! “borrow” the vector to print it.fn pairs(mut cs:std::str::Chars, vals:&mut Vec<u8>) -> Option<char> {
return match cs.next() {
Some('\n') => None,
Some(n) => match pairs(cs, vals) {
Some(m) => {
vals.push(two_hex(n,m)); // only change
None
},
None => Some(n),
},
None => None,
}
}u8s into it.0..4) as the addresses in computer memory.A big-endian system stores the most significant byte (MSB) of a word at the smallest memory address and the least significant byte (LSB) at the largest.
A little-endian system, in contrast, stores the least-significant byte (LSB) at the smallest address.
0x01020304, the MSB is 1, and LSB is 4[4, 3, 2, 1], the smallest memory address contains a 4.main$ cargo r
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/scratch`
0x01020304
[src/main.rs:10:5] &vals = [
4,
3,
2,
1,
]
[src/main.rs:38:9] (i, vals[i]) = (
0,
4,
)
[src/main.rs:38:9] (i, vals[i]) = (
1,
3,
)
[src/main.rs:38:9] (i, vals[i]) = (
2,
2,
)
[src/main.rs:38:9] (i, vals[i]) = (
3,
1,
)
1020304<< (well, left shift)fn custom_u8s_to_u32(vals : Vec<u8>) -> u32 {
// We'll just take the first four for now
let mut ret : u32 = 0;
for i in 0..4 {
dbg!((i, vals[i]));
ret += (vals[i] as u32) << (8 * i);
}
return ret;
}as u32!