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/ch3/ch3-adding-pub-to-file.rs | 28 +++++++++ meap/meap-code/ch3/ch3-anystring-macro.rs | 10 ++++ meap/meap-code/ch3/ch3-defining-files-neatly.rs | 29 ++++++++++ meap/meap-code/ch3/ch3-defining-files.rs | 18 ++++++ meap/meap-code/ch3/ch3-error-1.rs | 30 ++++++++++ meap/meap-code/ch3/ch3-file-doced.rs | 38 +++++++++++++ meap/meap-code/ch3/ch3-file-states.rs | 59 +++++++++++++++++++ meap/meap-code/ch3/ch3-files-with-modes.rs | 75 +++++++++++++++++++++++++ meap/meap-code/ch3/ch3-implementing-display.rs | 49 ++++++++++++++++ meap/meap-code/ch3/ch3-mock-file.rs | 18 ++++++ meap/meap-code/ch3/ch3-newtype-pattern.rs | 10 ++++ meap/meap-code/ch3/ch3-not-quite-file-1.rs | 23 ++++++++ meap/meap-code/ch3/ch3-not-quite-file-2.rs | 42 ++++++++++++++ meap/meap-code/ch3/ch3-not-quite-file-3.rs | 55 ++++++++++++++++++ meap/meap-code/ch3/ch3-not-quite-file-4.rs | 42 ++++++++++++++ meap/meap-code/ch3/ch3-parse-log.rs | 35 ++++++++++++ meap/meap-code/ch3/ch3-public-file.rs | 33 +++++++++++ meap/meap-code/ch3/ch3-return-result.rs | 68 ++++++++++++++++++++++ meap/meap-code/ch3/ch3-skeleton-read-trait.rs | 21 +++++++ meap/meap-code/ch3/ch3-string-macro.rs | 10 ++++ meap/meap-code/ch3/filebasics/Cargo.toml | 6 ++ meap/meap-code/ch3/filebasics/src/main.rs | 3 + meap/meap-code/ch3/fileresult/Cargo.toml | 7 +++ meap/meap-code/ch3/fileresult/src/main.rs | 65 +++++++++++++++++++++ meap/meap-code/ch3/globalerror/Cargo.toml | 7 +++ meap/meap-code/ch3/globalerror/src/main.rs | 30 ++++++++++ 26 files changed, 811 insertions(+) create mode 100644 meap/meap-code/ch3/ch3-adding-pub-to-file.rs create mode 100644 meap/meap-code/ch3/ch3-anystring-macro.rs create mode 100644 meap/meap-code/ch3/ch3-defining-files-neatly.rs create mode 100644 meap/meap-code/ch3/ch3-defining-files.rs create mode 100644 meap/meap-code/ch3/ch3-error-1.rs create mode 100644 meap/meap-code/ch3/ch3-file-doced.rs create mode 100644 meap/meap-code/ch3/ch3-file-states.rs create mode 100644 meap/meap-code/ch3/ch3-files-with-modes.rs create mode 100644 meap/meap-code/ch3/ch3-implementing-display.rs create mode 100644 meap/meap-code/ch3/ch3-mock-file.rs create mode 100644 meap/meap-code/ch3/ch3-newtype-pattern.rs create mode 100644 meap/meap-code/ch3/ch3-not-quite-file-1.rs create mode 100644 meap/meap-code/ch3/ch3-not-quite-file-2.rs create mode 100644 meap/meap-code/ch3/ch3-not-quite-file-3.rs create mode 100644 meap/meap-code/ch3/ch3-not-quite-file-4.rs create mode 100644 meap/meap-code/ch3/ch3-parse-log.rs create mode 100644 meap/meap-code/ch3/ch3-public-file.rs create mode 100644 meap/meap-code/ch3/ch3-return-result.rs create mode 100644 meap/meap-code/ch3/ch3-skeleton-read-trait.rs create mode 100644 meap/meap-code/ch3/ch3-string-macro.rs create mode 100644 meap/meap-code/ch3/filebasics/Cargo.toml create mode 100644 meap/meap-code/ch3/filebasics/src/main.rs create mode 100644 meap/meap-code/ch3/fileresult/Cargo.toml create mode 100644 meap/meap-code/ch3/fileresult/src/main.rs create mode 100644 meap/meap-code/ch3/globalerror/Cargo.toml create mode 100644 meap/meap-code/ch3/globalerror/src/main.rs (limited to 'meap/meap-code/ch3') 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, + 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, +} + +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::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, // <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) -> 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, +} + +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, + 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) -> Result { + 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 { + f.state = FileState::Open; + Ok(f) +} + +fn close(mut f: File) -> Result { + f.state = FileState::Closed; + Ok(f) +} + +fn main() { + let mut f5 = File::new("5.txt"); + + let mut buffer: Vec = 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, + 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, + 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, // <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) -> ! { // <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, +} + +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) -> 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 = 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` 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, +} + +impl File { + fn new(name: &str) -> File { + File { + name: String::from(name), + data: Vec::new(), + } + } + + fn new_with_data(name: &str, data: &Vec) -> 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) -> 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 = 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 = 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, // <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) { + (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` + 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, // <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, +} + +impl File { + fn new(name: &str) -> File { + File { + name: String::from(name), + data: Vec::new(), + } + } + + fn new_with_data(name: &str, data: &Vec) -> File { // <1> + let mut f = File::new(name); + f.data = data.clone(); + f + } + + fn read(self: &File, save_to: &mut Vec) -> 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 { + if one_in_(10_000) { + return Err(String::from("Permission denied")) + } + Some(f) +} + +fn close(f: &mut File) -> Result { + if one_in_(100_000) { + return Err(String::from("Interrupted by signal!")) + } + Some(f) +} + +fn main() { + let f3_data: Vec = vec![114, 117, 115, 116, 33]; // <4> + let mut f3 = File::new_with_data("2.txt", &f3_data); + + let mut buffer: Vec = 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) -> Result; +} + +impl Read for File { + fn read(self: &File, save_to: &mut Vec) -> Result { + 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 "] + +[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 "] + +[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, +} + +impl File { + fn new(name: &str) -> File { + File { name: String::from(name), data: Vec::new() } // <4> + } + + fn new_with_data(name: &str, data: &Vec) -> File { + let mut f = File::new(name); + f.data = data.clone(); + f + } + + fn read(self: &File, save_to: &mut Vec) -> Result { // <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 { + if one_in(10_000) { // <7> + let err_msg = String::from("Permission denied"); + return Err(err_msg); + } + Ok(f) +} + +fn close(f: File) -> Result { + 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 = vec![114, 117, 115, 116, 33]; + let mut f4 = File::new_with_data("4.txt", &f4_data); + + let mut buffer: Vec = 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 "] + +[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) -> 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 -- cgit v1.2.3