Add solution to Chapter 6 in separate folder

master
Andrew Johnson 6 years ago
parent caa0ea418c
commit de931dbe20

@ -0,0 +1,2 @@
Cargo.lock
target/

@ -0,0 +1,13 @@
[package]
name = "elevator_coding"
version = "1.0.0"
build = "build.rs"
[dependencies]
floating-duration = "0.1.2"
termion = "1.0"
timebomb = "0.1"
serde = "1.0"
serde_json = "1.0"
serde_derive = "1.0"
libc = "0.2"

@ -0,0 +1,17 @@
use std::process::Command;
use std::env;
use std::path::Path;
fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
Command::new("gcc").args(&["src/elevator_magic.c", "-c", "-fPIC", "-o"])
.arg(&format!("{}/elevator_magic.o", out_dir))
.status().unwrap();
Command::new("ar").args(&["crus", "libelevatormagic.a", "elevator_magic.o"])
.current_dir(&Path::new(&out_dir))
.status().unwrap();
println!("cargo:rustc-link-search=native={}", out_dir);
println!("cargo:rustc-link-lib=static=elevatormagic");
}

@ -0,0 +1,186 @@
use magic;
use libc::c_void;
use std::rc::Rc;
pub enum OverrideCode {
IssueOverride = 1,
IssuePrivileged = 2,
IssueAdmin = 3,
IssueInputFloor = 4,
IssueManualMode = 5,
IssueNormalMode = 6,
IssueFlash = 7,
IssueToggleLight = 8,
IssueSetLightColor = 9,
}
pub fn toOverrideCode(i: i32) -> OverrideCode {
match i {
1 => OverrideCode::IssueOverride,
2 => OverrideCode::IssuePrivileged,
3 => OverrideCode::IssueAdmin,
4 => OverrideCode::IssueInputFloor,
5 => OverrideCode::IssueManualMode,
6 => OverrideCode::IssueNormalMode,
7 => OverrideCode::IssueFlash,
8 => OverrideCode::IssueToggleLight,
9 => OverrideCode::IssueSetLightColor,
_ => panic!("Unexpected override code: {}", i)
}
}
pub enum ErrorCode {
DoubleAuthorize = 1,
DoubleFree = 2,
AccessDenied = 3,
}
pub fn toErrorCode(i: i32) -> ErrorCode {
match i {
1 => ErrorCode::DoubleAuthorize,
2 => ErrorCode::DoubleFree,
3 => ErrorCode::AccessDenied,
_ => panic!("Unexpected error code: {}", i)
}
}
pub struct AuthorizedSessionRaw(*const c_void);
#[derive(Clone)]
pub struct AuthorizedSession
{
session: Rc<AuthorizedSessionRaw>
}
impl Drop for AuthorizedSessionRaw {
fn drop(&mut self) {
unsafe {
magic::free_override_session(self.0);
}
}
}
pub fn authorize_override() -> Result<AuthorizedSession,ErrorCode> {
if is_override() || is_privileged() || is_admin() {
return Result::Err(ErrorCode::DoubleAuthorize)
}
let session = unsafe {
magic::issue_override_code(OverrideCode::IssueOverride as i32);
magic::poll_override_session()
};
let session = AuthorizedSession {
session: Rc::new(AuthorizedSessionRaw(session))
};
check_error(session)
}
pub fn authorize_privileged() -> Result<AuthorizedSession,ErrorCode> {
if is_override() || is_privileged() || is_admin() {
return Result::Err(ErrorCode::DoubleAuthorize)
}
let session = unsafe {
magic::issue_override_code(OverrideCode::IssuePrivileged as i32);
magic::poll_physical_override_privileged_session()
};
let session = AuthorizedSession {
session: Rc::new(AuthorizedSessionRaw(session))
};
check_error(session)
}
pub fn authorize_admin() -> Result<AuthorizedSession,ErrorCode> {
if is_override() || is_privileged() || is_admin() {
return Result::Err(ErrorCode::DoubleAuthorize)
}
let session = unsafe {
magic::issue_override_code(OverrideCode::IssueAdmin as i32);
magic::poll_physical_override_admin_session()
};
let session = AuthorizedSession {
session: Rc::new(AuthorizedSessionRaw(session))
};
check_error(session)
}
pub fn reset_state()
{
unsafe {
magic::override_reset_state();
}
}
pub fn check_error<T>(t: T) -> Result<T,ErrorCode>
{
let err = unsafe {
magic::poll_override_error()
};
if err==0 {
Result::Ok(t)
} else {
Result::Err(toErrorCode(err))
}
}
pub fn input_floor(floor: i32) -> Result<(),ErrorCode>
{
unsafe {
magic::override_input_floor(floor);
}
check_error(())
}
pub fn manual_mode() -> Result<(),ErrorCode>
{
unsafe {
magic::override_manual_mode();
}
check_error(())
}
pub fn normal_mode() -> Result<(),ErrorCode>
{
unsafe {
magic::override_normal_mode();
}
check_error(())
}
pub fn flash(pattern: i32) -> Result<(),ErrorCode>
{
unsafe {
magic::elevator_display_flash(pattern);
}
check_error(())
}
pub fn toggle_light(light_id: i32) -> Result<(),ErrorCode>
{
unsafe {
magic::elevator_display_toggle_light(light_id);
}
check_error(())
}
pub fn set_light_color(light_id: i32, color: i32) -> Result<(),ErrorCode>
{
unsafe {
magic::elevator_display_set_light_color(light_id, color);
}
check_error(())
}
pub fn is_override() -> bool
{
unsafe {
magic::is_override() != 0
}
}
pub fn is_privileged() -> bool
{
unsafe {
magic::is_privileged() != 0
}
}
pub fn is_admin() -> bool
{
unsafe {
magic::is_admin() != 0
}
}

@ -0,0 +1,154 @@
int input_codes[3] = {0, 0, 0};
int error_code = 0;
void *active_session = 0;
void *poll_session = 0;
int active_light = 0;
int active_light_toggle = 0;
int is_override() {
return (active_session == ((void*)1));
}
int is_privileged() {
return (active_session == ((void*)2));
}
int is_admin() {
return (active_session == ((void*)3));
}
void issue_override_code(int code) {
input_codes[0] = 0;
input_codes[1] = 0;
input_codes[2] = 0;
input_codes[0] = code;
if( code == 1 ) {
if( active_session == ((void*)0) ) {
active_session = (void*)1;
poll_session = (void*)1;
} else {
active_session = (void*)4;
poll_session = (void*)0;
error_code = 1;
}
} else if( code == 2 ) {
if( active_session == ((void*)0) ) {
active_session = (void*)2;
poll_session = (void*)2;
} else {
active_session = (void*)4;
poll_session = (void*)0;
error_code = 1;
}
} else if( code == 3 ) {
if( active_session == ((void*)0) ) {
active_session = (void*)3;
poll_session = (void*)3;
} else {
active_session = (void*)4;
poll_session = (void*)0;
error_code = 1;
}
}
}
int poll_override_code() {
int code = input_codes[0];
input_codes[0] = input_codes[1];
input_codes[1] = input_codes[2];
input_codes[2] = 0;
return code;
}
int poll_override_input_floor() {
//C Code
return 0;
}
int poll_override_error() {
return error_code;
}
void* poll_override_session() {
return poll_session;
}
void free_override_session(void* session) {
if( active_session == 0 ) {
error_code = 2;
}
active_session = 0;
}
void* poll_physical_override_privileged_session() {
return poll_session;
}
void* poll_physical_override_admin_session() {
return poll_session;
}
void override_input_floor(int floor) {
if(active_session) {
input_codes[0] = 4;
input_codes[1] = floor;
input_codes[2] = 0;
} else {
error_code = 3;
}
}
void override_manual_mode() {
if(active_session) {
input_codes[0] = 5;
input_codes[1] = 0;
input_codes[2] = 0;
} else {
error_code = 3;
}
}
void override_normal_mode() {
if(active_session) {
input_codes[0] = 6;
input_codes[1] = 0;
input_codes[2] = 0;
} else {
error_code = 3;
}
}
void override_reset_state() {
input_codes[0] = 0;
input_codes[1] = 0;
input_codes[2] = 0;
error_code = 0;
active_session = 0;
poll_session = 0;
active_light = 0;
active_light_toggle = 0;
}
void elevator_display_flash(int pattern) {
input_codes[0] = 7;
input_codes[1] = pattern;
input_codes[2] = 0;
}
void elevator_display_toggle_light(int light_id) {
int last_state = 0;
if( active_light == light_id ) {
last_state = active_light_toggle;
}
active_light = light_id;
active_light_toggle = last_state ? 0 : 1;
input_codes[0] = 8;
input_codes[1] = light_id;
input_codes[2] = active_light_toggle;
}
void elevator_display_set_light_color(int light_id, int color) {
input_codes[0] = 9;
input_codes[1] = light_id;
input_codes[2] = color;
}

@ -0,0 +1,6 @@
extern crate libc;
mod magic;
mod admin;
mod tests;

@ -0,0 +1,23 @@
use libc::{c_int, c_void};
#[link(name = "elevatormagic")]
extern {
pub fn issue_override_code(code: c_int);
pub fn poll_override_code() -> c_int;
pub fn poll_override_input_floor() -> c_int;
pub fn poll_override_error() -> c_int;
pub fn poll_override_session() -> *const c_void;
pub fn free_override_session(session: *const c_void);
pub fn poll_physical_override_privileged_session() -> *const c_void;
pub fn poll_physical_override_admin_session() -> *const c_void;
pub fn override_input_floor(floor: c_int);
pub fn override_manual_mode();
pub fn override_normal_mode();
pub fn override_reset_state();
pub fn elevator_display_flash(pattern: c_int);
pub fn elevator_display_toggle_light(light_id: c_int);
pub fn elevator_display_set_light_color(light_id: c_int, color: c_int);
pub fn is_override() -> c_int;
pub fn is_privileged() -> c_int;
pub fn is_admin() -> c_int;
}

@ -0,0 +1,177 @@
use admin;
#[test]
fn authorize_override() {
admin::reset_state();
{
let session = admin::authorize_override().ok();
assert!(admin::is_override());
}
assert!(!admin::is_override());
assert!(admin::check_error(()).is_ok());
}
#[test]
fn authorize_privileged() {
admin::reset_state();
{
let session = admin::authorize_privileged().ok();
assert!(admin::is_privileged());
}
assert!(!admin::is_privileged());
assert!(admin::check_error(()).is_ok());
}
#[test]
fn issue_admin_code() {
admin::reset_state();
{
let session = admin::authorize_admin().ok();
assert!(admin::is_admin());
}
assert!(!admin::is_admin());
assert!(admin::check_error(()).is_ok());
}
#[test]
fn double_override_failure() {
admin::reset_state();
let session = admin::authorize_override().ok();
assert!(admin::authorize_override().err().is_some());
}
#[test]
fn double_privileged_failure() {
admin::reset_state();
let session = admin::authorize_privileged().ok();
assert!(admin::authorize_privileged().err().is_some());
}
#[test]
fn double_admin_failure() {
admin::reset_state();
let session = admin::authorize_admin().ok();
assert!(admin::authorize_admin().err().is_some());
}
#[test]
fn clone_override() {
admin::reset_state();
{
let session = admin::authorize_override().ok().unwrap();
let session2 = session.clone();
assert!(admin::is_override());
}
assert!(!admin::is_override());
assert!(admin::check_error(()).is_ok());
}
#[test]
fn clone_privileged() {
admin::reset_state();
{
let session = admin::authorize_privileged().ok().unwrap();
let session2 = session.clone();
assert!(admin::is_privileged());
}
assert!(!admin::is_privileged());
assert!(admin::check_error(()).is_ok());
}
#[test]
fn clone_admin() {
admin::reset_state();
{
let session = admin::authorize_admin().ok().unwrap();
let session2 = session.clone();
assert!(admin::is_admin());
}
assert!(!admin::is_admin());
assert!(admin::check_error(()).is_ok());
}
#[test]
fn input_floor() {
admin::reset_state();
{
let session = admin::authorize_admin().ok();
admin::input_floor(2).ok();
}
assert!(!admin::is_admin());
assert!(admin::check_error(()).is_ok());
}
#[test]
fn manual_mode() {
admin::reset_state();
{
let session = admin::authorize_admin().ok();
admin::manual_mode().ok();
}
assert!(!admin::is_admin());
assert!(admin::check_error(()).is_ok());
}
#[test]
fn normal_mode() {
admin::reset_state();
{
let session = admin::authorize_admin().ok();
admin::normal_mode().ok();
}
assert!(!admin::is_admin());
assert!(admin::check_error(()).is_ok());
}
#[test]
fn flash() {
admin::reset_state();
assert!(!admin::is_override());
assert!(!admin::is_privileged());
assert!(!admin::is_admin());
admin::flash(222).ok();
assert!(admin::check_error(()).is_ok());
}
#[test]
fn toggle_light() {
admin::reset_state();
assert!(!admin::is_override());
assert!(!admin::is_privileged());
assert!(!admin::is_admin());
admin::toggle_light(7).ok();
assert!(admin::check_error(()).is_ok());
}
#[test]
fn set_light_color() {
admin::reset_state();
assert!(!admin::is_override());
assert!(!admin::is_privileged());
assert!(!admin::is_admin());
admin::set_light_color(33, 123).ok();
assert!(admin::check_error(()).is_ok());
}
#[test]
fn deny_input_floor() {
admin::reset_state();
admin::input_floor(2).err();
assert!(!admin::check_error(()).is_ok());
}
#[test]
fn deny_manual_mode() {
admin::reset_state();
admin::manual_mode().err();
assert!(!admin::check_error(()).is_ok());
}
#[test]
fn deny_normal_mode() {
admin::reset_state();
admin::normal_mode().err();
assert!(!admin::check_error(()).is_ok());
}
#[test]
fn invalid_deauthorization() {
admin::reset_state();
let session = admin::authorize_admin().ok();
assert!(admin::authorize_admin().is_err());
assert!(admin::is_admin());
}

@ -0,0 +1,229 @@
use magic;
use libc::{c_void};
#[test]
fn issue_override_code() {
unsafe {
magic::override_reset_state();
magic::issue_override_code(1);
assert!(magic::poll_override_code() == 1);
assert!(magic::poll_override_error() == 0);
}
}
#[test]
fn issue_privileged_code() {
unsafe {
magic::override_reset_state();
magic::issue_override_code(2);
assert!(magic::poll_override_code() == 2);
assert!(magic::poll_override_error() == 0);
}
}
#[test]
fn issue_admin_code() {
unsafe {
magic::override_reset_state();
magic::issue_override_code(3);
assert!(magic::poll_override_code() == 3);
assert!(magic::poll_override_error() == 0);
}
}
#[test]
fn authorize_override_success() {
unsafe {
magic::override_reset_state();
magic::issue_override_code(1);
let session = magic::poll_override_session();
assert!(session != (0 as *const c_void));
magic::free_override_session(session);
assert!(magic::poll_override_error() == 0);
}
}
#[test]
fn authorize_privileged_success() {
unsafe {
magic::override_reset_state();
magic::issue_override_code(2);
let session = magic::poll_physical_override_privileged_session();
assert!(session != (0 as *const c_void));
magic::free_override_session(session);
assert!(magic::poll_override_error() == 0);
}
}
#[test]
fn authorize_admin_success() {
unsafe {
magic::override_reset_state();
magic::issue_override_code(3);
let session = magic::poll_physical_override_admin_session();
assert!(session != (0 as *const c_void));
magic::free_override_session(session);
assert!(magic::poll_override_error() == 0);
}
}
#[test]
fn double_override_failure() {
unsafe {
magic::override_reset_state();
magic::issue_override_code(1);
magic::issue_override_code(1);
assert!(magic::poll_override_session() == (0 as *const c_void));
assert!(magic::poll_override_error() == 1);
}
}
#[test]
fn double_privileged_failure() {
unsafe {
magic::override_reset_state();
magic::issue_override_code(2);
magic::issue_override_code(2);
assert!(magic::poll_physical_override_privileged_session() == (0 as *const c_void));
assert!(magic::poll_override_error() == 1);
}
}
#[test]
fn double_admin_failure() {
unsafe {
magic::override_reset_state();
magic::issue_override_code(3);
magic::issue_override_code(3);
assert!(magic::poll_physical_override_admin_session() == (0 as *const c_void));
assert!(magic::poll_override_error() == 1);
}
}
#[test]
fn double_free_override_failure() {
unsafe {
magic::override_reset_state();
magic::issue_override_code(1);
let session = magic::poll_override_session();
assert!(session != (0 as *const c_void));
magic::free_override_session(session);
magic::free_override_session(session);
assert!(magic::poll_override_error() == 2);
}
}
#[test]
fn double_free_privileged_failure() {
unsafe {
magic::override_reset_state();
magic::issue_override_code(2);
let session = magic::poll_physical_override_privileged_session();
assert!(session != (0 as *const c_void));
magic::free_override_session(session);
magic::free_override_session(session);
assert!(magic::poll_override_error() == 2);
}
}
#[test]
fn double_free_admin_failure() {
unsafe {
magic::override_reset_state();
magic::issue_override_code(3);
let session = magic::poll_physical_override_admin_session();
assert!(session != (0 as *const c_void));
magic::free_override_session(session);
magic::free_override_session(session);
assert!(magic::poll_override_error() == 2);
}
}
#[test]
fn input_floor() {
unsafe {
magic::override_reset_state();
magic::issue_override_code(3);
magic::override_input_floor(2);
assert!(magic::poll_override_code() == 4);
assert!(magic::poll_override_code() == 2);
assert!(magic::poll_override_error() == 0);
}
}
#[test]
fn manual_mode() {
unsafe {
magic::override_reset_state();
magic::issue_override_code(3);
magic::override_manual_mode();
assert!(magic::poll_override_code() == 5);
assert!(magic::poll_override_error() == 0);
}
}
#[test]
fn normal_mode() {
unsafe {
magic::override_reset_state();
magic::issue_override_code(3);
magic::override_normal_mode();
assert!(magic::poll_override_code() == 6);
assert!(magic::poll_override_error() == 0);
}
}
#[test]
fn flash() {
unsafe {
magic::override_reset_state();
magic::elevator_display_flash(222);
assert!(magic::poll_override_code() == 7);
assert!(magic::poll_override_code() == 222);
}
}
#[test]
fn toggle_light() {
unsafe {
magic::override_reset_state();
magic::elevator_display_toggle_light(33);
assert!(magic::poll_override_code() == 8);
assert!(magic::poll_override_code() == 33);
assert!(magic::poll_override_code() == 1);
magic::elevator_display_toggle_light(33);
assert!(magic::poll_override_code() == 8);
assert!(magic::poll_override_code() == 33);
assert!(magic::poll_override_code() == 0);
}
}
#[test]
fn set_light_color() {
unsafe {
magic::override_reset_state();
magic::elevator_display_set_light_color(33, 222);
assert!(magic::poll_override_code() == 9);
assert!(magic::poll_override_code() == 33);
assert!(magic::poll_override_code() == 222);
}
}
#[test]
fn deny_input_floor() {
unsafe {
magic::override_reset_state();
magic::override_input_floor(2);
assert!(magic::poll_override_error() == 3);
}
}
#[test]
fn deny_manual_mode() {
unsafe {
magic::override_reset_state();
magic::override_manual_mode();
assert!(magic::poll_override_error() == 3);
}
}
#[test]
fn deny_normal_mode() {
unsafe {
magic::override_reset_state();
magic::override_manual_mode();
assert!(magic::poll_override_error() == 3);
}
}

@ -0,0 +1,3 @@
mod magic;
mod admin;
Loading…
Cancel
Save