Skip to content

Instantly share code, notes, and snippets.

@hjr3
Created October 27, 2016 04:15
Show Gist options
  • Save hjr3/a77ee17c792890bed37b270d3dbd1b97 to your computer and use it in GitHub Desktop.
Save hjr3/a77ee17c792890bed37b270d3dbd1b97 to your computer and use it in GitHub Desktop.
Rust Belt Rust: Building Better Function Interfaces Workshop - Exercise 2
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