Created
October 27, 2016 04:15
-
-
Save hjr3/a77ee17c792890bed37b270d3dbd1b97 to your computer and use it in GitHub Desktop.
Rust Belt Rust: Building Better Function Interfaces Workshop - Exercise 2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::borrow::{Borrow, BorrowMut, Cow}; | |
use std::mem; | |
#[derive(Eq, PartialEq, Debug, Clone)] | |
pub struct NameString { | |
inner: String, | |
} | |
impl NameString { | |
pub fn from_str(s: &str) -> NameString { | |
NameString { | |
inner: s.to_string() | |
} | |
} | |
pub fn uppercase(&mut self) { | |
self.inner = self.inner.to_uppercase(); | |
} | |
// TODO: Write a lowercase function to be used by `NameStr::to_lowercase`. | |
pub fn lowercase(&mut self) { | |
unimplemented!() | |
} | |
} | |
impl Borrow<NameStr> for NameString { | |
fn borrow(&self) -> &NameStr { | |
unsafe { mem::transmute(& *self.inner) } | |
} | |
} | |
impl BorrowMut<NameStr> for NameString { | |
fn borrow_mut(&mut self) -> &mut NameStr { | |
unsafe { mem::transmute(&mut *self.inner) } | |
} | |
} | |
#[derive(Eq, PartialEq, Debug)] | |
pub struct NameStr { | |
// allowed per https://doc.rust-lang.org/book/unsized-types.html | |
inner: str, | |
} | |
impl NameStr { | |
pub fn new(name: &str) -> &NameStr { | |
unsafe { mem::transmute(name) } | |
} | |
pub fn to_name_string(&self) -> NameString { | |
NameString { | |
inner: self.inner.to_string() | |
} | |
} | |
pub fn to_uppercase(&self) -> Cow<NameStr> { | |
if self.inner.chars().all(|b| b.is_uppercase()) { | |
Cow::Borrowed(self) | |
} else { | |
let mut name_string = self.to_name_string(); | |
name_string.uppercase(); | |
Cow::Owned(name_string) | |
} | |
} | |
// TODO: Write a `NameStr::to_lowercase` function. | |
pub fn to_lowercase(&self) -> Cow<NameStr> { | |
unimplemented!() | |
} | |
} | |
impl ToOwned for NameStr { | |
type Owned = NameString; | |
fn to_owned(&self) -> NameString { | |
self.to_name_string() | |
} | |
} | |
#[derive(Debug, Eq, PartialEq)] | |
pub struct Roster<'a> { | |
pub names: Vec<Cow<'a, NameStr>>, | |
} | |
impl<'a> Roster<'a> { | |
pub fn new() -> Roster<'a> { | |
Roster { | |
names: Vec::new(), | |
} | |
} | |
// TODO: Implement `Roster::with_names()`. | |
pub fn with_names(names: Vec<&'a NameStr>) -> Roster<'a> { | |
unimplemented!() | |
} | |
pub fn add_name(&mut self, name: &'a NameStr) { | |
self.names.push(name.to_uppercase()) | |
} | |
} | |
#[derive(Debug, Eq, PartialEq)] | |
pub struct Student { | |
name: NameString, | |
seat: usize, | |
} | |
impl Student { | |
pub fn new<I>(name: I, seat: usize) -> Student | |
where I: Into<NameString> | |
{ | |
Student { | |
name: name.into(), | |
seat: seat, | |
} | |
} | |
pub fn name(&self) -> &NameString { | |
&self.name | |
} | |
} | |
pub struct InClass<T> { | |
inner: T, | |
} | |
impl<T> InClass<T> { | |
pub fn rest(self) -> Home<T> { | |
// TODO: Implement a new function for the `InClass` struct called `rest` | |
// that changes a student to a new state caled `Home`. | |
unimplemented!() | |
} | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
use std::borrow::Cow; | |
#[test] | |
fn test_name_string_lowercase() { | |
let expected = NameString::from_str("name"); | |
let mut given = NameString:: from_str("Name"); | |
given.lowercase(); | |
assert_eq!(expected, given); | |
} | |
#[test] | |
fn test_name_str_to_lowercase() { | |
let lc_name_str = NameStr::new("name"); | |
assert_eq!(Cow::Borrowed(lc_name_str), lc_name_str.to_lowercase()); | |
let uc_name_string: Cow<NameStr> = Cow::Owned(lc_name_str.to_owned()); | |
let mixed_case_name_str = NameStr::new("Name"); | |
assert_eq!(uc_name_string, mixed_case_name_str.to_lowercase()); | |
} | |
#[test] | |
fn test_roster_with_names() { | |
let names = vec![NameStr::new("Grace Hopper"), NameStr::new("Ada Lovelace")]; | |
let given = Roster::with_names(names); | |
let mut expected = Roster::new(); | |
expected.add_name(NameStr::new("Grace Hopper")); | |
expected.add_name(NameStr::new("Ada Lovelace")); | |
assert_eq!(expected, given); | |
} | |
#[test] | |
fn test_student_state_change_home() { | |
let me = Student::new(NameString::from_str("Herman"), 0); | |
let me_in_class = InClass { inner: me }; | |
let me_at_home = me_in_class.rest(); | |
let _me_back_in_class = me_at_home.learn(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment