<commit_before>extern crate ffmpeg;

use std::path::Path;

use std::rc::Weak;
use std::rc::Rc;
use std::cell::RefCell;

pub trait VideoNotifiable {
    fn new_video_frame(&mut self, ffmpeg::frame::Video);
}
pub trait AudioNotifiable {
    fn new_audio_frame(&mut self, ffmpeg::frame::Audio);
}

pub struct Context {
    pub ffmpeg_context: ffmpeg::format::context::Input,
    pub path: String,
    pub name: String,
    pub description: String,

    pub video_stream: Option<usize>,
    pub video_decoder: Option<ffmpeg::codec::decoder::Video>,
    pub video_notifiable: Option<Weak<RefCell<VideoNotifiable>>>,

    pub audio_stream: Option<usize>,
    pub audio_decoder: Option<ffmpeg::codec::decoder::Audio>,
    pub audio_notifiable: Option<Weak<RefCell<AudioNotifiable>>>,
}

fn print_packet_content(stream: &ffmpeg::format::stream::Stream, packet: &ffmpeg::codec::packet::Packet) {
    println!("\n* Packet for {:?} stream: {}", stream.disposition(), stream.index());
    println!("\tsize: {} - duration: {}, is key: {}",
             packet.size(), packet.duration(), packet.is_key(),
    );
    match packet.pts() {
        Some(pts) => println!("\tpts: {}", pts),
        None => (),
    }
    match packet.dts() {
        Some(dts) => println!("\tdts: {}", dts),
        None => (),
    }
    if let Some(ref data) = packet.data() {
        println!("\tfound data with len: {}", data.len());
    }
    let side_data_iter = stream.side_data();
    let side_data_len = side_data_iter.size_hint().0;
    if side_data_len > 0 {
        println!("\tside data nb: {}", side_data_len);
    }
}

impl Context {
    pub fn new(path: &Path) -> Result<Context, String> {
        match ffmpeg::format::input(&path) {
            Ok(ffmpeg_context) => {
                let mut new_ctx = Context{
                    ffmpeg_context: ffmpeg_context,
                    path: String::from(path.to_str().unwrap()),
                    name: String::new(),
                    description: String::new(),

                    video_stream: None,
                    video_decoder: None,
                    video_notifiable: None,

                    audio_stream: None,
                    audio_decoder: None,
                    audio_notifiable: None,
                };

                {
                    let format = new_ctx.ffmpeg_context.format();
                    new_ctx.name = String::from(format.name());
                    new_ctx.description = String::from(format.description());

                    new_ctx.init_video_decoder();
                    new_ctx.init_audio_decoder();
                }

                // TODO: process metadata

                // TODO: see what we should do with subtitles

                println!("\n*** New media - Input: {} - {}", &new_ctx.name, &new_ctx.description);

                //new_ctx.preview();

                if new_ctx.video_stream.is_some() || new_ctx.audio_stream.is_some() {
                    // TODO: also check for misdetections (detection score)
                    Ok(new_ctx)
                }
                else {
                    Err("Couldn't find any video or audio stream".to_owned())
                }
            },
            Err(error) => {
                Err(format!("{:?}", error))
            },
        }
    }

    pub fn init_video_decoder(&mut self) {
        let stream_index;
        let stream = match self.ffmpeg_context.streams().best(ffmpeg::media::Type::Video) {
            Some(best_stream) => {
                stream_index = best_stream.index();
                println!("\nFound video stream with id: {}", stream_index);
                best_stream
            },
            None => {
                println!("No video stream");
                return;
            },
        };

        match stream.codec().decoder().video() {
            Ok(mut decoder) => {
                match decoder.set_parameters(stream.parameters()) {
                    Ok(_) => {
                        println!("\tinitialzed video decoder: {:?}", decoder.format());
                    },
                    Err(error) => panic!("Failed to set parameters for video decoder: {:?}", error),
                }

                println!("\tvideo decoder: {:?}, width: {}, height: {}",
                         decoder.format(), decoder.width(), decoder.height());
                self.video_stream = Some(stream_index);
                self.video_decoder = Some(decoder);
            },
            Err(error) => panic!("Failed to get video decoder: {:?}", error),
        }
    }

    pub fn init_audio_decoder(&mut self) {
        let stream_index;
        let stream = match self.ffmpeg_context.streams().best(ffmpeg::media::Type::Audio) {
            Some(best_stream) => {
                stream_index = best_stream.index();
                println!("\nFound audio stream with id: {}", stream_index);
                best_stream
            },
            None => {
                println!("No audio stream");
                return;
            },
        };

        match stream.codec().decoder().audio() {
            Ok(mut decoder) => {
                match decoder.set_parameters(stream.parameters()) {
                    Ok(_) => {
                        println!("\tinitialzed audio decoder: {:?} - channels: {}", decoder.format(), decoder.channels());
                    },
                    Err(error) => panic!("Failed to set parameters for audio decoder: {:?}", error),
                }
                println!("\taudio decoder: {:?}, channels: {}, frame count: {}",
                         decoder.format(), decoder.channels(), decoder.frames());
                self.audio_stream = Some(stream_index);
                self.audio_decoder = Some(decoder);
            },
            Err(error) => panic!("Failed to get audio decoder: {:?}", error),
        }
    }

    pub fn register_video_notifiable(&mut self, notifiable: Rc<RefCell<VideoNotifiable>>) {
        self.video_notifiable = Some(Rc::downgrade(&notifiable));
    }

    pub fn register_audio_notifiable(&mut self, notifiable: Rc<RefCell<AudioNotifiable>>) {
        self.audio_notifiable = Some(Rc::downgrade(&notifiable));
    }

    pub fn preview(&mut self) {
        // TODO: better trace streams processed (use a HashSet as before)
        let mut frames_processed = 0;
        let mut expected_frames = 0;
        if self.video_stream.is_some() {
            expected_frames += 1;
        }
        if self.audio_stream.is_some() {
            expected_frames += 1;
        }

        let mut video_frame = ffmpeg::frame::Video::empty();
        let mut audio_frame = ffmpeg::frame::Audio::empty();

        for (stream, packet) in self.ffmpeg_context.packets() {
            print_packet_content(&stream, &packet);
            let mut got_frame = false;
            let decoder = stream.codec().decoder();
            match decoder.medium() {
                ffmpeg::media::Type::Video => match self.video_stream {
                    Some(stream_index) => {
                        if stream_index == stream.index() {
                            let mut video = match self.video_decoder {
                                Some(ref mut decoder) => decoder,
                                None => panic!("Error getting video decoder for stream {}", stream_index),
                            };
                            match video.decode(&packet, &mut video_frame) {
                                Ok(decode_got_frame) =>  {
                                    got_frame = decode_got_frame;
                                    let planes = video_frame.planes();
                                    println!("\tdecoded video frame, found {} planes - got frame: {}", planes, got_frame);
                                    for index in 0..planes {
                                        println!("\tplane: {} - data len: {}", index, video_frame.data(index).len());
                                    }
                                },
                                Err(error) => println!("Error decoding video packet for stream {}: {:?}", stream_index, error),
                            }
                            if got_frame {
                                frames_processed += 1;
                                match self.video_notifiable.as_ref() {
                                    Some(notifiable_weak) => {
                                        match notifiable_weak.upgrade() {
                                            Some(notifiable) => {
                                                notifiable.borrow_mut().new_video_frame(video_frame);
                                                video_frame = ffmpeg::frame::Video::empty();
                                            },
                                            None => (),
                                        }
                                    },
                                    None => (),
                                }
                            }
                        }
                        else {
                            println!("Skipping stream {}", stream.index());
                        }
                    },
                    None => panic!("No video decoder"),
                },
                ffmpeg::media::Type::Audio => match self.audio_stream {
                    Some(stream_index) => {
                        if stream_index == stream.index() {
                            let ref mut audio = match self.audio_decoder.as_mut() {
                                Some(decoder) => decoder,
                                None => panic!("Error getting audio decoder for stream {}", stream_index),
                            };
                            match audio.decode(&packet, &mut audio_frame) {
                                Ok(decode_got_frame) =>  {
                                    got_frame = decode_got_frame;
                                    let planes = audio_frame.planes();
                                    println!("\tdecoded audio frame, found {} planes - got frame: {}", planes, got_frame);
                                    for index in 0..planes {
                                        println!("\tplane: {} - data len: {}", index, audio_frame.data(index).len());
                                    }
                                },
                                Err(error) => panic!("Error decoding audio packet for stream {}: {:?}", stream_index, error),
                            }
                            if got_frame {
                                frames_processed += 1;
                                match self.audio_notifiable.as_ref() {
                                    Some(notifiable_weak) => {
                                        match notifiable_weak.upgrade() {
                                            Some(notifiable) => {
                                                notifiable.borrow_mut().new_audio_frame(audio_frame);
                                                audio_frame = ffmpeg::frame::Audio::empty();
                                            },
                                            None => (),
                                        }
                                    },
                                    None => (),
                                }
                            }
                        }
                        else {
                            println!("Skipping stream {}", stream.index());
                        }
                    },
                    None => panic!("No audio decoder"),
                },
                _ => (),
            }

            if frames_processed == expected_frames {
                break;
            }
        }
    }
}
<commit_msg>Fixed processed streams tracking (#1)<commit_after>extern crate ffmpeg;

use std::path::Path;

use std::collections::HashSet;

use std::rc::Weak;
use std::rc::Rc;
use std::cell::RefCell;

pub trait VideoNotifiable {
    fn new_video_frame(&mut self, ffmpeg::frame::Video);
}
pub trait AudioNotifiable {
    fn new_audio_frame(&mut self, ffmpeg::frame::Audio);
}

pub struct Context {
    pub ffmpeg_context: ffmpeg::format::context::Input,
    pub path: String,
    pub name: String,
    pub description: String,

    pub video_stream: Option<usize>,
    pub video_decoder: Option<ffmpeg::codec::decoder::Video>,
    pub video_notifiable: Option<Weak<RefCell<VideoNotifiable>>>,

    pub audio_stream: Option<usize>,
    pub audio_decoder: Option<ffmpeg::codec::decoder::Audio>,
    pub audio_notifiable: Option<Weak<RefCell<AudioNotifiable>>>,
}

fn print_packet_content(stream: &ffmpeg::format::stream::Stream, packet: &ffmpeg::codec::packet::Packet) {
    println!("\n* Packet for {:?} stream: {}", stream.disposition(), stream.index());
    println!("\tsize: {} - duration: {}, is key: {}",
             packet.size(), packet.duration(), packet.is_key(),
    );
    match packet.pts() {
        Some(pts) => println!("\tpts: {}", pts),
        None => (),
    }
    match packet.dts() {
        Some(dts) => println!("\tdts: {}", dts),
        None => (),
    }
    if let Some(ref data) = packet.data() {
        println!("\tfound data with len: {}", data.len());
    }
    let side_data_iter = stream.side_data();
    let side_data_len = side_data_iter.size_hint().0;
    if side_data_len > 0 {
        println!("\tside data nb: {}", side_data_len);
    }
}

impl Context {
    pub fn new(path: &Path) -> Result<Context, String> {
        match ffmpeg::format::input(&path) {
            Ok(ffmpeg_context) => {
                let mut new_ctx = Context{
                    ffmpeg_context: ffmpeg_context,
                    path: String::from(path.to_str().unwrap()),
                    name: String::new(),
                    description: String::new(),

                    video_stream: None,
                    video_decoder: None,
                    video_notifiable: None,

                    audio_stream: None,
                    audio_decoder: None,
                    audio_notifiable: None,
                };

                {
                    let format = new_ctx.ffmpeg_context.format();
                    new_ctx.name = String::from(format.name());
                    new_ctx.description = String::from(format.description());

                    new_ctx.init_video_decoder();
                    new_ctx.init_audio_decoder();
                }

                // TODO: process metadata

                // TODO: see what we should do with subtitles

                println!("\n*** New media - Input: {} - {}", &new_ctx.name, &new_ctx.description);

                //new_ctx.preview();

                if new_ctx.video_stream.is_some() || new_ctx.audio_stream.is_some() {
                    // TODO: also check for misdetections (detection score)
                    Ok(new_ctx)
                }
                else {
                    Err("Couldn't find any video or audio stream".to_owned())
                }
            },
            Err(error) => {
                Err(format!("{:?}", error))
            },
        }
    }

    pub fn init_video_decoder(&mut self) {
        let stream_index;
        let stream = match self.ffmpeg_context.streams().best(ffmpeg::media::Type::Video) {
            Some(best_stream) => {
                stream_index = best_stream.index();
                println!("\nFound video stream with id: {}", stream_index);
                best_stream
            },
            None => {
                println!("No video stream");
                return;
            },
        };

        match stream.codec().decoder().video() {
            Ok(mut decoder) => {
                match decoder.set_parameters(stream.parameters()) {
                    Ok(_) => {
                        println!("\tinitialzed video decoder: {:?}", decoder.format());
                    },
                    Err(error) => panic!("Failed to set parameters for video decoder: {:?}", error),
                }

                println!("\tvideo decoder: {:?}, width: {}, height: {}",
                         decoder.format(), decoder.width(), decoder.height());
                self.video_stream = Some(stream_index);
                self.video_decoder = Some(decoder);
            },
            Err(error) => panic!("Failed to get video decoder: {:?}", error),
        }
    }

    pub fn init_audio_decoder(&mut self) {
        let stream_index;
        let stream = match self.ffmpeg_context.streams().best(ffmpeg::media::Type::Audio) {
            Some(best_stream) => {
                stream_index = best_stream.index();
                println!("\nFound audio stream with id: {}", stream_index);
                best_stream
            },
            None => {
                println!("No audio stream");
                return;
            },
        };

        match stream.codec().decoder().audio() {
            Ok(mut decoder) => {
                match decoder.set_parameters(stream.parameters()) {
                    Ok(_) => {
                        println!("\tinitialzed audio decoder: {:?} - channels: {}", decoder.format(), decoder.channels());
                    },
                    Err(error) => panic!("Failed to set parameters for audio decoder: {:?}", error),
                }
                println!("\taudio decoder: {:?}, channels: {}, frame count: {}",
                         decoder.format(), decoder.channels(), decoder.frames());
                self.audio_stream = Some(stream_index);
                self.audio_decoder = Some(decoder);
            },
            Err(error) => panic!("Failed to get audio decoder: {:?}", error),
        }
    }

    pub fn register_video_notifiable(&mut self, notifiable: Rc<RefCell<VideoNotifiable>>) {
        self.video_notifiable = Some(Rc::downgrade(&notifiable));
    }

    pub fn register_audio_notifiable(&mut self, notifiable: Rc<RefCell<AudioNotifiable>>) {
        self.audio_notifiable = Some(Rc::downgrade(&notifiable));
    }

    pub fn preview(&mut self) {
        let mut stream_processed = HashSet::new();
        let mut expected_frames = 0;
        if self.video_stream.is_some() {
            expected_frames += 1;
        }
        if self.audio_stream.is_some() {
            expected_frames += 1;
        }

        let mut video_frame = ffmpeg::frame::Video::empty();
        let mut audio_frame = ffmpeg::frame::Audio::empty();

        for (stream, packet) in self.ffmpeg_context.packets() {
            print_packet_content(&stream, &packet);
            let mut got_frame = false;
            let decoder = stream.codec().decoder();
            match decoder.medium() {
                ffmpeg::media::Type::Video => match self.video_stream {
                    Some(stream_index) => {
                        if stream_index == stream.index() {
                            let mut video = match self.video_decoder {
                                Some(ref mut decoder) => decoder,
                                None => panic!("Error getting video decoder for stream {}", stream_index),
                            };
                            if stream_processed.contains(&stream_index) {
                                // stream already processed
                                continue;
                            }
                            match video.decode(&packet, &mut video_frame) {
                                Ok(decode_got_frame) =>  {
                                    got_frame = decode_got_frame;
                                    let planes = video_frame.planes();
                                    println!("\tdecoded video frame, found {} planes - got frame: {}", planes, got_frame);
                                    for index in 0..planes {
                                        println!("\tplane: {} - data len: {}", index, video_frame.data(index).len());
                                    }
                                },
                                Err(error) => println!("Error decoding video packet for stream {}: {:?}", stream_index, error),
                            }
                            if got_frame {
                                stream_processed.insert(stream_index);
                                match self.video_notifiable.as_ref() {
                                    Some(notifiable_weak) => {
                                        match notifiable_weak.upgrade() {
                                            Some(notifiable) => {
                                                notifiable.borrow_mut().new_video_frame(video_frame);
                                                video_frame = ffmpeg::frame::Video::empty();
                                            },
                                            None => (),
                                        }
                                    },
                                    None => (),
                                }
                            }
                        }
                        else {
                            println!("Skipping stream {}", stream.index());
                        }
                    },
                    None => panic!("No video decoder"),
                },
                ffmpeg::media::Type::Audio => match self.audio_stream {
                    Some(stream_index) => {
                        if stream_index == stream.index() {
                            let ref mut audio = match self.audio_decoder.as_mut() {
                                Some(decoder) => decoder,
                                None => panic!("Error getting audio decoder for stream {}", stream_index),
                            };
                            if stream_processed.contains(&stream_index) {
                                // stream already processed
                                continue;
                            }
                            match audio.decode(&packet, &mut audio_frame) {
                                Ok(decode_got_frame) =>  {
                                    got_frame = decode_got_frame;
                                    let planes = audio_frame.planes();
                                    println!("\tdecoded audio frame, found {} planes - got frame: {}", planes, got_frame);
                                    for index in 0..planes {
                                        println!("\tplane: {} - data len: {}", index, audio_frame.data(index).len());
                                    }
                                },
                                Err(error) => panic!("Error decoding audio packet for stream {}: {:?}", stream_index, error),
                            }
                            if got_frame {
                                stream_processed.insert(stream_index);
                                match self.audio_notifiable.as_ref() {
                                    Some(notifiable_weak) => {
                                        match notifiable_weak.upgrade() {
                                            Some(notifiable) => {
                                                notifiable.borrow_mut().new_audio_frame(audio_frame);
                                                audio_frame = ffmpeg::frame::Audio::empty();
                                            },
                                            None => (),
                                        }
                                    },
                                    None => (),
                                }
                            }
                        }
                        else {
                            println!("Skipping stream {}", stream.index());
                        }
                    },
                    None => panic!("No audio decoder"),
                },
                _ => (),
            }

            if stream_processed.len() == expected_frames {
                break;
            }
        }
    }
}
<|endoftext|>


<commit_before>use super::fitsfile::{FitsFile, HduInfo, DescribesHdu};
use super::sys;
use super::stringutils;
use super::fitserror::{FitsError, Result};
use super::columndescription::ColumnDescription;
use super::libc;
use std::ffi;
use std::ptr;

/// Trait applied to types which can be read from a FITS header
///
/// This is currently:
///
/// * i32
/// * i64
/// * f32
/// * f64
/// * String
pub trait ReadsKey {
    fn read_key(f: &FitsFile, name: &str) -> Result<Self> where Self: Sized;
}

macro_rules! reads_key_impl {
    ($t:ty, $func:ident) => (
        impl ReadsKey for $t {
            fn read_key(f: &FitsFile, name: &str) -> Result<Self> {
                let c_name = ffi::CString::new(name).unwrap();
                let mut status = 0;
                let mut value: Self = Self::default();

                unsafe {
                    sys::$func(f.fptr,
                           c_name.into_raw(),
                           &mut value,
                           ptr::null_mut(),
                           &mut status);
                }

                fits_try!(status, value)
            }
        }
    )
}

reads_key_impl!(i32, ffgkyl);
reads_key_impl!(i64, ffgkyj);
reads_key_impl!(f32, ffgkye);
reads_key_impl!(f64, ffgkyd);

impl ReadsKey for String {
    fn read_key(f: &FitsFile, name: &str) -> Result<Self> {
        let c_name = ffi::CString::new(name).unwrap();
        let mut status = 0;
        let mut value: Vec<libc::c_char> = vec![0; sys::MAX_VALUE_LENGTH];

        unsafe {
            sys::ffgkys(f.fptr,
                        c_name.into_raw(),
                        value.as_mut_ptr(),
                        ptr::null_mut(),
                        &mut status);
        }

        fits_try!(status, {
            let value: Vec<u8> = value.iter()
                .map(|&x| x as u8)
                .filter(|&x| x != 0)
                .collect();
            String::from_utf8(value).unwrap()
        })
    }
}

/// Writing a fits keyword
pub trait WritesKey {
    fn write_key(f: &FitsFile, name: &str, value: Self) -> Result<()>;
}

macro_rules! writes_key_impl_flt {
    ($t:ty, $func:ident) => (
        impl WritesKey for $t {
            fn write_key(f: &FitsFile, name: &str, value: Self) -> Result<()> {
                let c_name = ffi::CString::new(name).unwrap();
                let mut status = 0;

                unsafe {
                    sys::$func(f.fptr,
                                c_name.into_raw(),
                                value,
                                9,
                                ptr::null_mut(),
                                &mut status);
                }
                fits_try!(status, ())
            }
        }
    )
}

impl WritesKey for i64 {
    fn write_key(f: &FitsFile, name: &str, value: Self) -> Result<()> {
        let c_name = ffi::CString::new(name).unwrap();
        let mut status = 0;

        unsafe {
            sys::ffpkyj(f.fptr,
                        c_name.into_raw(),
                        value,
                        ptr::null_mut(),
                        &mut status);
        }
        fits_try!(status, ())
    }
}

writes_key_impl_flt!(f32, ffpkye);
writes_key_impl_flt!(f64, ffpkyd);

impl WritesKey for String {
    fn write_key(f: &FitsFile, name: &str, value: Self) -> Result<()> {
        let c_name = ffi::CString::new(name).unwrap();
        let mut status = 0;

        unsafe {
            sys::ffpkys(f.fptr,
                        c_name.into_raw(),
                        ffi::CString::new(value).unwrap().into_raw(),
                        ptr::null_mut(),
                        &mut status);
        }

        fits_try!(status, ())
    }
}

pub struct FitsHdu<'open> {
    fits_file: &'open FitsFile,
    pub hdu_info: HduInfo,
}

impl<'open> FitsHdu<'open> {
    pub fn new<T: DescribesHdu>(fits_file: &'open FitsFile, hdu_description: T) -> Result<Self> {
        try!(fits_file.change_hdu(hdu_description));
        match fits_file.fetch_hdu_info() {
            Ok(hdu_info) => {
                Ok(FitsHdu {
                    fits_file: fits_file,
                    hdu_info: hdu_info,
                })
            }
            Err(e) => Err(e),
        }
    }

    fn change_hdu<T: DescribesHdu>(&self, hdu_description: T) -> Result<()> {
        hdu_description.change_hdu(self.fits_file)
    }

    /// Get the current HDU type
    pub fn hdu_type(&self) -> Result<sys::HduType> {
        let mut status = 0;
        let mut hdu_type = 0;
        unsafe {
            sys::ffghdt(self.fits_file.fptr, &mut hdu_type, &mut status);
        }

        fits_try!(status, {
            match hdu_type {
                0 => sys::HduType::IMAGE_HDU,
                2 => sys::HduType::BINARY_TBL,
                _ => unimplemented!(),
            }
        })
    }

    /// Read header key
    pub fn read_key<T: ReadsKey>(&self, name: &str) -> Result<T> {
        T::read_key(self.fits_file, name)
    }

    /// Write header key
    pub fn write_key<T: WritesKey>(&self, name: &str, value: T) -> Result<()> {
        T::write_key(self.fits_file, name, value)
    }
}

#[cfg(test)]
mod test {
    use super::FitsHdu;
    use super::super::fitsfile::{FitsFile, HduInfo};

    #[test]
    fn test_manually_creating_a_fits_hdu() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = FitsHdu::new(&f, "TESTEXT").unwrap();
        match hdu.hdu_info {
            HduInfo::TableInfo { num_rows, .. } => {
                assert_eq!(num_rows, 50);
            }
            _ => panic!("Incorrect HDU type found"),
        }
    }

    #[test]
    fn getting_hdu_type() {
        use ::sys::HduType;

        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let primary_hdu = f.hdu(0).unwrap();
        assert_eq!(primary_hdu.hdu_type().unwrap(), HduType::IMAGE_HDU);

        let ext_hdu = f.hdu("TESTEXT").unwrap();
        assert_eq!(ext_hdu.hdu_type().unwrap(), HduType::BINARY_TBL);
    }

    #[test]
    fn reading_header_keys() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.hdu(0).unwrap();
        match hdu.read_key::<i64>("INTTEST") {
            Ok(value) => assert_eq!(value, 42),
            Err(e) => panic!("Error reading key: {:?}", e),
        }

        match hdu.read_key::<f64>("DBLTEST") {
            Ok(value) => assert_eq!(value, 0.09375),
            Err(e) => panic!("Error reading key: {:?}", e),
        }

        match hdu.read_key::<String>("TEST") {
            Ok(value) => assert_eq!(value, "value"),
            Err(e) => panic!("Error reading key: {:?}", e),
        }
    }
}
<commit_msg>Remove change_hdu method from fitshdu<commit_after>use super::fitsfile::{FitsFile, HduInfo, DescribesHdu};
use super::sys;
use super::stringutils;
use super::fitserror::{FitsError, Result};
use super::columndescription::ColumnDescription;
use super::libc;
use std::ffi;
use std::ptr;

/// Trait applied to types which can be read from a FITS header
///
/// This is currently:
///
/// * i32
/// * i64
/// * f32
/// * f64
/// * String
pub trait ReadsKey {
    fn read_key(f: &FitsFile, name: &str) -> Result<Self> where Self: Sized;
}

macro_rules! reads_key_impl {
    ($t:ty, $func:ident) => (
        impl ReadsKey for $t {
            fn read_key(f: &FitsFile, name: &str) -> Result<Self> {
                let c_name = ffi::CString::new(name).unwrap();
                let mut status = 0;
                let mut value: Self = Self::default();

                unsafe {
                    sys::$func(f.fptr,
                           c_name.into_raw(),
                           &mut value,
                           ptr::null_mut(),
                           &mut status);
                }

                fits_try!(status, value)
            }
        }
    )
}

reads_key_impl!(i32, ffgkyl);
reads_key_impl!(i64, ffgkyj);
reads_key_impl!(f32, ffgkye);
reads_key_impl!(f64, ffgkyd);

impl ReadsKey for String {
    fn read_key(f: &FitsFile, name: &str) -> Result<Self> {
        let c_name = ffi::CString::new(name).unwrap();
        let mut status = 0;
        let mut value: Vec<libc::c_char> = vec![0; sys::MAX_VALUE_LENGTH];

        unsafe {
            sys::ffgkys(f.fptr,
                        c_name.into_raw(),
                        value.as_mut_ptr(),
                        ptr::null_mut(),
                        &mut status);
        }

        fits_try!(status, {
            let value: Vec<u8> = value.iter()
                .map(|&x| x as u8)
                .filter(|&x| x != 0)
                .collect();
            String::from_utf8(value).unwrap()
        })
    }
}

/// Writing a fits keyword
pub trait WritesKey {
    fn write_key(f: &FitsFile, name: &str, value: Self) -> Result<()>;
}

macro_rules! writes_key_impl_flt {
    ($t:ty, $func:ident) => (
        impl WritesKey for $t {
            fn write_key(f: &FitsFile, name: &str, value: Self) -> Result<()> {
                let c_name = ffi::CString::new(name).unwrap();
                let mut status = 0;

                unsafe {
                    sys::$func(f.fptr,
                                c_name.into_raw(),
                                value,
                                9,
                                ptr::null_mut(),
                                &mut status);
                }
                fits_try!(status, ())
            }
        }
    )
}

impl WritesKey for i64 {
    fn write_key(f: &FitsFile, name: &str, value: Self) -> Result<()> {
        let c_name = ffi::CString::new(name).unwrap();
        let mut status = 0;

        unsafe {
            sys::ffpkyj(f.fptr,
                        c_name.into_raw(),
                        value,
                        ptr::null_mut(),
                        &mut status);
        }
        fits_try!(status, ())
    }
}

writes_key_impl_flt!(f32, ffpkye);
writes_key_impl_flt!(f64, ffpkyd);

impl WritesKey for String {
    fn write_key(f: &FitsFile, name: &str, value: Self) -> Result<()> {
        let c_name = ffi::CString::new(name).unwrap();
        let mut status = 0;

        unsafe {
            sys::ffpkys(f.fptr,
                        c_name.into_raw(),
                        ffi::CString::new(value).unwrap().into_raw(),
                        ptr::null_mut(),
                        &mut status);
        }

        fits_try!(status, ())
    }
}

pub struct FitsHdu<'open> {
    fits_file: &'open FitsFile,
    pub hdu_info: HduInfo,
}

impl<'open> FitsHdu<'open> {
    pub fn new<T: DescribesHdu>(fits_file: &'open FitsFile, hdu_description: T) -> Result<Self> {
        try!(fits_file.change_hdu(hdu_description));
        match fits_file.fetch_hdu_info() {
            Ok(hdu_info) => {
                Ok(FitsHdu {
                    fits_file: fits_file,
                    hdu_info: hdu_info,
                })
            }
            Err(e) => Err(e),
        }
    }

    /// Get the current HDU type
    pub fn hdu_type(&self) -> Result<sys::HduType> {
        let mut status = 0;
        let mut hdu_type = 0;
        unsafe {
            sys::ffghdt(self.fits_file.fptr, &mut hdu_type, &mut status);
        }

        fits_try!(status, {
            match hdu_type {
                0 => sys::HduType::IMAGE_HDU,
                2 => sys::HduType::BINARY_TBL,
                _ => unimplemented!(),
            }
        })
    }

    /// Read header key
    pub fn read_key<T: ReadsKey>(&self, name: &str) -> Result<T> {
        T::read_key(self.fits_file, name)
    }

    /// Write header key
    pub fn write_key<T: WritesKey>(&self, name: &str, value: T) -> Result<()> {
        T::write_key(self.fits_file, name, value)
    }
}

#[cfg(test)]
mod test {
    use super::FitsHdu;
    use super::super::fitsfile::{FitsFile, HduInfo};

    #[test]
    fn test_manually_creating_a_fits_hdu() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = FitsHdu::new(&f, "TESTEXT").unwrap();
        match hdu.hdu_info {
            HduInfo::TableInfo { num_rows, .. } => {
                assert_eq!(num_rows, 50);
            }
            _ => panic!("Incorrect HDU type found"),
        }
    }

    #[test]
    fn getting_hdu_type() {
        use ::sys::HduType;

        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let primary_hdu = f.hdu(0).unwrap();
        assert_eq!(primary_hdu.hdu_type().unwrap(), HduType::IMAGE_HDU);

        let ext_hdu = f.hdu("TESTEXT").unwrap();
        assert_eq!(ext_hdu.hdu_type().unwrap(), HduType::BINARY_TBL);
    }

    #[test]
    fn reading_header_keys() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        let hdu = f.hdu(0).unwrap();
        match hdu.read_key::<i64>("INTTEST") {
            Ok(value) => assert_eq!(value, 42),
            Err(e) => panic!("Error reading key: {:?}", e),
        }

        match hdu.read_key::<f64>("DBLTEST") {
            Ok(value) => assert_eq!(value, 0.09375),
            Err(e) => panic!("Error reading key: {:?}", e),
        }

        match hdu.read_key::<String>("TEST") {
            Ok(value) => assert_eq!(value, "value"),
            Err(e) => panic!("Error reading key: {:?}", e),
        }
    }
}
<|endoftext|>


<commit_before>use std::*;

pub struct UnionFindForest {
    nodes: Vec<UffNode>,
}

enum UffNode {
    Root(usize),
    Child(usize),
}

impl UnionFindForest {
    pub fn new(size: usize) -> Self {
        UnionFindForest {
            nodes: (0..size)
                .map(|_| UffNode::Root(1))
                .collect::<Vec<_>>(),
        }
    }

    pub fn root_node(&mut self, v: usize) -> (usize, usize) {
        match self.nodes[v] {
            UffNode::Root(rank) => (v, rank),
            UffNode::Child(u) => {
                let (u, rank) = self.root_node(u);
                self.nodes[v] = UffNode::Child(u);
                (u, rank)
            }
        }
    }

    pub fn root(&mut self, v: usize) -> usize {
        self.root_node(v).0
    }

    pub fn connects(&mut self, u: usize, v: usize) -> bool {
        self.root(u) == self.root(v)
    }

    pub fn merge(&mut self, u: usize, v: usize) {
        let (u, u_rank) = self.root_node(u);
        let (v, v_rank) = self.root_node(v);

        if u == v {
            return;
        }

        if u_rank < v_rank {
            self.merge(v, u);
            return;
        }

        self.nodes[v] = UffNode::Child(u);
        self.nodes[u] = UffNode::Root(u_rank + 1);
    }
}
<commit_msg>Format<commit_after>use std::*;

pub struct UnionFindForest {
    nodes: Vec<UffNode>,
}

enum UffNode {
    Root(usize),
    Child(usize),
}

impl UnionFindForest {
    pub fn new(size: usize) -> Self {
        UnionFindForest {
            nodes: (0..size).map(|_| UffNode::Root(1)).collect::<Vec<_>>(),
        }
    }

    pub fn root_node(&mut self, v: usize) -> (usize, usize) {
        match self.nodes[v] {
            UffNode::Root(rank) => (v, rank),
            UffNode::Child(u) => {
                let (u, rank) = self.root_node(u);
                self.nodes[v] = UffNode::Child(u);
                (u, rank)
            }
        }
    }

    pub fn root(&mut self, v: usize) -> usize {
        self.root_node(v).0
    }

    pub fn connects(&mut self, u: usize, v: usize) -> bool {
        self.root(u) == self.root(v)
    }

    pub fn merge(&mut self, u: usize, v: usize) {
        let (u, u_rank) = self.root_node(u);
        let (v, v_rank) = self.root_node(v);

        if u == v {
            return;
        }

        if u_rank < v_rank {
            self.merge(v, u);
            return;
        }

        self.nodes[v] = UffNode::Child(u);
        self.nodes[u] = UffNode::Root(u_rank + 1);
    }
}
<|endoftext|>


<commit_before>use std;
import std::arena;
import std::arena::arena;

enum tree/& { nil, node(&tree, &tree, int), }

fn item_check(t: &tree) -> int {
    alt *t {
      nil { ret 0; }
      node(left, right, item) {
        ret item + item_check(left) - item_check(right);
      }
    }
}

fn bottom_up_tree(arena: &a.arena::arena, item: int, depth: int) -> &a.tree {
    if depth > 0 {
        ret new(*arena) node(bottom_up_tree(arena, 2 * item - 1, depth - 1),
                             bottom_up_tree(arena, 2 * item, depth - 1),
                             item);
    }
    ret new(*arena) nil;
}

fn main(args: ~[str]) {
    let args = if os::getenv("RUST_BENCH").is_some() {
        ~["", "17"]
    } else if args.len() <= 1u {
        ~["", "8"]
    } else {
        args
    };

    let n = int::from_str(args[1]).get();
    let min_depth = 4;
    let mut max_depth;
    if min_depth + 2 > n {
        max_depth = min_depth + 2;
    } else {
        max_depth = n;
    }

    let stretch_arena = arena::arena();
    let stretch_depth = max_depth + 1;
    let stretch_tree = bottom_up_tree(&stretch_arena, 0, stretch_depth);

    io::println(#fmt("stretch tree of depth %d\t check: %d",
                          stretch_depth,
                          item_check(stretch_tree)));

    let long_lived_arena = arena::arena();
    let long_lived_tree = bottom_up_tree(&long_lived_arena, 0, max_depth);
    let mut depth = min_depth;
    while depth <= max_depth {
        let iterations = int::pow(2, (max_depth - depth + min_depth) as uint);
        let mut chk = 0;
        let mut i = 1;
        while i <= iterations {
            let mut temp_tree = bottom_up_tree(&long_lived_arena, i, depth);
            chk += item_check(temp_tree);
            temp_tree = bottom_up_tree(&long_lived_arena, -i, depth);
            chk += item_check(temp_tree);
            i += 1;
        }
        io::println(#fmt("%d\t trees of depth %d\t check: %d",
                         iterations * 2, depth,
                         chk));
        depth += 2;
    }
    io::println(#fmt("long lived trees of depth %d\t check: %d",
                     max_depth,
                          item_check(long_lived_tree)));
}
<commit_msg>test: Fix shootout-binarytrees<commit_after>use std;
import std::arena;
import methods = std::arena::arena;

enum tree/& { nil, node(&tree, &tree, int), }

fn item_check(t: &tree) -> int {
    alt *t {
      nil { ret 0; }
      node(left, right, item) {
        ret item + item_check(left) - item_check(right);
      }
    }
}

fn bottom_up_tree(arena: &a.arena::arena, item: int, depth: int) -> &a.tree {
    if depth > 0 {
        ret new(*arena) node(bottom_up_tree(arena, 2 * item - 1, depth - 1),
                             bottom_up_tree(arena, 2 * item, depth - 1),
                             item);
    }
    ret new(*arena) nil;
}

fn main(args: ~[str]) {
    let args = if os::getenv("RUST_BENCH").is_some() {
        ~["", "17"]
    } else if args.len() <= 1u {
        ~["", "8"]
    } else {
        args
    };

    let n = int::from_str(args[1]).get();
    let min_depth = 4;
    let mut max_depth;
    if min_depth + 2 > n {
        max_depth = min_depth + 2;
    } else {
        max_depth = n;
    }

    let stretch_arena = arena::arena();
    let stretch_depth = max_depth + 1;
    let stretch_tree = bottom_up_tree(&stretch_arena, 0, stretch_depth);

    io::println(#fmt("stretch tree of depth %d\t check: %d",
                          stretch_depth,
                          item_check(stretch_tree)));

    let long_lived_arena = arena::arena();
    let long_lived_tree = bottom_up_tree(&long_lived_arena, 0, max_depth);
    let mut depth = min_depth;
    while depth <= max_depth {
        let iterations = int::pow(2, (max_depth - depth + min_depth) as uint);
        let mut chk = 0;
        let mut i = 1;
        while i <= iterations {
            let mut temp_tree = bottom_up_tree(&long_lived_arena, i, depth);
            chk += item_check(temp_tree);
            temp_tree = bottom_up_tree(&long_lived_arena, -i, depth);
            chk += item_check(temp_tree);
            i += 1;
        }
        io::println(#fmt("%d\t trees of depth %d\t check: %d",
                         iterations * 2, depth,
                         chk));
        depth += 2;
    }
    io::println(#fmt("long lived trees of depth %d\t check: %d",
                     max_depth,
                          item_check(long_lived_tree)));
}
<|endoftext|>


<commit_before>
use errors::*;
use libc::{c_char, c_int};
use libmodbus_sys;
use modbus::Modbus;

/// The server is waiting for request from clients and must answer when it is concerned by the request.
/// The libmodbus offers the following functions to handle requests:
pub trait ModbusServer {
}

impl ModbusServer for Modbus {
}
<commit_msg>Add Modbus::receive(), but this function segfaults<commit_after>
use errors::*;
use libc::{c_char, c_int};
use libmodbus_sys;
use modbus::Modbus;

/// The server is waiting for request from clients and must answer when it is concerned by the request. The libmodbus offers the following functions to handle requests:
///
/// * Receive
///     - [`receive()`](struct.Modbus.html#method.receive)
/// * Reply
///     - [`reply()`](struct.Modbus.html#method.reply), [`reply_exception()`](struct.Modbus.html#method.reply_exception)
///
pub trait ModbusServer {
    fn receive(&self, request: &mut [u8]) -> Result<i32>;
}

impl ModbusServer for Modbus {
    /// `receive` - receive an indication request
    ///
    /// The [`receive()`](#method.receive) function shall receive an indication request from the socket of the context ctx.
    /// This function is used by Modbus slave/server to receive and analyze indication request sent by the masters/clients.
    ///
    /// If you need to use another socket or file descriptor than the one defined in the context ctx, see the function [`set_socket()`](struct.Modbus.html#method.set_socket).
    ///
    /// # Examples
    ///
    /// ```
    /// use libmodbus_rs::{Modbus, ModbusServer, ModbusTCP, MODBUS_MAX_ADU_LENGTH};
    ///
    /// let modbus = Modbus::new_tcp("127.0.0.1", 1502).unwrap();
    /// let mut query = vec![0; MODBUS_MAX_ADU_LENGTH as usize];
    ///
    /// assert!(modbus.receive(&mut query).is_ok());
    /// ```
    fn receive(&self, request: &mut [u8]) -> Result<i32> {
        unsafe {
            let len = libmodbus_sys::modbus_receive(self.ctx, request.as_mut_ptr());
            match len {
                -1 => Err("Could not receive an idication request".into()),
                len => Ok(len),
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Do not inform the user about memes if the PoW is a meme<commit_after><|endoftext|>


<commit_before>use time::precise_time_ns;
use rand;

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct Id {
    time: u64,
    random: u64,
}

impl Id {
    pub fn new() -> Id {
        Id {
            time: precise_time_ns(),
            random: rand::random(),
        }
    }
}

<commit_msg>precise_time_ns -> Timespec<commit_after>use time;
use rand;

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct Id {
    time: time::Timespec,
    random: u32,
}

impl Id {
    pub fn new() -> Id {
        Id {
            time: time::now().to_timespec(),
            random: rand::random(),
        }
    }
}

<|endoftext|>


<commit_before>use core::cell::Cell;
use common::take_cell::TakeCell;
use common::math::{sqrtf32, get_errno};
use hil::{Driver,Callback};
use hil::i2c;
use hil::gpio::{GPIOPin, InputMode, InterruptMode, Client};

pub static mut BUFFER : [u8; 3] = [0; 3];

// error codes for this driver
const ERR_BAD_VALUE: isize = -2;

const MAX_SAMPLING_RATE: u8 = 0x0;
const DEFAULT_SAMPLING_RATE: u8 = 0x02;

// temperature calculation constants
//  From TMP006 User's Guide section 5.1
//  S_0 should be determined from calibration and ranges from 5E-14 to 7E-14
//  We have selected 5E-14 experimentally
const S_0: f32 = 5E-14;
const A_1: f32 = 1.75E-3;
const A_2: f32 = -1.678E-5;
const T_REF: f32 = 298.15;
const B_0: f32 = -2.94E-5;
const B_1: f32 = -5.7E-7;
const B_2: f32 = 4.63E-9;
const C_2: f32 = 13.4;
const K_TO_C: f32 = -273.15;
const C_TO_K: f32 = 273.15;
const NV_TO_V: f32 = 1E9;
const T_DIE_CONVERT: f32 = 0.03125;
const V_OBJ_CONVERT: f32 = 156.25;

#[allow(dead_code)]
enum Registers {
    SensorVoltage = 0x00,
    DieTemperature = 0x01,
    Configuration = 0x02,
    ManufacturerID = 0xFE,
    DeviceID = 0xFF,
}

type SensorVoltage = i16;

/// States of the I2C protocol with the TMP006. There are three sequences:
///
/// ### Enable sensor
///
/// Configure -> ()
///
/// ### Disable sensor
///
/// Disconfigure -> ()
///
/// ### Read temperature
///
/// SetRegSensorVoltage -->
///     ReadingSensorVoltage --(voltage)->
///         SetRegDieTemperature(voltage) --(voltage)->
///             ReadingDieTemperature --(unless repeated_mode)->
///                 Disconfigure
#[derive(Clone,Copy,PartialEq)]
enum ProtocolState {
    Idle,

    /// Enable sensor by setting the configuration register.
    Configure,

    /// Disable sensor by setting the configuration register. Optionally contains the most recent
    /// temperature to give back to callbacks.
    Deconfigure(Option<f32>),

    /// Set the active register to sensor voltage.
    SetRegSensorVoltage,

    /// Read the sensor voltage register.
    ReadingSensorVoltage,

    /// Set the active register to die temperature, carrying over the sensor
    /// voltage reading.
    SetRegDieTemperature(SensorVoltage),

    /// Read the die temperature register, carrying over the sensor voltage
    /// reading.
    ReadingDieTemperature(SensorVoltage),
}

pub struct TMP006<'a, I: i2c::I2C + 'a, G: GPIOPin + 'a> {
    i2c: &'a I,
    i2c_address: Cell<u8>,
    interrupt_pin: &'a G,
    sampling_period: Cell<u8>,
    repeated_mode: Cell<bool>,
    callback: Cell<Option<Callback>>,
    protocol_state: Cell<ProtocolState>,
    buffer: TakeCell<&'static mut [u8]>
}

impl<'a, I: i2c::I2C, G: GPIOPin> TMP006<'a, I, G> {
    pub fn new(i2c: &'a I, i2c_address: u8, interrupt_pin: &'a G,
               buffer: &'static mut [u8]) -> TMP006<'a, I, G> {
        // setup and return struct
        TMP006{
            i2c: i2c,
            i2c_address: Cell::new(i2c_address),
            interrupt_pin: interrupt_pin,
            sampling_period: Cell::new(DEFAULT_SAMPLING_RATE),
            repeated_mode: Cell::new(false),
            callback: Cell::new(None),
            protocol_state: Cell::new(ProtocolState::Idle),
            buffer: TakeCell::new(buffer)
        }
    }

    fn enable_sensor(&self, sampling_period: u8) {
        // enable and configure TMP006
        self.buffer.take().map(|buf| {
            // turn on i2c to send commands
            self.i2c.enable();

            let config = 0x7100 | (((sampling_period & 0x7) as u16) << 9);
            buf[0] = Registers::Configuration as u8;
            buf[1] = ((config & 0xFF00) >> 8) as u8;
            buf[2] = (config & 0x00FF) as u8;
            self.i2c.write(self.i2c_address.get(), buf, 3);
            self.protocol_state.set(ProtocolState::Configure);
        });
    }

    fn disable_sensor(&self, temperature: Option<f32>) {
        // disable the TMP006
        self.buffer.take().map(|buf| {
            // turn on i2c to send commands
            self.i2c.enable();

            let config = 0x0000;
            buf[0] = Registers::Configuration as u8;
            buf[1] = ((config & 0xFF00) >> 8) as u8;
            buf[2] = (config & 0x00FF) as u8;
            self.i2c.write(self.i2c_address.get(), buf, 3);
            self.protocol_state.set(ProtocolState::Deconfigure(temperature));
        });
    }

    fn enable_interrupts(&self) {
        // setup interrupts from the sensor
        self.interrupt_pin.enable_input(InputMode::PullUp);
        self.interrupt_pin.enable_interrupt(0, InterruptMode::FallingEdge);
    }

    fn disable_interrupts(&self) {
        // disable interrupts from the sensor
        self.interrupt_pin.disable_interrupt();
        self.interrupt_pin.disable();
    }
}

fn calculate_temperature(sensor_voltage: i16, die_temperature: i16) -> f32 {
    // do calculation of actual temperature
    //  Calculations based on TMP006 User's Guide section 5.1
    let t_die = ((die_temperature >> 2) as f32)*T_DIE_CONVERT + C_TO_K;
    let t_adj = t_die-T_REF;
    let s = S_0 * (1.0 + A_1*t_adj + A_2*t_adj*t_adj);

    let v_obj = (sensor_voltage as f32)*V_OBJ_CONVERT/NV_TO_V;
    let v_os = B_0 + B_1*t_adj + B_2*t_adj*t_adj;

    let v_adj = v_obj-v_os;
    let f_v_obj = v_adj + C_2*v_adj*v_adj;

    let t_kelvin =
        sqrtf32(sqrtf32(t_die * t_die * t_die * t_die + (f_v_obj / s)));
    let t_celsius = t_kelvin + K_TO_C;

    // return data value
    t_celsius
}

impl<'a, I: i2c::I2C, G: GPIOPin> i2c::I2CClient for TMP006<'a, I, G> {
    fn command_complete(&self, buffer: &'static mut [u8], _error: i2c::Error) {
        //TODO(alevy): handle protocol errors
        match self.protocol_state.get() {
            ProtocolState::Configure => {
                self.buffer.replace(buffer);
                self.enable_interrupts();
                self.i2c.disable();
                self.protocol_state.set(ProtocolState::Idle);
            },
            ProtocolState::Deconfigure(temperature) => {
                self.buffer.replace(buffer);
                self.disable_interrupts();
                self.i2c.disable();
                self.protocol_state.set(ProtocolState::Idle);
                temperature.map(|temp_val| {
                    self.callback.get().map(|mut cb|
                        cb.schedule(temp_val as usize, get_errno() as usize, 0));
                    self.callback.set(None);
                });
            },
            ProtocolState::SetRegSensorVoltage => {
                // Read sensor voltage register
                self.i2c.read(self.i2c_address.get(), buffer, 2);
                self.protocol_state.set(ProtocolState::ReadingSensorVoltage);
            },
            ProtocolState::ReadingSensorVoltage => {
                let sensor_voltage =
                    (((buffer[0] as u16) << 8) | buffer[1] as u16) as i16;

                // Select die temperature register
                buffer[0] = Registers::DieTemperature as u8;
                self.i2c.write(self.i2c_address.get(), buffer, 1);

                self.protocol_state.set(
                    ProtocolState::SetRegDieTemperature(sensor_voltage));
            },
            ProtocolState::SetRegDieTemperature(sensor_voltage) => {
                // Read die temperature register
                self.i2c.read(self.i2c_address.get(), buffer, 2);
                self.protocol_state.set(
                    ProtocolState::ReadingDieTemperature(sensor_voltage));
            },
            ProtocolState::ReadingDieTemperature(sensor_voltage) => {
                let die_temperature =
                    (((buffer[0] as u16) << 8) | buffer[1] as u16) as i16;
                self.buffer.replace(buffer);

                let temp_val = calculate_temperature(sensor_voltage, die_temperature);

                // disable callback and sensing if in single-shot mode
                if self.repeated_mode.get() == false {
                    // disable temperature sensor. When disabling is finished, we will give the
                    // temperature to the callback.
                    self.disable_sensor(Some(temp_val));
                } else {
                    // send value to callback
                    self.callback.get().map(|mut cb|
                        cb.schedule(temp_val as usize, get_errno() as usize, 0)
                    );

                    self.i2c.disable();
                }
            },
            _ => {}
        }
    }
}

impl<'a, I: i2c::I2C, G: GPIOPin> Client for TMP006<'a, I, G> {
    fn fired(&self, _: usize) {
        self.buffer.take().map(|buf| {
            // turn on i2c to send commands
            self.i2c.enable();

            // select sensor voltage register and read it
            buf[0] = Registers::SensorVoltage as u8;
            self.i2c.write(self.i2c_address.get(), buf, 1);
            self.protocol_state.set(ProtocolState::SetRegSensorVoltage);
        });
    }
}

impl<'a, I: i2c::I2C, G: GPIOPin> Driver for TMP006<'a, I, G> {
    fn subscribe(&self, subscribe_num: usize, callback: Callback) -> isize {
        match subscribe_num {
            // single temperature reading with callback
            0 => {
                // single sample mode
                self.repeated_mode.set(false);

                // set callback function
                self.callback.set(Some(callback));

                // enable sensor
                //  turn up the sampling rate so we get the sample faster
                self.enable_sensor(MAX_SAMPLING_RATE);

                0
            },

            // periodic temperature reading subscription
            1 => {
                // periodic sampling mode
                self.repeated_mode.set(true);

                // set callback function
                self.callback.set(Some(callback));

                // enable temperature sensor
                self.enable_sensor(self.sampling_period.get());

                0
            },

            // default
            _ => -1
        }
    }

    fn command(&self, command_num: usize, data: usize) -> isize {
        match command_num {
            // set period for sensing
            0 => {
                // bounds check on the period
                if (data & 0xFFFFFFF8) != 0 {
                    return ERR_BAD_VALUE;
                }

                // set period value
                self.sampling_period.set((data & 0x7) as u8);

                0
            },

            // unsubscribe callback
            1 => {
                // clear callback function
                self.callback.set(None);

                // disable temperature sensor
                self.disable_sensor(None);

                0
            },

            // default
            _ => -1
        }
    }
}

<commit_msg>TMP006: Removing unnecessary Cell<commit_after>use core::cell::Cell;
use common::take_cell::TakeCell;
use common::math::{sqrtf32, get_errno};
use hil::{Driver,Callback};
use hil::i2c;
use hil::gpio::{GPIOPin, InputMode, InterruptMode, Client};

pub static mut BUFFER : [u8; 3] = [0; 3];

// error codes for this driver
const ERR_BAD_VALUE: isize = -2;

const MAX_SAMPLING_RATE: u8 = 0x0;
const DEFAULT_SAMPLING_RATE: u8 = 0x02;

// temperature calculation constants
//  From TMP006 User's Guide section 5.1
//  S_0 should be determined from calibration and ranges from 5E-14 to 7E-14
//  We have selected 5E-14 experimentally
const S_0: f32 = 5E-14;
const A_1: f32 = 1.75E-3;
const A_2: f32 = -1.678E-5;
const T_REF: f32 = 298.15;
const B_0: f32 = -2.94E-5;
const B_1: f32 = -5.7E-7;
const B_2: f32 = 4.63E-9;
const C_2: f32 = 13.4;
const K_TO_C: f32 = -273.15;
const C_TO_K: f32 = 273.15;
const NV_TO_V: f32 = 1E9;
const T_DIE_CONVERT: f32 = 0.03125;
const V_OBJ_CONVERT: f32 = 156.25;

#[allow(dead_code)]
enum Registers {
    SensorVoltage = 0x00,
    DieTemperature = 0x01,
    Configuration = 0x02,
    ManufacturerID = 0xFE,
    DeviceID = 0xFF,
}

type SensorVoltage = i16;

/// States of the I2C protocol with the TMP006. There are three sequences:
///
/// ### Enable sensor
///
/// Configure -> ()
///
/// ### Disable sensor
///
/// Disconfigure -> ()
///
/// ### Read temperature
///
/// SetRegSensorVoltage -->
///     ReadingSensorVoltage --(voltage)->
///         SetRegDieTemperature(voltage) --(voltage)->
///             ReadingDieTemperature --(unless repeated_mode)->
///                 Disconfigure
#[derive(Clone,Copy,PartialEq)]
enum ProtocolState {
    Idle,

    /// Enable sensor by setting the configuration register.
    Configure,

    /// Disable sensor by setting the configuration register. Optionally contains the most recent
    /// temperature to give back to callbacks.
    Deconfigure(Option<f32>),

    /// Set the active register to sensor voltage.
    SetRegSensorVoltage,

    /// Read the sensor voltage register.
    ReadingSensorVoltage,

    /// Set the active register to die temperature, carrying over the sensor
    /// voltage reading.
    SetRegDieTemperature(SensorVoltage),

    /// Read the die temperature register, carrying over the sensor voltage
    /// reading.
    ReadingDieTemperature(SensorVoltage),
}

pub struct TMP006<'a, I: i2c::I2C + 'a, G: GPIOPin + 'a> {
    i2c: &'a I,
    i2c_address: u8,
    interrupt_pin: &'a G,
    sampling_period: Cell<u8>,
    repeated_mode: Cell<bool>,
    callback: Cell<Option<Callback>>,
    protocol_state: Cell<ProtocolState>,
    buffer: TakeCell<&'static mut [u8]>
}

impl<'a, I: i2c::I2C, G: GPIOPin> TMP006<'a, I, G> {
    pub fn new(i2c: &'a I, i2c_address: u8, interrupt_pin: &'a G,
               buffer: &'static mut [u8]) -> TMP006<'a, I, G> {
        // setup and return struct
        TMP006{
            i2c: i2c,
            i2c_address: i2c_address,
            interrupt_pin: interrupt_pin,
            sampling_period: Cell::new(DEFAULT_SAMPLING_RATE),
            repeated_mode: Cell::new(false),
            callback: Cell::new(None),
            protocol_state: Cell::new(ProtocolState::Idle),
            buffer: TakeCell::new(buffer)
        }
    }

    fn enable_sensor(&self, sampling_period: u8) {
        // enable and configure TMP006
        self.buffer.take().map(|buf| {
            // turn on i2c to send commands
            self.i2c.enable();

            let config = 0x7100 | (((sampling_period & 0x7) as u16) << 9);
            buf[0] = Registers::Configuration as u8;
            buf[1] = ((config & 0xFF00) >> 8) as u8;
            buf[2] = (config & 0x00FF) as u8;
            self.i2c.write(self.i2c_address, buf, 3);
            self.protocol_state.set(ProtocolState::Configure);
        });
    }

    fn disable_sensor(&self, temperature: Option<f32>) {
        // disable the TMP006
        self.buffer.take().map(|buf| {
            // turn on i2c to send commands
            self.i2c.enable();

            let config = 0x0000;
            buf[0] = Registers::Configuration as u8;
            buf[1] = ((config & 0xFF00) >> 8) as u8;
            buf[2] = (config & 0x00FF) as u8;
            self.i2c.write(self.i2c_address, buf, 3);
            self.protocol_state.set(ProtocolState::Deconfigure(temperature));
        });
    }

    fn enable_interrupts(&self) {
        // setup interrupts from the sensor
        self.interrupt_pin.enable_input(InputMode::PullUp);
        self.interrupt_pin.enable_interrupt(0, InterruptMode::FallingEdge);
    }

    fn disable_interrupts(&self) {
        // disable interrupts from the sensor
        self.interrupt_pin.disable_interrupt();
        self.interrupt_pin.disable();
    }
}

fn calculate_temperature(sensor_voltage: i16, die_temperature: i16) -> f32 {
    // do calculation of actual temperature
    //  Calculations based on TMP006 User's Guide section 5.1
    let t_die = ((die_temperature >> 2) as f32)*T_DIE_CONVERT + C_TO_K;
    let t_adj = t_die-T_REF;
    let s = S_0 * (1.0 + A_1*t_adj + A_2*t_adj*t_adj);

    let v_obj = (sensor_voltage as f32)*V_OBJ_CONVERT/NV_TO_V;
    let v_os = B_0 + B_1*t_adj + B_2*t_adj*t_adj;

    let v_adj = v_obj-v_os;
    let f_v_obj = v_adj + C_2*v_adj*v_adj;

    let t_kelvin =
        sqrtf32(sqrtf32(t_die * t_die * t_die * t_die + (f_v_obj / s)));
    let t_celsius = t_kelvin + K_TO_C;

    // return data value
    t_celsius
}

impl<'a, I: i2c::I2C, G: GPIOPin> i2c::I2CClient for TMP006<'a, I, G> {
    fn command_complete(&self, buffer: &'static mut [u8], _error: i2c::Error) {
        //TODO(alevy): handle protocol errors
        match self.protocol_state.get() {
            ProtocolState::Configure => {
                self.buffer.replace(buffer);
                self.enable_interrupts();
                self.i2c.disable();
                self.protocol_state.set(ProtocolState::Idle);
            },
            ProtocolState::Deconfigure(temperature) => {
                self.buffer.replace(buffer);
                self.disable_interrupts();
                self.i2c.disable();
                self.protocol_state.set(ProtocolState::Idle);
                temperature.map(|temp_val| {
                    self.callback.get().map(|mut cb|
                        cb.schedule(temp_val as usize, get_errno() as usize, 0));
                    self.callback.set(None);
                });
            },
            ProtocolState::SetRegSensorVoltage => {
                // Read sensor voltage register
                self.i2c.read(self.i2c_address, buffer, 2);
                self.protocol_state.set(ProtocolState::ReadingSensorVoltage);
            },
            ProtocolState::ReadingSensorVoltage => {
                let sensor_voltage =
                    (((buffer[0] as u16) << 8) | buffer[1] as u16) as i16;

                // Select die temperature register
                buffer[0] = Registers::DieTemperature as u8;
                self.i2c.write(self.i2c_address, buffer, 1);

                self.protocol_state.set(
                    ProtocolState::SetRegDieTemperature(sensor_voltage));
            },
            ProtocolState::SetRegDieTemperature(sensor_voltage) => {
                // Read die temperature register
                self.i2c.read(self.i2c_address, buffer, 2);
                self.protocol_state.set(
                    ProtocolState::ReadingDieTemperature(sensor_voltage));
            },
            ProtocolState::ReadingDieTemperature(sensor_voltage) => {
                let die_temperature =
                    (((buffer[0] as u16) << 8) | buffer[1] as u16) as i16;
                self.buffer.replace(buffer);

                let temp_val = calculate_temperature(sensor_voltage, die_temperature);

                // disable callback and sensing if in single-shot mode
                if self.repeated_mode.get() == false {
                    // disable temperature sensor. When disabling is finished, we will give the
                    // temperature to the callback.
                    self.disable_sensor(Some(temp_val));
                } else {
                    // send value to callback
                    self.callback.get().map(|mut cb|
                        cb.schedule(temp_val as usize, get_errno() as usize, 0)
                    );

                    self.i2c.disable();
                }
            },
            _ => {}
        }
    }
}

impl<'a, I: i2c::I2C, G: GPIOPin> Client for TMP006<'a, I, G> {
    fn fired(&self, _: usize) {
        self.buffer.take().map(|buf| {
            // turn on i2c to send commands
            self.i2c.enable();

            // select sensor voltage register and read it
            buf[0] = Registers::SensorVoltage as u8;
            self.i2c.write(self.i2c_address, buf, 1);
            self.protocol_state.set(ProtocolState::SetRegSensorVoltage);
        });
    }
}

impl<'a, I: i2c::I2C, G: GPIOPin> Driver for TMP006<'a, I, G> {
    fn subscribe(&self, subscribe_num: usize, callback: Callback) -> isize {
        match subscribe_num {
            // single temperature reading with callback
            0 => {
                // single sample mode
                self.repeated_mode.set(false);

                // set callback function
                self.callback.set(Some(callback));

                // enable sensor
                //  turn up the sampling rate so we get the sample faster
                self.enable_sensor(MAX_SAMPLING_RATE);

                0
            },

            // periodic temperature reading subscription
            1 => {
                // periodic sampling mode
                self.repeated_mode.set(true);

                // set callback function
                self.callback.set(Some(callback));

                // enable temperature sensor
                self.enable_sensor(self.sampling_period.get());

                0
            },

            // default
            _ => -1
        }
    }

    fn command(&self, command_num: usize, data: usize) -> isize {
        match command_num {
            // set period for sensing
            0 => {
                // bounds check on the period
                if (data & 0xFFFFFFF8) != 0 {
                    return ERR_BAD_VALUE;
                }

                // set period value
                self.sampling_period.set((data & 0x7) as u8);

                0
            },

            // unsubscribe callback
            1 => {
                // clear callback function
                self.callback.set(None);

                // disable temperature sensor
                self.disable_sensor(None);

                0
            },

            // default
            _ => -1
        }
    }
}

<|endoftext|>


<commit_before>use std::collections::HashMap;

use rocket_contrib::JSON;

type ErrorMap = HashMap<&'static str, Vec<HashMap<&'static str, &'static str>>>;

#[error(400)]
pub fn bad_request() -> JSON<ErrorMap> {
    JSON(map!{
        "errors" => vec![
            map!{
                "status" => "400",
                "detail" => "Bad Request",
            },
        ],
    })
}

#[error(404)]
pub fn not_found() -> JSON<ErrorMap> {
    JSON(map!{
        "errors" => vec![
            map!{
                "status" => "404",
                "detail" => "Not Found",
            },
        ],
    })
}

#[error(500)]
pub fn internal_server_error() -> JSON<ErrorMap> {
    JSON(map!{
        "errors" => vec![
            map!{
                "status" => "500",
                "detail" => "Internal Server Error",
            },
        ],
    })
}
<commit_msg>test: add tests for error catchers<commit_after>use std::collections::HashMap;

use rocket_contrib::JSON;

type ErrorMap = HashMap<&'static str, Vec<HashMap<&'static str, &'static str>>>;

#[error(400)]
pub fn bad_request() -> JSON<ErrorMap> {
    JSON(map!{
        "errors" => vec![
            map!{
                "status" => "400",
                "detail" => "Bad Request",
            },
        ],
    })
}

#[error(404)]
pub fn not_found() -> JSON<ErrorMap> {
    JSON(map!{
        "errors" => vec![
            map!{
                "status" => "404",
                "detail" => "Not Found",
            },
        ],
    })
}

#[error(500)]
pub fn internal_server_error() -> JSON<ErrorMap> {
    JSON(map!{
        "errors" => vec![
            map!{
                "status" => "500",
                "detail" => "Internal Server Error",
            },
        ],
    })
}

#[cfg(test)]
mod tests {
    use rocket;
    use rocket::http::Status;
    use rocket::http::Method::*;
    use rocket::testing::MockRequest;

    use super::*;

    #[derive(Deserialize, Serialize)]
    struct Params {
        message: String,
    }

    #[patch("/echo", data = "<params>", format="application/json")]
    fn echo(params: JSON<Params>) -> JSON<Params> {
        params
    }

    #[get("/error")]
    fn error() -> Result<(), ()> {
        Err(())
    }

    #[test]
    #[should_panic]
    fn test_bad_request() {
        let server = rocket::ignite()
            .mount("/", routes![echo])
            .catch(errors![bad_request]);

        let mut req = MockRequest::new(Patch, "/echo");
        let res = req.dispatch_with(&server);

        assert_eq!(res.status(), Status::BadRequest);
    }

    #[test]
    fn test_not_found() {
        let server = rocket::ignite()
            .mount("/", routes![])
            .catch(errors![not_found]);

        let mut req = MockRequest::new(Get, "/");
        let res = req.dispatch_with(&server);

        assert_eq!(res.status(), Status::NotFound);
    }

    #[test]
    #[should_panic]
    fn test_error() {
        let server = rocket::ignite()
            .mount("/", routes![error])
            .catch(errors![internal_server_error]);

        let mut req = MockRequest::new(Get, "/error");
        let res = req.dispatch_with(&server);

        assert_eq!(res.status(), Status::InternalServerError);
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 Jeffery Olson
//
// Licensed under the 3-Clause BSD License, see LICENSE.txt
// at the top-level of this repository.
// This file may not be copied, modified, or distributed
// except according to those terms.
#![crate_id="http://olsonjeffery.github.io#schemers:0.0.1"]
#![desc = "Simple Scheme Interpreter"]
#![license = "3-Clause BSD"]

// this is starting out as a straight port of Peter Norvig's
// lis.py (the first iteration) to Rust

#[cfg(not(test))]
fn main() {
    use std::os::args;
    let args: Vec<~str> = args().move_iter().skip(1).collect();
    if args.len() == 0 {
        fail!("no program provided");
    }
    let program: ~str = args.move_iter()
        .fold(~"", |memo, arg| memo + arg + " ").trim().to_owned();
    let tokens = &mut tokenize(program);
    println!("{:?}", read(tokens));
}

// parser impl
fn pad_input(input: ~str) -> ~str {
    input.replace("(", " ( ").replace(")", " ) ")
}

fn tokenize(input: ~str) -> Vec<~str> {
    pad_input(input).split_str(" ")
        .filter(|i| *i != "").map(|i| i.to_owned()).collect()
}

pub enum ParseItem {
    Atom(~str),
    List(Vec<~ParseItem>)
}

fn read(tokens: &mut Vec<~str>) -> ParseItem {
    println!("current state of tokens: '{:?}'", tokens);
    match tokens.pop().expect("calling read() w/ empty token list; shouldn't happen") {
        ref x if *x == ~"(" => {
            let mut list = Vec::new();
            while *tokens.get(0) != ~")" {
                list.push(box read(tokens));
            }
            tokens.pop();
            List(list)
        },
        ref x if *x == ~")" => fail!("hit ) token; shouldn't happen"),
        x => Atom(x)
    }
}

#[cfg(test)]
mod parser_test {
    use super::{pad_input, tokenize, read, Atom};

    #[test]
    fn pad_input_should_insert_spaces_before_and_after_parens() {
        assert_eq!(pad_input(~"(x 1 2 3)"), ~" ( x 1 2 3 ) ");
    }

    #[test]
    fn tokenize_string_into_tokens() {
        let tokens = tokenize(~"(foo 12 3)");
        assert_eq!(tokens.len(), 5);
        assert_eq!(tokens.get(0).to_owned(), ~"(");
        assert_eq!(tokens.get(1).to_owned(), ~"foo");
        assert_eq!(tokens.get(2).to_owned(), ~"12");
        assert_eq!(tokens.get(3).to_owned(), ~"3");
        assert_eq!(tokens.get(4).to_owned(), ~")");
    }

    #[test]
    fn parse_should_take_a_vector_consisting_an_atom_and_convert_it_to_a_parse_item() {
        let tokens = &mut tokenize(~"bar");
        let parsed_item = read(tokens);
        println!("{:?}", parsed_item);
        match parsed_item {
            Atom(val) => {
                assert_eq!(val, ~"bar")
            },
            _ => assert!(false)
        }
    }
}
<commit_msg>more sophisticated tests for parse<commit_after>// Copyright 2013-2014 Jeffery Olson
//
// Licensed under the 3-Clause BSD License, see LICENSE.txt
// at the top-level of this repository.
// This file may not be copied, modified, or distributed
// except according to those terms.
#![crate_id="http://olsonjeffery.github.io#schemers:0.0.1"]
#![desc = "Simple Scheme Interpreter"]
#![license = "3-Clause BSD"]

// this is starting out as a straight port of Peter Norvig's
// lis.py (the first iteration) to Rust

#[cfg(not(test))]
fn main() {
    use std::os::args;
    let args: Vec<~str> = args().move_iter().skip(1).collect();
    if args.len() == 0 {
        fail!("no program provided");
    }
    let program: ~str = args.move_iter()
        .fold(~"", |memo, arg| memo + arg + " ").trim().to_owned();
    let tokens = &mut tokenize(program);
    println!("{:?}", read(tokens));
}

// parser impl
fn pad_input(input: ~str) -> ~str {
    input.replace("(", " ( ").replace(")", " ) ")
}

fn tokenize(input: ~str) -> Vec<~str> {
    pad_input(input).split_str(" ")
        .filter(|i| *i != "").map(|i| i.to_owned()).collect()
}

#[deriving(Eq, Show)]
pub enum ParseItem {
    Atom(~str),
    List(Vec<~ParseItem>)
}

impl ParseItem {
    pub fn is_atom(&self) -> bool {
        match *self {
            Atom(_) => true,
            _ => false
        }
    }
}

fn read(tokens: &mut Vec<~str>) -> ParseItem {
    let current_token =
        tokens.shift().expect("calling read() w/ empty token list; shouldn't happen");
    match current_token {
        ref x if *x == ~"(" => {
            let mut list = Vec::new();
            while *tokens.get(0) != ~")" {
                list.push(box read(tokens));
            }
            tokens.shift();
            List(list)
        },
        ref x if *x == ~")" => fail!("hit ) token; shouldn't happen"),
        x => Atom(x)
    }
}

#[cfg(test)]
mod parser_test {
    use super::{pad_input, tokenize, read, Atom, List};

    #[test]
    fn pad_input_should_insert_spaces_before_and_after_parens() {
        assert_eq!(pad_input(~"(x 1 2 3)"), ~" ( x 1 2 3 ) ");
    }

    #[test]
    fn tokenize_string_into_tokens() {
        let tokens = tokenize(~"(foo 12 3)");
        assert_eq!(tokens.len(), 5);
        assert_eq!(tokens.get(0).to_owned(), ~"(");
        assert_eq!(tokens.get(1).to_owned(), ~"foo");
        assert_eq!(tokens.get(2).to_owned(), ~"12");
        assert_eq!(tokens.get(3).to_owned(), ~"3");
        assert_eq!(tokens.get(4).to_owned(), ~")");
    }

    #[test]
    fn should_parse_tokens_consisting_an_atom_and_convert_it_to_a_parse_item() {
        let tokens = &mut tokenize(~"bar");
        let parsed_item = read(tokens);
        println!("{:?}", parsed_item);
        match parsed_item {
            Atom(val) => {
                assert_eq!(val, ~"bar")
            },
            _ => assert!(false)
        }
    }

    #[test]
    fn should_parse_tokens_consisting_of_a_list_of_atoms_and_parse_it() {
        let tokens = &mut tokenize(~"(bar 12 45)");
        let parsed_item = read(tokens);
        assert_eq!(parsed_item.is_atom(), false);
        match parsed_item {
            List(items) => {
                let items_len = items.len();
                assert!(3 == items_len);
                assert_eq!(items.get(0).is_atom(), true);
                assert_eq!(*items.get(0), ~Atom(~"bar"));
                assert_eq!(items.get(1).is_atom(), true);
                assert_eq!(*items.get(1), ~Atom(~"12"));
                assert_eq!(items.get(2).is_atom(), true);
                assert_eq!(*items.get(2), ~Atom(~"45"));
            },
            _ => fail!("got back an atom, it seems")
        }
    }
    #[test]
    fn should_parse_tokens_consisting_of_a_list_of_atoms_and_a_nested_list() {
        let tokens = &mut tokenize(~"((2 3) bar 12 (hee (hah)))");
        let parsed_item = read(tokens);
        assert_eq!(parsed_item.is_atom(), false);
        match parsed_item {
            List(items) => {
                let items_len = items.len();
                assert!(4 == items_len);
                match *items.get(0) {
                    ~List(ref items) => {
                        assert_eq!(items.len(), 2);
                        assert_eq!(*items.get(0), ~Atom(~"2"));
                        assert_eq!(*items.get(1), ~Atom(~"3"));
                    },
                    _ => fail!("shoulda got a list")
                }
                assert_eq!(*items.get(1), ~Atom(~"bar"));
                assert_eq!(*items.get(2), ~Atom(~"12"));
                match *items.get(3) {
                    ~List(ref items) => {
                        assert_eq!(items.len(), 2);
                        assert_eq!(*items.get(0), ~Atom(~"hee"));
                        match *items.get(1) {
                            ~List(ref items) => {
                                assert_eq!(items.len(), 1);
                                assert_eq!(*items.get(0), ~Atom(~"hah"));
                            },
                            _ => fail!("shoulda got a list")
                        }
                    },
                    _ => fail!("shoulda got a list")
                }
            },
            _ => fail!("got back an atom, it seems")
        }
    }
}
<|endoftext|>