summaryrefslogtreecommitdiff
path: root/meap/meap-code/ch3
diff options
context:
space:
mode:
authorAdam Carpenter <53hornet@gmail.com>2019-03-27 15:32:37 -0400
committerAdam Carpenter <53hornet@gmail.com>2019-03-27 15:32:37 -0400
commit67cdcc2e12118becb823e20a40cc2687f2b8425a (patch)
treeed92c3234b89079e6d4cf36f5e80c5ffa79def48 /meap/meap-code/ch3
parente25482fca375d318a39c3b54db396b0db6e0b263 (diff)
downloadlearning-rust-67cdcc2e12118becb823e20a40cc2687f2b8425a.tar.xz
learning-rust-67cdcc2e12118becb823e20a40cc2687f2b8425a.zip
Started Rust in Action MEAP.
Diffstat (limited to 'meap/meap-code/ch3')
-rw-r--r--meap/meap-code/ch3/ch3-adding-pub-to-file.rs28
-rw-r--r--meap/meap-code/ch3/ch3-anystring-macro.rs10
-rw-r--r--meap/meap-code/ch3/ch3-defining-files-neatly.rs29
-rw-r--r--meap/meap-code/ch3/ch3-defining-files.rs18
-rw-r--r--meap/meap-code/ch3/ch3-error-1.rs30
-rw-r--r--meap/meap-code/ch3/ch3-file-doced.rs38
-rw-r--r--meap/meap-code/ch3/ch3-file-states.rs59
-rw-r--r--meap/meap-code/ch3/ch3-files-with-modes.rs75
-rw-r--r--meap/meap-code/ch3/ch3-implementing-display.rs49
-rw-r--r--meap/meap-code/ch3/ch3-mock-file.rs18
-rw-r--r--meap/meap-code/ch3/ch3-newtype-pattern.rs10
-rw-r--r--meap/meap-code/ch3/ch3-not-quite-file-1.rs23
-rw-r--r--meap/meap-code/ch3/ch3-not-quite-file-2.rs42
-rw-r--r--meap/meap-code/ch3/ch3-not-quite-file-3.rs55
-rw-r--r--meap/meap-code/ch3/ch3-not-quite-file-4.rs42
-rw-r--r--meap/meap-code/ch3/ch3-parse-log.rs35
-rw-r--r--meap/meap-code/ch3/ch3-public-file.rs33
-rw-r--r--meap/meap-code/ch3/ch3-return-result.rs68
-rw-r--r--meap/meap-code/ch3/ch3-skeleton-read-trait.rs21
-rw-r--r--meap/meap-code/ch3/ch3-string-macro.rs10
-rw-r--r--meap/meap-code/ch3/filebasics/Cargo.toml6
-rw-r--r--meap/meap-code/ch3/filebasics/src/main.rs3
-rw-r--r--meap/meap-code/ch3/fileresult/Cargo.toml7
-rw-r--r--meap/meap-code/ch3/fileresult/src/main.rs65
-rw-r--r--meap/meap-code/ch3/globalerror/Cargo.toml7
-rw-r--r--meap/meap-code/ch3/globalerror/src/main.rs30
26 files changed, 811 insertions, 0 deletions
diff --git a/meap/meap-code/ch3/ch3-adding-pub-to-file.rs b/meap/meap-code/ch3/ch3-adding-pub-to-file.rs
new file mode 100644
index 0000000..b5ade57
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-adding-pub-to-file.rs
@@ -0,0 +1,28 @@
+#[derive(Debug,PartialEq)]
+pub enum FileState {
+ Open,
+ Closed,
+}
+
+#[derive(Debug)]
+struct File {
+ pub name: String,
+ data: Vec<u8>,
+ pub state: FileState,
+}
+
+impl File {
+ pub fn new(name: &str) -> File {
+ File {
+ name: String::from(name),
+ data: Vec::new(),
+ state: FileState::Closed
+ }
+ }
+}
+
+fn main() {
+ let f7 = File::new("f7.txt");
+ //...
+ println!("{:?}", f7);
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-anystring-macro.rs b/meap/meap-code/ch3/ch3-anystring-macro.rs
new file mode 100644
index 0000000..7500e95
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-anystring-macro.rs
@@ -0,0 +1,10 @@
+macro_rules! string {
+ ($x:expr) => ( // <1>
+ String::from(stringify!($x)); // <2>
+ )
+}
+
+fn main() {
+ let s = string!(hello there);
+ println!("{}", s);
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-defining-files-neatly.rs b/meap/meap-code/ch3/ch3-defining-files-neatly.rs
new file mode 100644
index 0000000..2025f72
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-defining-files-neatly.rs
@@ -0,0 +1,29 @@
+#[derive(Debug)]
+struct File {
+ name: String,
+ data: Vec<u8>,
+}
+
+impl File {
+ fn new(name: &str) -> File { // <1> As `File::new()` is a completely normal function--rather than something blessed by the language--we need to tell Rust that it will be returning a `File` from this function
+ File { // <2>
+ name: String::from(name), // <2> `File::new()` does little more than encapsulate the object creation syntax
+ data: Vec::new(), // <2>
+ }
+ }
+
+ // fn len(&self) -> usize { // <3> `File::len()` takes an implicit argument `self`. You'll notice that there is no explicit argument provided on line 25.
+ // self.data.len() // <4> `usize` is the type returned by `Vec<T>::len()`, which is sent directly through to the caller
+ // }
+}
+
+fn main() {
+ let f3 = File::new("f3.txt");
+
+ let f3_name = &f3.name; // <5> Fields are private by default, but can be accessed within the module that defines the struct. The module system is discussed further on in the chapter.
+ //let f3_length = f3.len();
+ let f3_length = f3.data.len();
+
+ println!("{:?}", f3);
+ println!("{} is {} bytes long", f3_name, f3_length);
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-defining-files.rs b/meap/meap-code/ch3/ch3-defining-files.rs
new file mode 100644
index 0000000..c41ac4b
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-defining-files.rs
@@ -0,0 +1,18 @@
+#[derive(Debug)] // <1>
+struct File {
+ name: String,
+ data: Vec<u8>, // <2>
+}
+
+fn main() {
+ let f1 = File {
+ name: String::from("f1.txt"), // <3>
+ data: Vec::new(), // <4>
+ };
+
+ let f1_name = &f1.name; // <5>
+ let f1_length = &f1.data.len(); // <5>
+
+ println!("{:?}", f1);
+ println!("{} is {} bytes long", f1_name, f1_length);
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-error-1.rs b/meap/meap-code/ch3/ch3-error-1.rs
new file mode 100644
index 0000000..bdf9088
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-error-1.rs
@@ -0,0 +1,30 @@
+extern crate rand; // <> Make an external crate available to our code
+use rand; // <> Bring `rand` into local scope
+
+static mut ERROR: isize = 0;
+
+struct File;
+
+#[allow(unused_variables)]
+fn read(f: &File, save_to: Vec<u8>) -> usize {
+ if rand::thread_rng().gen_weighted_bool(10000) {
+ unsafe {
+ ERROR = 1;
+ }
+ }
+
+ 0 // <> Always read() 0 bytes
+}
+
+#[allow(unused_mut)]
+fn main() {
+ let mut f = File;
+ let mut buffer = vec![];
+
+ read(&f, buffer);
+ unsafe {
+ if ERROR != 0 {
+ panic!("An error has occurred!")
+ }
+ }
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-file-doced.rs b/meap/meap-code/ch3/ch3-file-doced.rs
new file mode 100644
index 0000000..18e35f0
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-file-doced.rs
@@ -0,0 +1,38 @@
+//! Simulating files one step at a time.
+
+/// Represents a "file", which probably lives on a file system.
+#[derive(Debug)]
+pub struct File {
+ name: String,
+ data: Vec<u8>,
+}
+
+impl File {
+ /// New files are assumed to be empty, but a name is required.
+ pub fn new(name: &str) -> File {
+ File {
+ name: String::from(name),
+ data: Vec::new(),
+ }
+ }
+
+ pub fn len(&self) -> usize {
+ //! Returns the file's length in bytes.
+ self.data.len()
+ }
+
+ pub fn name(&self) -> String {
+ //! Returns the file's name.
+ self.name.clone()
+ }
+}
+
+fn main() {
+ let f1 = File::new("f1.txt");
+
+ let f1_name = f1.name();
+ let f1_length = f1.len();
+
+ println!("{:?}", f1);
+ println!("{} is {} bytes long", f1_name, f1_length);
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-file-states.rs b/meap/meap-code/ch3/ch3-file-states.rs
new file mode 100644
index 0000000..36510a5
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-file-states.rs
@@ -0,0 +1,59 @@
+#[derive(Debug,PartialEq)]
+enum FileState {
+ Open,
+ Closed,
+}
+
+#[derive(Debug)]
+struct File {
+ name: String,
+ data: Vec<u8>,
+ state: FileState,
+}
+
+impl File {
+ fn new(name: &str) -> File {
+ File { name: String::from(name), data: Vec::new(), state: FileState::Closed }
+ }
+
+ fn read(self: &File, save_to: &mut Vec<u8>) -> Result<usize, String> {
+ if self.state != FileState::Open {
+ return Err(String::from("File must be open for reading"));
+ }
+ let mut tmp = self.data.clone();
+ let read_length = tmp.len();
+ save_to.reserve(read_length);
+ save_to.append(&mut tmp);
+ Ok(read_length) // <6>
+ }
+}
+
+fn open(mut f: File) -> Result<File, String> {
+ f.state = FileState::Open;
+ Ok(f)
+}
+
+fn close(mut f: File) -> Result<File, String> {
+ f.state = FileState::Closed;
+ Ok(f)
+}
+
+fn main() {
+ let mut f5 = File::new("5.txt");
+
+ let mut buffer: Vec<u8> = vec![];
+
+ if f5.read(&mut buffer).is_err() {
+ println!("Error checking is working");
+ }
+
+ f5 = open(f5).unwrap(); // <9>
+ let f5_length = f5.read(&mut buffer).unwrap(); // <9>
+ f5 = close(f5).unwrap(); // <9>
+
+ let text = String::from_utf8_lossy(&buffer);
+
+ println!("{:?}", f5);
+ println!("{} is {} bytes long", &f5.name, f5_length);
+ println!("{}", text);
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-files-with-modes.rs b/meap/meap-code/ch3/ch3-files-with-modes.rs
new file mode 100644
index 0000000..4440924
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-files-with-modes.rs
@@ -0,0 +1,75 @@
+#[derive(Debug)]
+pub enum FileOpenMode {
+ Read,
+ Write,
+ Append,
+ Truncate,
+}
+
+#[derive(Debug)]
+pub enum FileHandle {
+ Handle(usize),
+ None,
+}
+
+#[derive(Debug)]
+pub enum FileState {
+ PendingCreation,
+ Created(FileOpenMode),
+ Opened(FileOpenMode),
+ Error(String),
+ Closed,
+ Deleted,
+}
+
+#[derive(Debug)]
+pub struct File {
+ name: String,
+ data: Vec<u8>,
+ state: FileState,
+ handle: FileHandle,
+}
+
+impl File {
+ pub fn new(name: &str) -> File {
+ File {
+ name: String::from(name),
+ data: Vec::new(),
+ state: FileState::PendingCreation, // <1>
+ handle: FileHandle::None, // <1>
+ }
+ }
+
+ pub fn from_options(name: &str, state: FileState, handle: FileHandle) -> File {
+ File {
+ name: String::from(name),
+ data: Vec::new(),
+ state: state,
+ handle: handle,
+ }
+ }
+}
+
+fn main() {
+ let f1 = File::new("f1.txt");
+ let f2 = File::from_options("f2.txt",
+ FileState::Opened(FileOpenMode::Read),
+ FileHandle::Handle(123)
+ );
+ let f3 = File::from_options("f3.txt",
+ FileState::Opened(FileOpenMode::Write),
+ FileHandle::None
+ );
+
+ let mut files = [f1, f2, f3];
+
+ for f in &files {
+ println!("{:?}", f);
+ }
+
+ // uh oh, disk failure
+ for ref mut f in &mut files {
+ f.state = FileState::Error(String::from("disk read failure"));
+ println!("{:?}", f);
+ }
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-implementing-display.rs b/meap/meap-code/ch3/ch3-implementing-display.rs
new file mode 100644
index 0000000..8537bd9
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-implementing-display.rs
@@ -0,0 +1,49 @@
+#![allow(dead_code)] // <1> Silence warnings related to FileState::Open not being used
+
+use std::fmt; // <2> Bring the `std::fmt` crate into local scope, allowing us to make use of `fmt::Result`
+use std::fmt::{Display}; // <3> Bring `Display` into local scope, avoiding the need for us to prefix it as `fmt::Display` in our code
+
+#[derive(Debug,PartialEq)]
+enum FileState {
+ Open,
+ Closed,
+}
+
+#[derive(Debug)]
+struct File {
+ name: String,
+ data: Vec<u8>,
+ state: FileState,
+}
+
+impl Display for FileState {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ FileState::Open => write!(f, "OPEN"), // <4> Sneakily, we can make use of `write!` to do the grunt work for us. Strings already implement `Display` themselves, so there's very little left for us to do.
+ FileState::Closed => write!(f, "CLOSED"), // <4>
+ }
+ }
+}
+
+impl Display for File {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "<{} ({})>", self.name, self.state) // <5> We can rely on the FileState Display implementation in our own code
+ }
+}
+
+impl File {
+ fn new(name: &str) -> File {
+ File {
+ name: String::from(name),
+ data: Vec::new(),
+ state: FileState::Closed
+ }
+ }
+}
+
+fn main() {
+ let f5 = File::new("f5.txt");
+ //...
+ println!("{:?}", f5); // <1>
+ println!("{}", f5); // <1>
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-mock-file.rs b/meap/meap-code/ch3/ch3-mock-file.rs
new file mode 100644
index 0000000..a07645c
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-mock-file.rs
@@ -0,0 +1,18 @@
+#[derive(Debug)] // <1>
+struct File {
+ name: String,
+ data: Vec<u8>, // <2>
+}
+
+fn main() {
+ let f1 = File {
+ name: String::from("f1.txt"), // <3>
+ data: Vec::new(), // <4>
+ };
+
+ let f1_name = &f1.name; // <5>
+ let f1_length = &f1.data.len(); // <5>
+
+ println!("{:?}", f1);
+ println!("{} is {} bytes long", f1_name, f1_length);
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-newtype-pattern.rs b/meap/meap-code/ch3/ch3-newtype-pattern.rs
new file mode 100644
index 0000000..9647b27
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-newtype-pattern.rs
@@ -0,0 +1,10 @@
+#[derive(PartialEq)] // <1>
+struct Hostname(String); // <2>
+
+fn main() {
+ let ordinary_string = String::from("localhost");
+ let host = Hostname ( ordinary_string.clone() );
+ if host == ordinary_string { // <3>
+ println!("huh?");
+ };
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-not-quite-file-1.rs b/meap/meap-code/ch3/ch3-not-quite-file-1.rs
new file mode 100644
index 0000000..292d7ab
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-not-quite-file-1.rs
@@ -0,0 +1,23 @@
+#![allow(unused_variables)] // <1> Relax compiler warnings while working through ideas
+
+type File = String; // <2> Create a type alias. The compiler won't distinguish between String & File, but your source code will.
+
+fn open(f: &mut File) -> bool {
+ true // <3> let's assume for the moment that this always succeeds
+}
+
+fn close(f: &mut File) -> bool {
+ true // <3>
+}
+
+#[allow(dead_code)] // <4> Relaxes a compiler warning about an unused function
+fn read(f: &mut File, save_to: &mut Vec<u8>) -> ! { // <5> Using `!` as a return type indicates to the Rust compiler that this function never returns
+ unimplemented!() // <6> A macro that crashes the program if it is encountered
+}
+
+fn main() {
+ let mut f1 = File::from("f1.txt"); // <7> With the type declaration at line 3, `File` "inherits" all of String's methods
+ open(&mut f1);
+ //read(f1 , vec![]); // <8> There's little point in calling this method
+ close(&mut f1);
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-not-quite-file-2.rs b/meap/meap-code/ch3/ch3-not-quite-file-2.rs
new file mode 100644
index 0000000..f4f86fd
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-not-quite-file-2.rs
@@ -0,0 +1,42 @@
+#![allow(unused_variables)] // <1> Silences a warnings caused by `open()` and `close()` not making use of needing their argument
+
+#[derive(Debug)] // <2> This enables `File` to work with `println!` and its `fmt!` sibling macros, used at the bottom of the code listing
+struct File {
+ name: String,
+ data: Vec<u8>,
+}
+
+fn open(f: &mut File) -> bool { // <3> These two functions will remain inert for now
+ true
+}
+
+fn close(f: &mut File) -> bool { // <3>
+ true
+}
+
+fn read(f: &File, save_to: &mut Vec<u8>) -> usize { // <4> Return the "number of bytes read"
+ let mut tmp = f.data.clone(); // <5> Make a copy of the data here, as `save_to.append()` will shrink the input vec
+ let read_length = tmp.len();
+ save_to.reserve(read_length); // <6> Not strictly necessary, but useful to know about
+ save_to.append(&mut tmp); // <7> Allocate sufficient data in the `save_to` buffer to hold the contents of `f`
+ read_length
+}
+
+fn main() {
+ let mut f2 = File {
+ name: String::from("2.txt"),
+ data: vec![114, 117, 115, 116, 33],
+ };
+
+ let mut buffer: Vec<u8> = vec![];
+
+ open(&mut f2); // <8> Do the hard work of interacting the the file.
+ let f2_length = read(&f2, &mut buffer); // <8>
+ close(&mut f2); // <8>
+
+ let text = String::from_utf8_lossy(&buffer); // <9> Convert `Vec<u8>` to `String`. Any bytes that are not valid UTF-8 are replaced with �
+
+ println!("{:?}", f2);
+ println!("{} is {} bytes long", &f2.name, f2_length);
+ println!("{}", text) // <10> View [114, 117, 115, 116, 33] as an actual word
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-not-quite-file-3.rs b/meap/meap-code/ch3/ch3-not-quite-file-3.rs
new file mode 100644
index 0000000..a88d112
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-not-quite-file-3.rs
@@ -0,0 +1,55 @@
+#![allow(unused_variables)]
+
+#[derive(Debug)]
+struct File {
+ name: String,
+ data: Vec<u8>,
+}
+
+impl File {
+ fn new(name: &str) -> File {
+ File {
+ name: String::from(name),
+ data: Vec::new(),
+ }
+ }
+
+ fn new_with_data(name: &str, data: &Vec<u8>) -> File { // <1> This method has snuck in to deal with cases where we want to simulate cases where a file has pre-existing data
+ let mut f = File::new(name);
+ f.data = data.clone();
+ f
+ }
+
+ fn read(self: &File, save_to: &mut Vec<u8>) -> usize { // <2> The `f` argument has been replaced with `self`
+ let mut tmp = self.data.clone();
+ let read_length = tmp.len();
+ save_to.reserve(read_length);
+ save_to.append(&mut tmp);
+ read_length
+ }
+}
+
+fn open(f: &mut File) -> bool { // <3> These two can remain as-in until we've looked at error handling
+ true
+}
+
+fn close(f: &mut File) -> bool { // <3>
+ true
+}
+
+fn main() {
+ let f3_data: Vec<u8> = vec![114, 117, 115, 116, 33]; // <4> An explicit type needs to be provided, as `vec!` can't infer the necessary type through the function boundary
+ let mut f3 = File::new_with_data("2.txt", &f3_data);
+
+ let mut buffer: Vec<u8> = vec![];
+
+ open(&mut f3);
+ let f3_length = f3.read(&mut buffer); // <5> Here is the the change in the calling code
+ close(&mut f3);
+
+ let text = String::from_utf8_lossy(&buffer);
+
+ println!("{:?}", f3);
+ println!("{} is {} bytes long", &f3.name, f3_length);
+ println!("{}", text);
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-not-quite-file-4.rs b/meap/meap-code/ch3/ch3-not-quite-file-4.rs
new file mode 100644
index 0000000..4c3dbfd
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-not-quite-file-4.rs
@@ -0,0 +1,42 @@
+#[derive(Debug)] // <1>
+struct File {
+ name: String,
+ data: Vec<u8>, // <2>
+ state: &'static str,
+}
+
+type FileMode = &'static str;
+
+const OPEN: FileMode = "open";
+const CLOSED: FileMode = "closed";
+
+fn open(f: &mut File) -> bool {
+ f.state = OPEN;
+ true // <3> let's assume for the moment that this always succeeds
+}
+
+fn close(f: &mut File) -> bool {
+ f.state = CLOSED;
+ true // <3>
+}
+
+fn read(f: &File) -> (usize, Vec<u8>) {
+ (f.data.len(), f.data.clone())
+}
+
+fn main() {
+ let mut f2 = File {
+ name: String::from("2.txt"), // <3>
+ data: vec![],
+ state: CLOSED,
+ };
+
+ let f2_name = &f2.name.clone(); // <5>
+
+ open(&mut f2);
+ let (f2_length, _) = read(&f2);
+ close(&mut f2);
+
+ println!("{:?}", f2);
+ println!("{} is {} bytes long", f2_name, f2_length);
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-parse-log.rs b/meap/meap-code/ch3/ch3-parse-log.rs
new file mode 100644
index 0000000..b675aa1
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-parse-log.rs
@@ -0,0 +1,35 @@
+#[derive(Debug)] // <1> Enable this enum to be printed to the screen via auto-generated code
+enum Event {
+ Update, // <2> Create three variants of Event, including one value for unrecognized events
+ Delete, // <2>
+ Unknown, // <2>
+}
+
+type Message = String; // <3> A convenient name for String for use in this crate's context
+
+fn parse_log(line: &'static str) -> (Event, Message) { // <4> A function for parsing a line and converting it into semi-structured data
+ let parts: Vec<&str> = line.splitn(2, ' ').collect(); // <5> `collect()` consumes an iterator (returned from `line.splitn()`) and returns `Vec<T>`
+ if parts.len() == 1 { // <6> If `line.splitn()` didn't split `log` into two parts, return an error
+ return (Event::Unknown, String::from(line))
+ }
+
+ let event = parts[0]; // <7> Assign each part to a variable for ease of future use
+ let rest = String::from(parts[1]); // <7>
+
+ match event {
+ "UPDATE" | "update" => (Event::Update, rest), // <8> When we match a known event, return structured data
+ "DELETE" | "delete" => (Event::Delete, rest), // <8>
+ _ => (Event::Unknown, String::from(line)), // <9> If we don't recognize the event type, return the whole line
+ }
+}
+
+fn main() {
+ let log = "BEGIN Transaction XK342
+UPDATE 234:LS/32231 {\"price\": 31.00} -> {\"price\": 40.00}
+DELETE 342:LO/22111";
+
+ for line in log.lines(){
+ let parse_result = parse_log(line);
+ println!("{:?}", parse_result);
+ }
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-public-file.rs b/meap/meap-code/ch3/ch3-public-file.rs
new file mode 100644
index 0000000..ac6a9f5
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-public-file.rs
@@ -0,0 +1,33 @@
+#[derive(Debug)]
+pub struct File { // <1>
+ name: String, // <2>
+ data: Vec<u8>, // <2>
+}
+
+impl File {
+ pub fn new(name: &str) -> File {
+ File {
+ name: String::from(name),
+ data: Vec::new(),
+ }
+ }
+
+ pub fn len(&self) -> usize {
+ self.data.len()
+ }
+
+ pub fn name(&self) -> String {
+ self.name.clone() // <3>
+ }
+}
+
+
+fn main() {
+ let f1 = File::new("f1.txt");
+
+ let f1_name = f1.name(); // <4>
+ let f1_length = f1.len();
+
+ println!("{:?}", f1);
+ println!("{} is {} bytes long", f1_name, f1_length);
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-return-result.rs b/meap/meap-code/ch3/ch3-return-result.rs
new file mode 100644
index 0000000..da25107
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-return-result.rs
@@ -0,0 +1,68 @@
+//#![allow(unused_variables)]
+
+extern crate rand;
+use rand;
+
+fn one_in_(n: usize) -> bool {
+ rand::thread_rng().gen_weighted_bool(n)
+}
+
+#[derive(Debug)]
+struct File {
+ name: String,
+ data: Vec<u8>,
+}
+
+impl File {
+ fn new(name: &str) -> File {
+ File {
+ name: String::from(name),
+ data: Vec::new(),
+ }
+ }
+
+ fn new_with_data(name: &str, data: &Vec<u8>) -> File { // <1>
+ let mut f = File::new(name);
+ f.data = data.clone();
+ f
+ }
+
+ fn read(self: &File, save_to: &mut Vec<u8>) -> usize { // <2>
+ let mut tmp = self.data.clone();
+ let read_length = tmp.len();
+ save_to.reserve(read_length);
+ save_to.append(&mut tmp);
+ read_length
+ }
+}
+
+fn open(f: &mut File) -> Result<File, String> {
+ if one_in_(10_000) {
+ return Err(String::from("Permission denied"))
+ }
+ Some(f)
+}
+
+fn close(f: &mut File) -> Result<File, String> {
+ if one_in_(100_000) {
+ return Err(String::from("Interrupted by signal!"))
+ }
+ Some(f)
+}
+
+fn main() {
+ let f3_data: Vec<u8> = vec![114, 117, 115, 116, 33]; // <4>
+ let mut f3 = File::new_with_data("2.txt", &f3_data);
+
+ let mut buffer: Vec<u8> = vec![];
+
+ open(&mut f3);
+ let f3_length = f3.read(&mut buffer); // <5>
+ close(&mut f3);
+
+ let text = String::from_utf8_lossy(&buffer);
+
+ println!("{:?}", f3);
+ println!("{} is {} bytes long", &f3.name, f3_length);
+ println!("{}", text);
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-skeleton-read-trait.rs b/meap/meap-code/ch3/ch3-skeleton-read-trait.rs
new file mode 100644
index 0000000..9189bef
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-skeleton-read-trait.rs
@@ -0,0 +1,21 @@
+#![allow(unused_variables)]
+
+#[derive(Debug)]
+struct File;
+
+trait Read {
+ fn read(self: &Self, save_to: &mut Vec<u8>) -> Result<usize, String>;
+}
+
+impl Read for File {
+ fn read(self: &File, save_to: &mut Vec<u8>) -> Result<usize, String> {
+ Ok(0)
+ }
+}
+
+fn main() {
+ let f = File{};
+ let mut buffer = vec!();
+ let n_bytes = f.read(&mut buffer).unwrap();
+ println!("{} byte(s) read from {:?}", n_bytes, f);
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/ch3-string-macro.rs b/meap/meap-code/ch3/ch3-string-macro.rs
new file mode 100644
index 0000000..bc68c58
--- /dev/null
+++ b/meap/meap-code/ch3/ch3-string-macro.rs
@@ -0,0 +1,10 @@
+macro_rules! string {
+ ($x:expr) => (
+ String::from($x);
+ )
+}
+
+fn main() {
+ let s = string!("hello");
+ println!("{}", s);
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/filebasics/Cargo.toml b/meap/meap-code/ch3/filebasics/Cargo.toml
new file mode 100644
index 0000000..1fc7586
--- /dev/null
+++ b/meap/meap-code/ch3/filebasics/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "filebasics"
+version = "0.1.0"
+authors = ["Tim McNamara <code@timmcnamara.co.nz>"]
+
+[dependencies]
diff --git a/meap/meap-code/ch3/filebasics/src/main.rs b/meap/meap-code/ch3/filebasics/src/main.rs
new file mode 100644
index 0000000..e7a11a9
--- /dev/null
+++ b/meap/meap-code/ch3/filebasics/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+ println!("Hello, world!");
+}
diff --git a/meap/meap-code/ch3/fileresult/Cargo.toml b/meap/meap-code/ch3/fileresult/Cargo.toml
new file mode 100644
index 0000000..d5902d0
--- /dev/null
+++ b/meap/meap-code/ch3/fileresult/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "fileresult"
+version = "0.1.0"
+authors = ["Tim McNamara <code@timmcnamara.co.nz>"]
+
+[dependencies]
+rand = "0.3" \ No newline at end of file
diff --git a/meap/meap-code/ch3/fileresult/src/main.rs b/meap/meap-code/ch3/fileresult/src/main.rs
new file mode 100644
index 0000000..c02d959
--- /dev/null
+++ b/meap/meap-code/ch3/fileresult/src/main.rs
@@ -0,0 +1,65 @@
+extern crate rand; // <1>
+use rand::Rng; // <2>
+
+fn one_in(n: u32) -> bool { // <3>
+ rand::thread_rng().gen_weighted_bool(n)
+}
+
+#[derive(Debug)]
+struct File {
+ name: String,
+ data: Vec<u8>,
+}
+
+impl File {
+ fn new(name: &str) -> File {
+ File { name: String::from(name), data: Vec::new() } // <4>
+ }
+
+ fn new_with_data(name: &str, data: &Vec<u8>) -> File {
+ let mut f = File::new(name);
+ f.data = data.clone();
+ f
+ }
+
+ fn read(self: &File, save_to: &mut Vec<u8>) -> Result<usize, String> { // <5>
+ let mut tmp = self.data.clone();
+ let read_length = tmp.len();
+ save_to.reserve(read_length);
+ save_to.append(&mut tmp);
+ Ok(read_length) // <6>
+ }
+}
+
+fn open(f: File) -> Result<File, String> {
+ if one_in(10_000) { // <7>
+ let err_msg = String::from("Permission denied");
+ return Err(err_msg);
+ }
+ Ok(f)
+}
+
+fn close(f: File) -> Result<File, String> {
+ if one_in(100_000) { // <8>
+ let err_msg = String::from("Interrupted by signal!");
+ return Err(err_msg);
+ }
+ Ok(f)
+}
+
+fn main() {
+ let f4_data: Vec<u8> = vec![114, 117, 115, 116, 33];
+ let mut f4 = File::new_with_data("4.txt", &f4_data);
+
+ let mut buffer: Vec<u8> = vec![];
+
+ f4 = open(f4).unwrap(); // <9>
+ let f4_length = f4.read(&mut buffer).unwrap(); // <9>
+ f4 = close(f4).unwrap(); // <9>
+
+ let text = String::from_utf8_lossy(&buffer);
+
+ println!("{:?}", f4);
+ println!("{} is {} bytes long", &f4.name, f4_length);
+ println!("{}", text);
+} \ No newline at end of file
diff --git a/meap/meap-code/ch3/globalerror/Cargo.toml b/meap/meap-code/ch3/globalerror/Cargo.toml
new file mode 100644
index 0000000..7300db2
--- /dev/null
+++ b/meap/meap-code/ch3/globalerror/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "globalerror"
+version = "0.1.0"
+authors = ["Tim McNamara <code@timmcnamara.co.nz>"]
+
+[dependencies]
+rand = "0.3"
diff --git a/meap/meap-code/ch3/globalerror/src/main.rs b/meap/meap-code/ch3/globalerror/src/main.rs
new file mode 100644
index 0000000..c3db4cb
--- /dev/null
+++ b/meap/meap-code/ch3/globalerror/src/main.rs
@@ -0,0 +1,30 @@
+extern crate rand;
+use ::rand::Rng;
+
+static mut ERROR: isize = 0;
+
+struct File;
+
+#[allow(unused_variables)]
+fn read(f: &File, save_to: Vec<u8>) -> usize {
+ if rand::thread_rng().gen_weighted_bool(10_000) {
+ unsafe {
+ ERROR = 1;
+ }
+ }
+
+ 0 // <> Always read() 0 bytes
+}
+
+#[allow(unused_mut)]
+fn main() {
+ let mut f = File;
+ let mut buffer = vec![];
+
+ read(&f, buffer);
+ unsafe {
+ if ERROR != 0 {
+ panic!("An error has occurred!")
+ }
+ }
+} \ No newline at end of file