From 67cdcc2e12118becb823e20a40cc2687f2b8425a Mon Sep 17 00:00:00 2001 From: Adam Carpenter <53hornet@gmail.com> Date: Wed, 27 Mar 2019 15:32:37 -0400 Subject: Started Rust in Action MEAP. --- meap/meap-code/ch5/ch5-cpu1/Cargo.lock | 4 + meap/meap-code/ch5/ch5-cpu1/Cargo.toml | 6 + meap/meap-code/ch5/ch5-cpu1/src/main.rs | 60 ++++++++++ meap/meap-code/ch5/ch5-cpu2/Cargo.lock | 4 + meap/meap-code/ch5/ch5-cpu2/Cargo.toml | 6 + meap/meap-code/ch5/ch5-cpu2/src/main.rs | 60 ++++++++++ meap/meap-code/ch5/ch5-cpu3/Cargo.lock | 4 + meap/meap-code/ch5/ch5-cpu3/Cargo.toml | 6 + meap/meap-code/ch5/ch5-cpu3/src/main.rs | 88 ++++++++++++++ meap/meap-code/ch5/ch5-f32-as-u32.rs | 8 ++ meap/meap-code/ch5/ch5-fixed-width.rs | 34 ++++++ meap/meap-code/ch5/ch5-genfib/Cargo.lock | 102 +++++++++++++++++ meap/meap-code/ch5/ch5-genfib/Cargo.toml | 7 ++ meap/meap-code/ch5/ch5-genfib/src/main.rs | 17 +++ meap/meap-code/ch5/ch5-impossible-add.rs | 5 + meap/meap-code/ch5/ch5-message-store/Cargo.lock | 4 + meap/meap-code/ch5/ch5-message-store/Cargo.toml | 6 + meap/meap-code/ch5/ch5-message-store/src/main.rs | 93 +++++++++++++++ meap/meap-code/ch5/ch5-q/Cargo.lock | 127 +++++++++++++++++++++ meap/meap-code/ch5/ch5-q/Cargo.toml | 7 ++ meap/meap-code/ch5/ch5-q/src/lib.rs | 76 ++++++++++++ .../ch5/ch5-sat-messaging/msg-with-refs/Cargo.lock | 4 + .../ch5/ch5-sat-messaging/msg-with-refs/Cargo.toml | 6 + .../ch5-sat-messaging/msg-with-refs/src/main.rs | 51 +++++++++ meap/meap-code/ch5/ch5-to-oblivion.rs | 11 ++ meap/meap-code/ch5/ch5-u8-to-mock-rand.rs | 17 +++ meap/meap-code/ch5/ch5-visualising-f32.rs | 44 +++++++ 27 files changed, 857 insertions(+) create mode 100644 meap/meap-code/ch5/ch5-cpu1/Cargo.lock create mode 100644 meap/meap-code/ch5/ch5-cpu1/Cargo.toml create mode 100644 meap/meap-code/ch5/ch5-cpu1/src/main.rs create mode 100644 meap/meap-code/ch5/ch5-cpu2/Cargo.lock create mode 100644 meap/meap-code/ch5/ch5-cpu2/Cargo.toml create mode 100644 meap/meap-code/ch5/ch5-cpu2/src/main.rs create mode 100644 meap/meap-code/ch5/ch5-cpu3/Cargo.lock create mode 100644 meap/meap-code/ch5/ch5-cpu3/Cargo.toml create mode 100644 meap/meap-code/ch5/ch5-cpu3/src/main.rs create mode 100644 meap/meap-code/ch5/ch5-f32-as-u32.rs create mode 100644 meap/meap-code/ch5/ch5-fixed-width.rs create mode 100644 meap/meap-code/ch5/ch5-genfib/Cargo.lock create mode 100644 meap/meap-code/ch5/ch5-genfib/Cargo.toml create mode 100644 meap/meap-code/ch5/ch5-genfib/src/main.rs create mode 100644 meap/meap-code/ch5/ch5-impossible-add.rs create mode 100644 meap/meap-code/ch5/ch5-message-store/Cargo.lock create mode 100644 meap/meap-code/ch5/ch5-message-store/Cargo.toml create mode 100644 meap/meap-code/ch5/ch5-message-store/src/main.rs create mode 100644 meap/meap-code/ch5/ch5-q/Cargo.lock create mode 100644 meap/meap-code/ch5/ch5-q/Cargo.toml create mode 100644 meap/meap-code/ch5/ch5-q/src/lib.rs create mode 100644 meap/meap-code/ch5/ch5-sat-messaging/msg-with-refs/Cargo.lock create mode 100644 meap/meap-code/ch5/ch5-sat-messaging/msg-with-refs/Cargo.toml create mode 100644 meap/meap-code/ch5/ch5-sat-messaging/msg-with-refs/src/main.rs create mode 100644 meap/meap-code/ch5/ch5-to-oblivion.rs create mode 100644 meap/meap-code/ch5/ch5-u8-to-mock-rand.rs create mode 100644 meap/meap-code/ch5/ch5-visualising-f32.rs (limited to 'meap/meap-code/ch5') diff --git a/meap/meap-code/ch5/ch5-cpu1/Cargo.lock b/meap/meap-code/ch5/ch5-cpu1/Cargo.lock new file mode 100644 index 0000000..2baaa64 --- /dev/null +++ b/meap/meap-code/ch5/ch5-cpu1/Cargo.lock @@ -0,0 +1,4 @@ +[[package]] +name = "ch5-cpu1" +version = "0.1.0" + diff --git a/meap/meap-code/ch5/ch5-cpu1/Cargo.toml b/meap/meap-code/ch5/ch5-cpu1/Cargo.toml new file mode 100644 index 0000000..060a235 --- /dev/null +++ b/meap/meap-code/ch5/ch5-cpu1/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "ch5-cpu1" +version = "0.1.0" +authors = ["Tim McNamara "] + +[dependencies] diff --git a/meap/meap-code/ch5/ch5-cpu1/src/main.rs b/meap/meap-code/ch5/ch5-cpu1/src/main.rs new file mode 100644 index 0000000..c934c13 --- /dev/null +++ b/meap/meap-code/ch5/ch5-cpu1/src/main.rs @@ -0,0 +1,60 @@ +const ARITHMETIC_AND_LOGIC: u8 = 0x8; +const HALT: u8 = 0x0; // <1> +const ADD_XY: u8 = 0x4; + +struct CPU { + // current_operation: u16, // <2> + registers: [u8; 16], // <3> + position_in_memory: usize, // <4> + memory: [u8; 4096], // <5> +} + +impl CPU { + fn run(&mut self) { + loop { + let op_byte1 = self.memory[self.position_in_memory] as u16; // <6> + let op_byte2 = self.memory[self.position_in_memory + 1] as u16; // <6> + let raw_op = op_byte1 << 8 | op_byte2; // <7> + + let op_major = ((raw_op & 0xF000) >> 12) as u8; + let x = ((raw_op & 0x0F00) >> 8) as u8; + let y = ((raw_op & 0x00F0) >> 4) as u8; + let op_minor = (raw_op & 0x000F) as u8; + + self.position_in_memory += 2; // <8> + + match (op_major, op_minor) { + (HALT, HALT) => { return; }, // <9> + (ARITHMETIC_AND_LOGIC, ADD_XY) => self.add_xy(x, y), + _ => unimplemented!("opcode {:04x}", raw_op), // <10> + } + } + } + + fn add_xy(&mut self, x: u8, y: u8) { + self.registers[x as usize] += self.registers[y as usize]; + } +} + +fn main() { + let mut cpu = CPU { + registers: [0; 16], + memory: [0; 4096], + position_in_memory: 0, + }; + + cpu.registers[0] = 5; + cpu.registers[1] = 10; + cpu.registers[2] = 10; // <11> + cpu.registers[3] = 10; // <11> + + cpu.memory[0] = 0x80; cpu.memory[1] = 0x14; // <12> + cpu.memory[2] = 0x80; cpu.memory[3] = 0x24; // <13> + cpu.memory[4] = 0x80; cpu.memory[5] = 0x34; // <14> + + cpu.run(); + + assert_eq!(cpu.registers[0], 35); + + println!("5 + 10 + 10 + 10 = {}", cpu.registers[0]); +} \ No newline at end of file diff --git a/meap/meap-code/ch5/ch5-cpu2/Cargo.lock b/meap/meap-code/ch5/ch5-cpu2/Cargo.lock new file mode 100644 index 0000000..eda929e --- /dev/null +++ b/meap/meap-code/ch5/ch5-cpu2/Cargo.lock @@ -0,0 +1,4 @@ +[[package]] +name = "ch5-cpu2" +version = "0.1.0" + diff --git a/meap/meap-code/ch5/ch5-cpu2/Cargo.toml b/meap/meap-code/ch5/ch5-cpu2/Cargo.toml new file mode 100644 index 0000000..9b115b5 --- /dev/null +++ b/meap/meap-code/ch5/ch5-cpu2/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "ch5-cpu2" +version = "0.1.0" +authors = ["Tim McNamara "] + +[dependencies] diff --git a/meap/meap-code/ch5/ch5-cpu2/src/main.rs b/meap/meap-code/ch5/ch5-cpu2/src/main.rs new file mode 100644 index 0000000..8271ca8 --- /dev/null +++ b/meap/meap-code/ch5/ch5-cpu2/src/main.rs @@ -0,0 +1,60 @@ +const HALT: u8 = 0x0; +const ARITHMETIC_AND_LOGIC: u8 = 0x8; +const ADD_XY: u8 = 0x4; + +struct CPU { + // current_operation: u16, // no longer needed + registers: [u8; 16], // increase number of registers to 16 (0..F), as per CHIP-8 + position_in_memory: usize, // add a program counter.. using a usize to simplify array indexing + memory: [u8; 4096], // give the system 4kb memory +} + +impl CPU { + fn run(&mut self) { + loop { + let op_byte1 = self.memory[self.position_in_memory] as u16; // + let op_byte2 = self.memory[self.position_in_memory + 1] as u16; // + let raw_op = op_byte1 << 8 | op_byte2; + + self.position_in_memory += 2; + + let op_major = ((raw_op & 0xF000) >> 12) as u8; + let x = ((raw_op & 0x0F00) >> 8) as u8; + let y = ((raw_op & 0x00F0) >> 4) as u8; + let op_minor = (raw_op & 0x000F) as u8; + + match (op_major, op_minor) { + (HALT, HALT) => { return; }, + (ARITHMETIC_AND_LOGIC, ADD_XY) => self.add_xy(x, y), + _ => unimplemented!("opcode {:04x}", raw_op), // this macro is useful when you are debugging, as it will promptly indicate that you have made a typo + } + } + } + + fn add_xy(&mut self, x: u8, y: u8) { + self.registers[x as usize] += self.registers[y as usize]; + } +} + +fn main() { + let mut cpu = CPU { + registers: [0; 16], + memory: [0; 4096], + position_in_memory: 0, + }; + + cpu.registers[0] = 5; + cpu.registers[1] = 10; + cpu.registers[2] = 10; // initialise a few more registers + cpu.registers[3] = 10; // + + cpu.memory[0] = 0x80; cpu.memory[1] = 0x14; // 0x8014 -> ADD register 1 to register 0 + cpu.memory[2] = 0x80; cpu.memory[3] = 0x24; // 0x8014 -> ADD register 2 to register 0 + cpu.memory[4] = 0x80; cpu.memory[5] = 0x34; // 0x8014 -> ADD register 3 to register 0 + + cpu.run(); + + assert_eq!(cpu.registers[0], 35); + + println!("5 + 10 + 10 + 10 = {}", cpu.registers[0]); +} diff --git a/meap/meap-code/ch5/ch5-cpu3/Cargo.lock b/meap/meap-code/ch5/ch5-cpu3/Cargo.lock new file mode 100644 index 0000000..6262526 --- /dev/null +++ b/meap/meap-code/ch5/ch5-cpu3/Cargo.lock @@ -0,0 +1,4 @@ +[[package]] +name = "ch5-cpu3" +version = "0.1.0" + diff --git a/meap/meap-code/ch5/ch5-cpu3/Cargo.toml b/meap/meap-code/ch5/ch5-cpu3/Cargo.toml new file mode 100644 index 0000000..1f964df --- /dev/null +++ b/meap/meap-code/ch5/ch5-cpu3/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "ch5-cpu3" +version = "0.1.0" +authors = ["Tim McNamara "] + +[dependencies] diff --git a/meap/meap-code/ch5/ch5-cpu3/src/main.rs b/meap/meap-code/ch5/ch5-cpu3/src/main.rs new file mode 100644 index 0000000..903ef23 --- /dev/null +++ b/meap/meap-code/ch5/ch5-cpu3/src/main.rs @@ -0,0 +1,88 @@ +struct CPU { + registers: [u8; 16], + position_in_memory: usize, + memory: [u8; 4096], + stack: [u16; 16], + stack_pointer: usize, +} + +impl CPU { + fn run(&mut self) { + loop { + let op_byte1 = self.memory[self.position_in_memory] as u16; + let op_byte2 = self.memory[self.position_in_memory + 1] as u16; + let opcode = op_byte1 << 8 | op_byte2; + + let x = ((opcode & 0x0F00) >> 8) as u8; + let y = ((opcode & 0x00F0) >> 4) as u8; + let op_minor = (opcode & 0x000F) as u8; + let addr = opcode & 0x0FFF; + + self.position_in_memory += 2; + + match opcode { + 0x0000 => { return; }, + 0x00EE => { self.ret(); }, + 0x2000...0x2FFF => { self.call(addr); }, + 0x8000...0x8FFF => { + match op_minor { + 4 => { self.add_xy(x, y); } + _ => { unimplemented!("opcode: {:04x}", opcode); }, + } + }, + _ => unimplemented!("opcode {:04x}", opcode), + } + } + } + + fn call(&mut self, addr: u16) { + let sp = self.stack_pointer; + let stack = &mut self.stack; + + if sp > stack.len() { + panic!("Stack overflow!") + } + + stack[sp] = self.position_in_memory as u16; + self.stack_pointer += 1; + self.position_in_memory = addr as usize; + } + fn ret(&mut self) { + if self.stack_pointer == 0 { + panic!("Stack underflow"); + } + + self.stack_pointer -= 1; + self.position_in_memory = self.stack[self.stack_pointer] as usize; + } + + fn add_xy(&mut self, x: u8, y: u8) { + self.registers[x as usize] += self.registers[y as usize]; + } +} + +fn main() { + let mut cpu = CPU { + registers: [0; 16], + memory: [0; 4096], + position_in_memory: 0, + stack: [0; 16], + stack_pointer: 0, + }; + + cpu.registers[0] = 5; + cpu.registers[1] = 10; + + cpu.memory[0x000] = 0x21; cpu.memory[0x001] = 0x00; + cpu.memory[0x002] = 0x21; cpu.memory[0x003] = 0x00; + + cpu.memory[0x100] = 0x80; cpu.memory[0x101] = 0x14; + cpu.memory[0x102] = 0x80; cpu.memory[0x103] = 0x14; + cpu.memory[0x104] = 0x00; cpu.memory[0x105] = 0xEE; + + cpu.run(); + + assert_eq!(cpu.registers[0], 45); + + println!("5 + (10 * 2) + (10 * 2) = {}", cpu.registers[0]); +} \ No newline at end of file diff --git a/meap/meap-code/ch5/ch5-f32-as-u32.rs b/meap/meap-code/ch5/ch5-f32-as-u32.rs new file mode 100644 index 0000000..b23cf89 --- /dev/null +++ b/meap/meap-code/ch5/ch5-f32-as-u32.rs @@ -0,0 +1,8 @@ +fn main() { + let a: f32 = 42.42; + let frankentype: u32 = unsafe { + std::mem::transmute(a) // <1> + }; + + println!("{:032b}", frankentype); // <2> +} \ No newline at end of file diff --git a/meap/meap-code/ch5/ch5-fixed-width.rs b/meap/meap-code/ch5/ch5-fixed-width.rs new file mode 100644 index 0000000..fa0b867 --- /dev/null +++ b/meap/meap-code/ch5/ch5-fixed-width.rs @@ -0,0 +1,34 @@ +use num::{Float}; + +/// Q1_7 - single byte representation of a fixed point number with range [-1, 1]. +/// The name refers to the Texas Instrument representation +/// +/// References: +/// - English Wikipedia: "Q (number format)" https://en.wikipedia.org/wiki/Q_(number_format) +struct Q1_7(i8); // tuple struct holding a i8 value + +impl From for Q1_7 { + fn from (n:T) -> Self { + let val = if n > 1.0 { // out of bounds numbers are coerced to the maximum of the range + 1 + } else if n < -1.0 { + -1 + } else { + n * (2**7) + } + + Q1_7(val as i8) + } +} + +impl From for U: Float { + fn from(q: Q1_7) -> U { + q.0 * (2 ** -7) + } +} + +mod tests { + use super::*; + + test +} \ No newline at end of file diff --git a/meap/meap-code/ch5/ch5-genfib/Cargo.lock b/meap/meap-code/ch5/ch5-genfib/Cargo.lock new file mode 100644 index 0000000..83a7013 --- /dev/null +++ b/meap/meap-code/ch5/ch5-genfib/Cargo.lock @@ -0,0 +1,102 @@ +[root] +name = "genfib" +version = "0.1.0" +dependencies = [ + "num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-bigint 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "num-complex 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "num-rational 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-bigint" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-complex" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-integer" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-iter" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-rational" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-bigint 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-serialize" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "684f330624d8c3784fb9558ca46c4ce488073a8d22450415c5eb4f4cfb0d11b5" +"checksum num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "98b15ba84e910ea7a1973bccd3df7b31ae282bf9d8bd2897779950c9b8303d40" +"checksum num-bigint 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "5e2955fede25639c4f4f797e864b7585f20d98069c45e0c86b1d22a808eb9f77" +"checksum num-complex 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "3534898d8a1f6b16c12f9fc2f4eaabc7ecdcc55f267213caa8988fdc7d60ff94" +"checksum num-integer 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "21e4df1098d1d797d27ef0c69c178c3fab64941559b290fcae198e0825c9c8b5" +"checksum num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d1891bd7b936f12349b7d1403761c8a0b85a18b148e9da4429d5d102c1a41e" +"checksum num-rational 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "c2dc5ea04020a8f18318ae485c751f8cfa1c0e69dcf465c29ddaaa64a313cc44" +"checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99" +"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" +"checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b" diff --git a/meap/meap-code/ch5/ch5-genfib/Cargo.toml b/meap/meap-code/ch5/ch5-genfib/Cargo.toml new file mode 100644 index 0000000..1324537 --- /dev/null +++ b/meap/meap-code/ch5/ch5-genfib/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "genfib" +version = "0.1.0" +authors = ["Tim"] + +[dependencies] +num = "0.1" diff --git a/meap/meap-code/ch5/ch5-genfib/src/main.rs b/meap/meap-code/ch5/ch5-genfib/src/main.rs new file mode 100644 index 0000000..e3c95e0 --- /dev/null +++ b/meap/meap-code/ch5/ch5-genfib/src/main.rs @@ -0,0 +1,17 @@ +extern crate num; + +use num::{Integer, Unsigned}; + +fn fibonacci(n: T) -> T { + match n { + 0 => 0, + 1 => 1, + _ => n + fibonacci(n-1), + } +} + +fn main() { + let n = 10; + println!("{}", fibonacci(n as u16)); + println!("{}", fibonacci(n as u64)); +} diff --git a/meap/meap-code/ch5/ch5-impossible-add.rs b/meap/meap-code/ch5/ch5-impossible-add.rs new file mode 100644 index 0000000..f7f238d --- /dev/null +++ b/meap/meap-code/ch5/ch5-impossible-add.rs @@ -0,0 +1,5 @@ +fn main() { + let (a, b) = (200, 200); + let c: u8 = a + b; // <1> + println!("200 + 200 = {}", c); +} \ No newline at end of file diff --git a/meap/meap-code/ch5/ch5-message-store/Cargo.lock b/meap/meap-code/ch5/ch5-message-store/Cargo.lock new file mode 100644 index 0000000..e5df836 --- /dev/null +++ b/meap/meap-code/ch5/ch5-message-store/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "ch5-message-store" +version = "0.1.0" + diff --git a/meap/meap-code/ch5/ch5-message-store/Cargo.toml b/meap/meap-code/ch5/ch5-message-store/Cargo.toml new file mode 100644 index 0000000..4fb4bc0 --- /dev/null +++ b/meap/meap-code/ch5/ch5-message-store/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "ch5-message-store" +version = "0.1.0" +authors = ["Tim McNamara "] + +[dependencies] diff --git a/meap/meap-code/ch5/ch5-message-store/src/main.rs b/meap/meap-code/ch5/ch5-message-store/src/main.rs new file mode 100644 index 0000000..e790a57 --- /dev/null +++ b/meap/meap-code/ch5/ch5-message-store/src/main.rs @@ -0,0 +1,93 @@ + +#[derive(Debug)] +struct CubeSat { + id: u64, +} + +#[derive(Debug)] +enum StatusMessage { + Ok, +} + +#[derive(Debug)] +struct Mailbox { + messages: Vec, +} + +#[derive(Debug)] +struct Message { + to: u64, + content: String, +} + +struct GroundStation {} + +impl Mailbox { + fn post(&mut self, to: &CubeSat, msg: Message) { + self.messages.push(msg); + } + + fn deliver(&mut self, recipient: &CubeSat) -> Option { + for i in 0..self.messages.len() { + if self.messages[i].to == recipient.id { + let msg = self.messages.remove(i); + return Some(msg); + } + } + + None + } +} + +impl GroundStation { + fn connect(&self, sat_id: u64) -> CubeSat { + CubeSat { + id: sat_id, + } + } + + fn send(&self, mailbox: &mut Mailbox, to: &CubeSat, msg: Message) { + mailbox.post(to, msg); + } +} + +impl CubeSat { + fn recv(&self, mailbox: &mut Mailbox) -> Option { + mailbox.deliver(&self) + } +} + +// fn main() { +// let base = GroundStation {}; +// let mut sat_a = CubeSat { id: 0, mailbox: Mailbox { messages: vec![] } }; +// let mut sat_b = CubeSat { id: 1, mailbox: Mailbox { messages: vec![] } }; +// let mut sat_c = CubeSat { id: 2, mailbox: Mailbox { messages: vec![] } }; + +// } + +/// Returns a vector of CubeSat IDs +fn fetch_sat_ids() -> Vec { + vec![1,2,3] +} + + +fn main() { + let mut mail = Mailbox { messages: vec![] }; + + let base = GroundStation {}; + + let sat_ids = fetch_sat_ids(); + + for sat_id in &sat_ids { + let sat = base.connect(sat_id); + let msg = Message { to: sat_id, content: String::from("hello") }; + base.send(&mut mail, &sat, msg); + } + + for sat_id in &sat_ids { + let sat = base.connect(sat_id); + + let msg = sat.recv(&mut mail); + println!("{:?}: {:?}", sat, msg); + } +} \ No newline at end of file diff --git a/meap/meap-code/ch5/ch5-q/Cargo.lock b/meap/meap-code/ch5/ch5-q/Cargo.lock new file mode 100644 index 0000000..3ac932f --- /dev/null +++ b/meap/meap-code/ch5/ch5-q/Cargo.lock @@ -0,0 +1,127 @@ +[root] +name = "ch5-q" +version = "0.1.0" +dependencies = [ + "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitflags" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fuchsia-zircon" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "libc" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-bigint 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-complex 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", + "num-rational 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-bigint" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-complex" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-integer" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-iter" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-rational" +version = "0.1.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-bigint 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159" +"checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82" +"checksum libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "5ba3df4dcb460b9dfbd070d41c94c19209620c191b0340b929ce748a2bcd42d2" +"checksum num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "a311b77ebdc5dd4cf6449d81e4135d9f0e3b153839ac90e648a8ef538f923525" +"checksum num-bigint 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "8fd0f8dbb4c0960998958a796281d88c16fbe68d87b1baa6f31e2979e81fd0bd" +"checksum num-complex 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "503e668405c5492d67cf662a81e05be40efe2e6bcf10f7794a07bd9865e704e6" +"checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" +"checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" +"checksum num-rational 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "288629c76fac4b33556f4b7ab57ba21ae202da65ba8b77466e6d598e31990790" +"checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" +"checksum rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "61efcbcd9fa8d8fbb07c84e34a8af18a1ff177b449689ad38a6e9457ecc7b2ae" +"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" diff --git a/meap/meap-code/ch5/ch5-q/Cargo.toml b/meap/meap-code/ch5/ch5-q/Cargo.toml new file mode 100644 index 0000000..ffd0826 --- /dev/null +++ b/meap/meap-code/ch5/ch5-q/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "ch5-q" +version = "0.1.0" +authors = ["Tim McNamara "] + +[dependencies] +num = "*" \ No newline at end of file diff --git a/meap/meap-code/ch5/ch5-q/src/lib.rs b/meap/meap-code/ch5/ch5-q/src/lib.rs new file mode 100644 index 0000000..d05ca3a --- /dev/null +++ b/meap/meap-code/ch5/ch5-q/src/lib.rs @@ -0,0 +1,76 @@ +/// Q1_7 - single byte representation of a fixed point number with range [-1, 1]. +/// The name refers to the Texas Instrument representation +/// +/// References: +/// - English Wikipedia: "Q (number format)" https://en.wikipedia.org/wiki/Q_(number_format) +#[derive(Debug,Clone,Copy,PartialEq,Eq)] +pub struct Q7(i8); // tuple struct holding a i8 value + +impl From for Q7 { + fn from (n: f64) -> Self { + if n >= 1.0 { // out of bounds numbers are coerced to the maximum of the range + Q7(127) + } else if n <= -1.0 { + Q7(-128) + } else { + Q7((n * 128.0) as i8) // 128 == (2 ** 7) == pow(2,7) + } + } +} + +impl From for f64 { + fn from(n: Q7) -> f64 { + (n.0 as f64) * 2f64.powf(-7.0) // 0.0078125// (2 ** -7) // pow(2, -7) + } +} + +impl From for Q7 { + fn from (n: f32) -> Self { + Q7::from(n as f64) // conversion from f32 to f64 works perfectly + } +} + +impl From for f32 { + fn from(n: Q7) -> f32 { + f64::from(n) as f32 // conversion from f64 to f32 can result in undefined behavior, + // but not here as f32 can represent all values representable by Q7 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn out_of_bounds() { + assert_eq!(Q7::from(10.), Q7::from(1.)); + assert_eq!(Q7::from(-10.), Q7::from(-1.)); + } + + #[test] + fn f32_to_q7() { + let n1: f32 = 0.7; + let q1 = Q7::from(n1); + + let n2 = -0.4; + let q2 = Q7::from(n2); + + let n3 = 123.0; + let q3 = Q7::from(n3); + + assert_eq!(q1, Q7(89)); + assert_eq!(q2, Q7(-51)); + assert_eq!(q3, Q7(127)); + } + + #[test] + fn q7_to_f32() { + let q1 = Q7::from(0.7); + let n1 = f32::from(q1); + assert_eq!(n1, 0.6953125); + + let q2 = Q7::from(n1); // numbers that can be represented exactly by Q7 + let n2 = f32::from(q2); // can survive the transition between Q7 and f32 + assert_eq!(n1, n2); + } +} diff --git a/meap/meap-code/ch5/ch5-sat-messaging/msg-with-refs/Cargo.lock b/meap/meap-code/ch5/ch5-sat-messaging/msg-with-refs/Cargo.lock new file mode 100644 index 0000000..79da38d --- /dev/null +++ b/meap/meap-code/ch5/ch5-sat-messaging/msg-with-refs/Cargo.lock @@ -0,0 +1,4 @@ +[root] +name = "msg-with-refs" +version = "0.1.0" + diff --git a/meap/meap-code/ch5/ch5-sat-messaging/msg-with-refs/Cargo.toml b/meap/meap-code/ch5/ch5-sat-messaging/msg-with-refs/Cargo.toml new file mode 100644 index 0000000..699bbde --- /dev/null +++ b/meap/meap-code/ch5/ch5-sat-messaging/msg-with-refs/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "msg-with-refs" +version = "0.1.0" +authors = ["Tim McNamara "] + +[dependencies] diff --git a/meap/meap-code/ch5/ch5-sat-messaging/msg-with-refs/src/main.rs b/meap/meap-code/ch5/ch5-sat-messaging/msg-with-refs/src/main.rs new file mode 100644 index 0000000..394f6cd --- /dev/null +++ b/meap/meap-code/ch5/ch5-sat-messaging/msg-with-refs/src/main.rs @@ -0,0 +1,51 @@ +#[derive(Debug)] +enum StatusCode { + Ok, +} + +#[derive(Debug)] +struct Mailbox { + messages: Vec, +} + +type Message = String; + +#[derive(Debug)] +struct CubeSat { + id: u64, + mailbox: Mailbox, +} + +impl CubeSat { + fn recv(&mut self) -> Option { + self.mailbox.messages.pop() + } +} + +struct GroundStation; + +impl GroundStation { + fn send(&self, to: &mut CubeSat, msg: Message) { + to.mailbox.messages.push(msg); + } +} + +fn main() { + let base = GroundStation {}; + let mut sat_a = CubeSat { id: 0, mailbox: Mailbox { messages: vec![] } }; + let mut sat_b = CubeSat { id: 1, mailbox: Mailbox { messages: vec![] } }; + let mut sat_c = CubeSat { id: 2, mailbox: Mailbox { messages: vec![] } }; + + println!("t0: {:?}", sat_a); + + // sat_a.mailbox.messages.push(Message::from("hi")); + + base.send(&mut sat_a, Message::from("hello there!")); + + println!("t1: {:?}", sat_a); + + let msg = sat_a.recv(); + //println!("{:?}", msg); + + println!("t2: {:?}", sat_a); +} diff --git a/meap/meap-code/ch5/ch5-to-oblivion.rs b/meap/meap-code/ch5/ch5-to-oblivion.rs new file mode 100644 index 0000000..1bfee53 --- /dev/null +++ b/meap/meap-code/ch5/ch5-to-oblivion.rs @@ -0,0 +1,11 @@ +fn main() { + let mut i: u16 = 0; + print!("{:}..", i); + loop { + i += 1000; + print!("{}..", i); + if i % 10000 == 0 { + print!{"\n"} + } + } +} \ No newline at end of file diff --git a/meap/meap-code/ch5/ch5-u8-to-mock-rand.rs b/meap/meap-code/ch5/ch5-u8-to-mock-rand.rs new file mode 100644 index 0000000..46ac91a --- /dev/null +++ b/meap/meap-code/ch5/ch5-u8-to-mock-rand.rs @@ -0,0 +1,17 @@ +// fn mock_rand(n: u8) -> f32 { +// (n as f32) / 255. +// } + +fn mock_rand(n: u8) -> f32 { + let base: u32 = 0b0_01111110_00000000000000000000000; // <1> Underscores mark the sign/mantissa/exponent boundaries + let large_n = (n as u32) << 15; // <2> Align the input byte `n` to 32 bits, then increase its value by shifting its bits 15 places to the left + let f32_bits = base | large_n; // <3> Take a bitwise OR, merging the base with the input byte + let m = f32::from_bits(f32_bits);// <4> Interpret `f32_bits` (which is type `u32`) as an `f32` + 2.0 * ( m - 0.5 ) // <5> Normalize the output range +} + +fn main() { + println!("max of input range: {:08b} -> {}", 0xff, mock_rand(0xff)); + println!("mid of input range: {:08b} -> {}", 0x77, mock_rand(0x77)); + println!("min of input range: {:08b} -> {}", 0x00, mock_rand(0x00)); +} \ No newline at end of file diff --git a/meap/meap-code/ch5/ch5-visualising-f32.rs b/meap/meap-code/ch5/ch5-visualising-f32.rs new file mode 100644 index 0000000..6de5526 --- /dev/null +++ b/meap/meap-code/ch5/ch5-visualising-f32.rs @@ -0,0 +1,44 @@ +const BIAS: i32 = 127; // <1> Similar constants are accessible via the `std::f32` module +const RADIX: f32 = 2.0; // <1> + +fn main() { // <2> main() can live happily at the beginning of a file + let n: f32 = 42.42; + + let (signbit, exponent, fraction) = deconstruct_f32(n); // <3> Here the three components of `n` are extracted, with each one being an uninterpreted sequence of bits + println!("{} -> [sign:{:01b}, exponent:{:08b}, mantissa:{:023b}] -> tbc", n, signbit, exponent, fraction); + + let (sign, exponent, mantissa) = decode_f32_parts(signbit, exponent, fraction); // <4> Each component is interpreted according to the standard + let reconstituted_n = f32_from_parts(sign, exponent, mantissa); // <5> The original value is produced from those three components + println!("{} -> [sign:{}, exponent:{}, mantissa:{:?}] -> {}", n, signbit, exponent, mantissa, reconstituted_n); +} + +fn deconstruct_f32(n: f32) -> (u32, u32, u32) { + let n_: u32 = unsafe { std::mem::transmute(n) }; + + let sign = (n_ >> 31) & 1; // <2> strip 31 unwanted bits away by shifting them into nowhere, leaving only the sign bit + let exponent = (n_ >> 23) & 0xff; // <3> filter out the top bit with a logical AND mask, then strip 23 unwanted bits away + let fraction = 0b00000000_01111111_11111111_11111111 & n_; // <4> only retain the 23 "`least significant`" bits via a mask + + (sign, exponent, fraction) // <5> The mantissa part is called a fraction here, as it becomes the mantissa once it's decoded +} + +fn decode_f32_parts(sign: u32, exponent: u32, fraction: u32) -> (f32, f32, f32) { + let signed_1 = (-1.0_f32).powf(sign as f32); // <6> Convert the sign bit to 1.0 or -1.0. Parentheses are required around `-1.0_f32` to clarify operator precedence as method calls rank higher than unary minus. + + let exponent = (exponent as i32) - BIAS; // <7> We need to do a bit of a type dance here. `exponent` must become an `i32` in case subtracting the `BIAS` results in a negative number. Then it needs to be cast as a `f32`, so that it can be used for exponentiation. + let exponent = RADIX.powf(exponent as f32); // <7> + + let mut mantissa: f32 = 1.0; // <8> We start by assuming that the implicit 24th bit is set. That has the upshot of defaulting the mantissa's value as 1. + for i in 0..23_u32 { // <9> We provide a concrete type here to ensure that the bit patterns that are generated by the mask are defined + let one_at_bit_i = 1 << i; // <10> At each iteration, create an AND mask of a single bit in the position that we're currently interested in. + if (one_at_bit_i & fraction) != 0 { // <11> Any non-zero result means that the bit is present within `fraction` + mantissa += 2_f32.powf((i as f32) - 23.0); // <11> To arrive at the decimal value of the bit at `i`, we find 2^i-23^. -23 means that the result gets smaller when `i` is close to 0, as desired. + } + } + + (signed_1, exponent, mantissa) +} + +fn f32_from_parts(sign: f32, exponent: f32, mantissa: f32) -> f32 { // <12> This code cheats a bit by using `f32` values in intermediate steps. Hopefully it is a forgivable offense. + sign * exponent * mantissa +} \ No newline at end of file -- cgit v1.2.3