<commit_before>use std::net::{SocketAddr, ToSocketAddrs};
use std::iter::Iterator;
use std::io::Result as IoResult;
use mioco;
use mioco::tcp::TcpListener;
use request::Request;
use response::Response;
use connection::{Connection, ConnResult};

macro_rules! try_com {
    ($com: expr, err => $errexpr: expr) => {
        match $com {
            ConnResult::Ok(x) => x,
            ConnResult::ParseErr(_) => $errexpr,
            ConnResult::IoError(_) => $errexpr,
        }
    }
}

///
/// HTTP Proxy Server implemenation
///
pub struct RainyProxy {
    pub addr: SocketAddr,
}

impl RainyProxy {
    pub fn new<T: ToSocketAddrs>(addr: &T) -> RainyProxy {
        let sock = addr.to_socket_addrs().unwrap().next().unwrap();
        RainyProxy { addr: sock }
    }

    pub fn serve(&self) -> IoResult<()> {
        let listener = try!(TcpListener::bind(&self.addr));
        debug!("Proxy server listen at {}", &self.addr);

        mioco::start(move || -> IoResult<()> {
            for _ in 0..mioco::thread_num() {
                let listener: TcpListener = try!(listener.try_clone());
                mioco::spawn(move || -> IoResult<()> {
                    loop {
                        let mut src_conn = Connection::new(try!(listener.accept()));
                        mioco::spawn(move || -> IoResult<()> {
                            loop {
                                // recieve source request
                                let request: Request = try_com!(src_conn.recieve(), err=>break);
                                debug!("receive from client.");

                                // connect to the server
                                let mut dest_conn = match Connection::from(&request.host()
                                                                                .as_str(),
                                                                           &request.port()) {
                                    Some(conn) => conn,
                                    None => break,
                                };
                                debug!("connect to server.");

                                // send request to destination host
                                try_com!(dest_conn.send(&request), err=>break);

                                debug!("send to server.");

                                // recieve destination response
                                let response: Response = try_com!(dest_conn.recieve(), err=>break);

                                debug!("recieved from server.");

                                // send response to source host
                                try_com!(src_conn.send(&response), err=>break);

                                debug!("send to client");

                                if request.must_close() {
                                    break;
                                }
                            }

                            Ok(())
                        });
                    }
                });
            }

            Ok(())
        });
        Ok(())
    }
}
<commit_msg>add customize point<commit_after>use std::net::{SocketAddr, ToSocketAddrs};
use std::iter::Iterator;
use std::io::Result as IoResult;
use std::sync::Arc;
use mioco;
use mioco::tcp::TcpListener;
use request::Request;
use response::Response;
use connection::{Connection, ConnResult};

macro_rules! try_com {
    ($com: expr, err => $errexpr: expr) => {
        match $com {
            ConnResult::Ok(x) => x,
            ConnResult::ParseErr(_) => $errexpr,
            ConnResult::IoError(_) => $errexpr,
        }
    }
}

///
/// HTTP Proxy Server implemenation
///
pub struct RainyProxy {
    pub addr: SocketAddr,
}

impl RainyProxy {
    pub fn new<T: ToSocketAddrs>(addr: &T) -> RainyProxy {
        let sock = addr.to_socket_addrs().unwrap().next().unwrap();

        RainyProxy { addr: sock }
    }

    pub fn serve(&self) -> IoResult<()> {
        self.serve_custom(|&mut _, &mut _| {}, |&mut _| {})
    }

    pub fn serve_custom<RQ, RS>(&self, on_request: RQ, on_response: RS) -> IoResult<()>
        where RQ: Fn(&mut Request, &mut Option<Response>) + 'static + Send + Sync,
              RS: Fn(&mut Response) + 'static + Send + Sync
    {
        let listener = try!(TcpListener::bind(&self.addr));
        debug!("Proxy server listen at {}", &self.addr);

        let handlers = Arc::new((on_request, on_response));
        mioco::start(move || -> IoResult<()> {
            for _ in 0..mioco::thread_num() {
                let listener: TcpListener = try!(listener.try_clone());
                let _handlers = handlers.clone();

                mioco::spawn(move || -> IoResult<()> {
                    loop {
                        let mut src_conn = Connection::new(try!(listener.accept()));
                        let __handlers = _handlers.clone();

                        mioco::spawn(move || -> IoResult<()> {
                            loop {
                                // recieve source request
                                let mut request: Request = try_com!(src_conn.recieve(), err=>break);
                                debug!("receive from client.");

                                // connect to the server
                                let mut dest_conn = match Connection::from(&request.host()
                                                                                .as_str(),
                                                                           &request.port()) {
                                    Some(conn) => conn,
                                    None => break,
                                };
                                debug!("connect to server.");

                                let mut user_res = None;
                                __handlers.0(&mut request, &mut user_res);

                                // send request to destination host
                                try_com!(dest_conn.send(&request), err=>break);

                                debug!("send to server.");

                                // recieve destination response
                                let mut response: Response = match user_res {
                                    Some(r) => r,
                                    None => try_com!(dest_conn.recieve(), err=>break),
                                };

                                debug!("recieved from server.");

                                __handlers.1(&mut response);

                                // send response to source host
                                try_com!(src_conn.send(&response), err=>break);

                                debug!("send to client");

                                if request.must_close() {
                                    break;
                                };
                            }

                            Ok(())
                        });
                    }
                });
            }

            Ok(())
        });
        Ok(())
    }
}
<|endoftext|>


<commit_before>#[derive(Serialize)]
pub struct CardParams<'a> {
    pub object: &'static str, // must be "card"
    pub exp_month: &'a str,    // eg. "12"
    pub exp_year: &'a str,     // eg. "17" or 2017"

    pub number: &'a str,       // card number
    pub name: Option<&'a str>, // cardholder's full name
    pub cvc: Option<&'a str>,  // card security code
}

impl<'a> Default for CardParams<'a> {
    fn default() -> Self {
        CardParams{
            object: "card",
            exp_month: "",
            exp_year: "",
            number: "",
            name: None,
            cvc: None,
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct Card {
    pub id: String,
    pub address_city: Option<String>,
    pub address_country: Option<String>,
    pub address_line1: Option<String>,
    pub address_line1_check: Option<String>, // (pass, fail, unavailable, unchecked)
    pub address_line2: Option<String>,
    pub address_state: Option<String>,
    pub address_zip: Option<String>,
    pub address_zip_check: Option<String>, // (pass, fail, unavailable, unchecked)
    pub brand: String, // (Visa, American Express, MasterCard, Discover, JCB, Diners Club, or Unknown)
    pub country: String, // eg. "US"
    pub customer: Option<String>,
    pub cvc_check: Option<String>, // (pass, fail, unavailable, unchecked)
    pub exp_month: u32,
    pub exp_year: u32,
    pub fingerprint: String,
    pub funding: String, // (credit, debit, prepaid, unknown)
}
<commit_msg>Add card last 4 digit number<commit_after>#[derive(Serialize)]
pub struct CardParams<'a> {
    pub object: &'static str, // must be "card"
    pub exp_month: &'a str,    // eg. "12"
    pub exp_year: &'a str,     // eg. "17" or 2017"

    pub number: &'a str,       // card number
    pub name: Option<&'a str>, // cardholder's full name
    pub cvc: Option<&'a str>,  // card security code
}

impl<'a> Default for CardParams<'a> {
    fn default() -> Self {
        CardParams{
            object: "card",
            exp_month: "",
            exp_year: "",
            number: "",
            name: None,
            cvc: None,
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct Card {
    pub id: String,
    pub address_city: Option<String>,
    pub address_country: Option<String>,
    pub address_line1: Option<String>,
    pub address_line1_check: Option<String>, // (pass, fail, unavailable, unchecked)
    pub address_line2: Option<String>,
    pub address_state: Option<String>,
    pub address_zip: Option<String>,
    pub address_zip_check: Option<String>, // (pass, fail, unavailable, unchecked)
    pub brand: String, // (Visa, American Express, MasterCard, Discover, JCB, Diners Club, or Unknown)
    pub country: String, // eg. "US"
    pub customer: Option<String>,
    pub cvc_check: Option<String>, // (pass, fail, unavailable, unchecked)
    pub exp_month: u32,
    pub exp_year: u32,
    pub fingerprint: String,
    pub funding: String, // (credit, debit, prepaid, unknown)
    pub last4: String,
}
<|endoftext|>


<commit_before>//! Decoding of AVIF images.
///
/// The [AVIF] specification defines an image derivative of the AV1 bitstream, an open video codec.
///
/// [AVIF]: https://aomediacodec.github.io/av1-avif/
use std::convert::TryFrom;
use std::error::Error;
use std::io::{self, Cursor, Read};
use std::marker::PhantomData;
use std::mem;

use crate::error::DecodingError;
use crate::{ColorType, ImageDecoder, ImageError, ImageFormat, ImageResult};

use dav1d::{PixelLayout, PlanarImageComponent};
use dcv_color_primitives as dcp;
use mp4parse::{read_avif, ParseStrictness};

fn error_map<E: Into<Box<dyn Error + Send + Sync>>>(err: E) -> ImageError {
    ImageError::Decoding(DecodingError::new(ImageFormat::Avif.into(), err))
}

/// AVIF Decoder.
///
/// Reads one image into the chosen input.
pub struct AvifDecoder<R> {
    inner: PhantomData<R>,
    picture: dav1d::Picture,
    alpha_picture: Option<dav1d::Picture>,
}

impl<R: Read> AvifDecoder<R> {
    /// Create a new decoder that reads its input from `r`.
    pub fn new(mut r: R) -> ImageResult<Self> {
        let ctx = read_avif(&mut r, ParseStrictness::Normal).map_err(error_map)?;
        let mut primary_decoder = dav1d::Decoder::new();
        let coded = ctx.primary_item_coded_data();
        primary_decoder
            .send_data(coded, None, None, None)
            .map_err(error_map)?;
        let picture = primary_decoder.get_picture().map_err(error_map)?;
        let alpha_item = ctx.alpha_item_coded_data();
        let alpha_picture = if !alpha_item.is_empty() {
            let mut alpha_decoder = dav1d::Decoder::new();
            alpha_decoder
                .send_data(alpha_item, None, None, None)
                .map_err(error_map)?;
            Some(alpha_decoder.get_picture().map_err(error_map)?)
        } else {
            None
        };
        assert_eq!(picture.bit_depth(), 8);
        Ok(AvifDecoder {
            inner: PhantomData,
            picture,
            alpha_picture,
        })
    }
}

/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct AvifReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for AvifReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        if self.0.position() == 0 && buf.is_empty() {
            mem::swap(buf, self.0.get_mut());
            Ok(buf.len())
        } else {
            self.0.read_to_end(buf)
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for AvifDecoder<R> {
    type Reader = AvifReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        (self.picture.width(), self.picture.height())
    }

    fn color_type(&self) -> ColorType {
        ColorType::Rgba8
    }

    fn into_reader(self) -> ImageResult<Self::Reader> {
        let plane = self.picture.plane(PlanarImageComponent::Y);
        Ok(AvifReader(
            Cursor::new(plane.as_ref().to_vec()),
            PhantomData,
        ))
    }

    fn read_image(self, buf: &mut [u8]) -> ImageResult<()> {
        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));

        dcp::initialize();

        if self.picture.pixel_layout() != PixelLayout::I400 {
            let pixel_format = match self.picture.pixel_layout() {
                PixelLayout::I400 => todo!(),
                PixelLayout::I420 => dcp::PixelFormat::I420,
                PixelLayout::I422 => dcp::PixelFormat::I422,
                PixelLayout::I444 => dcp::PixelFormat::I444,
                PixelLayout::Unknown => panic!("Unknown pixel layout"),
            };
            let src_format = dcp::ImageFormat {
                pixel_format,
                color_space: dcp::ColorSpace::Bt601,
                num_planes: 3,
            };
            let dst_format = dcp::ImageFormat {
                pixel_format: dcp::PixelFormat::Bgra,
                color_space: dcp::ColorSpace::Lrgb,
                num_planes: 1,
            };
            let (width, height) = self.dimensions();
            let planes = &[
                self.picture.plane(PlanarImageComponent::Y),
                self.picture.plane(PlanarImageComponent::U),
                self.picture.plane(PlanarImageComponent::V),
            ];
            let src_buffers = planes.iter().map(AsRef::as_ref).collect::<Vec<_>>();
            let strides = &[
                self.picture.stride(PlanarImageComponent::Y) as usize,
                self.picture.stride(PlanarImageComponent::U) as usize,
                self.picture.stride(PlanarImageComponent::V) as usize,
            ];
            let dst_buffers = &mut [&mut buf[..]];
            dcp::convert_image(
                width,
                height,
                &src_format,
                Some(strides),
                &src_buffers,
                &dst_format,
                None,
                dst_buffers,
            )
            .map_err(error_map)?;
        } else {
            let plane = self.picture.plane(PlanarImageComponent::Y);
            buf.copy_from_slice(plane.as_ref());
        }

        if let Some(picture) = self.alpha_picture {
            assert_eq!(picture.pixel_layout(), PixelLayout::I400);
            let stride = picture.stride(PlanarImageComponent::Y) as usize;
            let plane = picture.plane(PlanarImageComponent::Y);
            let width = picture.width();
            for (buf, slice) in Iterator::zip(
                buf.chunks_exact_mut(width as usize * 4),
                plane.as_ref().chunks_exact(stride),
            ) {
                for i in 0..width as usize {
                    buf[3 + i * 4] = slice[i];
                }
            }
        }

        // Convert Bgra to Rgba
        for chunk in buf.chunks_exact_mut(4) {
            chunk.swap(0, 2);
        }

        Ok(())
    }
}
<commit_msg>avif-decoder: Convert directly to RGBA<commit_after>//! Decoding of AVIF images.
///
/// The [AVIF] specification defines an image derivative of the AV1 bitstream, an open video codec.
///
/// [AVIF]: https://aomediacodec.github.io/av1-avif/
use std::convert::TryFrom;
use std::error::Error;
use std::io::{self, Cursor, Read};
use std::marker::PhantomData;
use std::mem;

use crate::error::DecodingError;
use crate::{ColorType, ImageDecoder, ImageError, ImageFormat, ImageResult};

use dav1d::{PixelLayout, PlanarImageComponent};
use dcv_color_primitives as dcp;
use mp4parse::{read_avif, ParseStrictness};

fn error_map<E: Into<Box<dyn Error + Send + Sync>>>(err: E) -> ImageError {
    ImageError::Decoding(DecodingError::new(ImageFormat::Avif.into(), err))
}

/// AVIF Decoder.
///
/// Reads one image into the chosen input.
pub struct AvifDecoder<R> {
    inner: PhantomData<R>,
    picture: dav1d::Picture,
    alpha_picture: Option<dav1d::Picture>,
}

impl<R: Read> AvifDecoder<R> {
    /// Create a new decoder that reads its input from `r`.
    pub fn new(mut r: R) -> ImageResult<Self> {
        let ctx = read_avif(&mut r, ParseStrictness::Normal).map_err(error_map)?;
        let mut primary_decoder = dav1d::Decoder::new();
        let coded = ctx.primary_item_coded_data();
        primary_decoder
            .send_data(coded, None, None, None)
            .map_err(error_map)?;
        let picture = primary_decoder.get_picture().map_err(error_map)?;
        let alpha_item = ctx.alpha_item_coded_data();
        let alpha_picture = if !alpha_item.is_empty() {
            let mut alpha_decoder = dav1d::Decoder::new();
            alpha_decoder
                .send_data(alpha_item, None, None, None)
                .map_err(error_map)?;
            Some(alpha_decoder.get_picture().map_err(error_map)?)
        } else {
            None
        };
        assert_eq!(picture.bit_depth(), 8);
        Ok(AvifDecoder {
            inner: PhantomData,
            picture,
            alpha_picture,
        })
    }
}

/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct AvifReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for AvifReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        if self.0.position() == 0 && buf.is_empty() {
            mem::swap(buf, self.0.get_mut());
            Ok(buf.len())
        } else {
            self.0.read_to_end(buf)
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for AvifDecoder<R> {
    type Reader = AvifReader<R>;

    fn dimensions(&self) -> (u32, u32) {
        (self.picture.width(), self.picture.height())
    }

    fn color_type(&self) -> ColorType {
        ColorType::Rgba8
    }

    fn into_reader(self) -> ImageResult<Self::Reader> {
        let plane = self.picture.plane(PlanarImageComponent::Y);
        Ok(AvifReader(
            Cursor::new(plane.as_ref().to_vec()),
            PhantomData,
        ))
    }

    fn read_image(self, buf: &mut [u8]) -> ImageResult<()> {
        assert_eq!(u64::try_from(buf.len()), Ok(self.total_bytes()));

        dcp::initialize();

        if self.picture.pixel_layout() != PixelLayout::I400 {
            let pixel_format = match self.picture.pixel_layout() {
                PixelLayout::I400 => todo!(),
                PixelLayout::I420 => dcp::PixelFormat::I420,
                PixelLayout::I422 => dcp::PixelFormat::I422,
                PixelLayout::I444 => dcp::PixelFormat::I444,
                PixelLayout::Unknown => panic!("Unknown pixel layout"),
            };
            let src_format = dcp::ImageFormat {
                pixel_format,
                color_space: dcp::ColorSpace::Bt601,
                num_planes: 3,
            };
            let dst_format = dcp::ImageFormat {
                pixel_format: dcp::PixelFormat::Rgba,
                color_space: dcp::ColorSpace::Lrgb,
                num_planes: 1,
            };
            let (width, height) = self.dimensions();
            let planes = &[
                self.picture.plane(PlanarImageComponent::Y),
                self.picture.plane(PlanarImageComponent::U),
                self.picture.plane(PlanarImageComponent::V),
            ];
            let src_buffers = planes.iter().map(AsRef::as_ref).collect::<Vec<_>>();
            let strides = &[
                self.picture.stride(PlanarImageComponent::Y) as usize,
                self.picture.stride(PlanarImageComponent::U) as usize,
                self.picture.stride(PlanarImageComponent::V) as usize,
            ];
            let dst_buffers = &mut [&mut buf[..]];
            dcp::convert_image(
                width,
                height,
                &src_format,
                Some(strides),
                &src_buffers,
                &dst_format,
                None,
                dst_buffers,
            )
            .map_err(error_map)?;
        } else {
            let plane = self.picture.plane(PlanarImageComponent::Y);
            buf.copy_from_slice(plane.as_ref());
        }

        if let Some(picture) = self.alpha_picture {
            assert_eq!(picture.pixel_layout(), PixelLayout::I400);
            let stride = picture.stride(PlanarImageComponent::Y) as usize;
            let plane = picture.plane(PlanarImageComponent::Y);
            let width = picture.width();
            for (buf, slice) in Iterator::zip(
                buf.chunks_exact_mut(width as usize * 4),
                plane.as_ref().chunks_exact(stride),
            ) {
                for i in 0..width as usize {
                    buf[3 + i * 4] = slice[i];
                }
            }
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::iter::{once, repeat, FromIterator};
use std::ops::Index;

use memory::{MemoryLayout, MemoryBlock, CellIndex, MemSize};
use operations::{Operation, Operations};

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Instructions(Vec<Instruction>);

impl Instructions {
    pub fn len(&self) -> usize {
        self.0.len()
    }

    pub fn last(&self) -> Option<&Instruction> {
        self.0.last()
    }

    pub fn iter(&self) -> ::std::slice::Iter<Instruction> {
        self.0.iter()
    }

    pub fn remove(&mut self, index: usize) -> Instruction {
        self.0.remove(index)
    }

    pub fn pop(&mut self) -> Option<Instruction> {
        self.0.pop()
    }

    pub fn truncate(&mut self, len: usize) {
        self.0.truncate(len)
    }

    pub fn clear(&mut self) {
        self.0.clear()
    }

}

impl Index<usize> for Instructions {
    type Output = Instruction;
    fn index(&self, index: usize) -> &Self::Output {
        &self.0[index]
    }
}

impl IntoIterator for Instructions {
    type Item = Instruction;
    type IntoIter = ::std::vec::IntoIter<Instruction>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl FromIterator<Instruction> for Instructions {
    fn from_iter<I: IntoIterator<Item=Instruction>>(iter: I) -> Self {
        Instructions(iter.into_iter().collect())
    }
}

impl FromIterator<Instruction> for String {
    fn from_iter<I: IntoIterator<Item=Instruction>>(iter: I) -> Self {
        iter.into_iter().map(|instr| instr.to_string()).collect()
    }
}

impl From<Instructions> for String {
    fn from(instrs: Instructions) -> String {
        instrs.into_iter().collect()
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Instruction {
    // ">" - increment the pointer (move it to the "right")
    Right,
    // "<" - decrement the pointer (move it to the "left")
    Left,
    // "+" - increment the byte at the pointer
    Increment,
    // "-" - decrement the byte at the pointer
    Decrement,
    // "." - output the byte at the pointer
    Write,
    // "," - input a byte and store it in the byte at the pointer
    Read,
    // "[" - jump forward past the matching ] if the byte at the pointer is zero
    JumpForwardIfZero,
    // "]" - jump backward to the matching [ unless the byte at the pointer is zero
    JumpBackwardUnlessZero,
}

impl fmt::Display for Instruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Instruction::*;
        f.write_str(match *self {
            Right => ">",
            Left => "<",
            Increment => "+",
            Decrement => "-",
            Write => ".",
            Read => ",",
            JumpForwardIfZero => "[",
            JumpBackwardUnlessZero => "]",
        })
    }
}

impl From<Operations> for Instructions {
    fn from(ops: Operations) -> Instructions {
        let mut current_cell = 0;
        let mut layout = MemoryLayout::new();

        into_instructions_index(ops, &mut layout, &mut current_cell)
    }
}

fn into_instructions_index(
    ops: Operations,
    layout: &mut MemoryLayout,
    current_cell: &mut CellIndex,
) -> Instructions {
    use self::Operation::*;
    ops.into_iter().flat_map(|op| match op {
        Block {body} => into_instructions_index(body, layout, current_cell),
        TempAllocate {temp, body, should_zero} => {
            let instrs = into_instructions_index(body, layout, current_cell);
            layout.remove(&temp);
            if should_zero {
                instrs.into_iter().chain(zero(current_cell, layout, temp)).collect()
            }
            else {
                instrs
            }
        },
        Increment {target, amount} => {
            move_to(current_cell, layout.position(&target)).into_iter()
                .chain(repeat(Instruction::Increment).take(amount as usize)).collect()
        },
        Decrement {target, amount} => {
            move_to(current_cell, layout.position(&target)).into_iter()
                .chain(repeat(Instruction::Decrement).take(amount as usize)).collect()
        },
        Read {target} => {
            move_to(current_cell, layout.position(&target.position())).into_iter()
                .chain(consecutive(vec![Instruction::Read], current_cell, target.size())).collect()
        },
        Write {target} => {
            move_to(current_cell, layout.position(&target.position())).into_iter()
                .chain(consecutive(vec![Instruction::Write], current_cell, target.size())).collect()
        },
        Zero {target} => zero(current_cell, layout, target),
        Branch {cond, if_body, else_body} => {
            // Algorithm from: https://esolangs.org/wiki/Brainfuck_algorithms#if_.28x.29_.7B_code1_.7D_else_.7B_code2_.7D
            //
            // temp0 and temp1 are consecutive in memory following cond
            // temp0[-]+
            // temp1[-]
            // cond[
            //  if_block
            //  cond>-]>
            // [<
            //  else_block
            //  cond>->]
            //
            // Three consecutive temporary cells:
            // 1. cond - the boolean result of the condition expression
            // 2. temp0 - used to go into the else block when necessary
            // 3. temp1 - used *not* to go into the else block when necessary
            //
            // The basic idea of the algorithm is that you can control which of two adjacent loops run
            // by "sending" them either temp0 or temp1 based on the condition result
            layout.consecutive(&cond, 2, |layout, cond, temp| {
                move_to(current_cell, temp.position()).into_iter()
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, cond))
                    .chain(once(Instruction::JumpForwardIfZero))

                    .chain(into_instructions_index(if_body, layout, current_cell))
                    .chain(move_to(current_cell, cond))
                    .chain(once(Instruction::Right))
                    .chain(once(Instruction::Decrement))

                    .chain(once(Instruction::JumpBackwardUnlessZero))

                    .chain(once(Instruction::Right))

                    .chain(once(Instruction::JumpForwardIfZero))
                    .chain(once(Instruction::Left))

                    .chain(into_instructions_index(else_body, layout, current_cell))
                    .chain(move_to(current_cell, cond))
                    .chain(once(Instruction::Right))
                    .chain(once(Instruction::Decrement))
                    .chain(once(Instruction::Right))

                    .chain(once(Instruction::JumpBackwardUnlessZero))
                    .chain(once(Instruction::Left))
                    .chain(once(Instruction::Left))

                    .collect()
            })
        },
        Loop {cond, body} => {
            move_to(current_cell, layout.position(&cond)).into_iter()
                .chain(once(Instruction::JumpForwardIfZero))
                .chain(into_instructions_index(body, layout, current_cell))
                .chain(move_to(current_cell, layout.position(&cond)))
                .chain(once(Instruction::JumpBackwardUnlessZero))
                .collect()
        },
        Copy {source, target, size} => {
            debug_assert!(source.associated_memory().size() - source.offset() == size);
            debug_assert!(target.associated_memory().size() - target.offset() == size);

            // Algorithm for copying cells:
            // 1. In a loop, decrement the source cell and increment both the target cell and a
            //    temporary cell until the source cell is zero
            // 2. In a loop, decrement the temporary cell and increment the source cell until the
            //    temporary cell is zero
            // 3. Repeat these steps for each cell to be copied

            let source = layout.position(&source);
            let target = layout.position(&target);
            layout.temporary(1, |temp| (0..size).flat_map(|i| {
                move_to(current_cell, source + i).into_iter()
                    // Fill the target and the temporary with the value of the source cell
                    .chain(once(Instruction::JumpForwardIfZero))

                    .chain(move_to(current_cell, target + i))
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, temp.position()))
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, source + i))
                    .chain(once(Instruction::Decrement))

                    .chain(once(Instruction::JumpBackwardUnlessZero))

                    // Refill the source cell with the temporary
                    .chain(move_to(current_cell, temp.position()))
                    .chain(once(Instruction::JumpForwardIfZero))

                    .chain(move_to(current_cell, source + i))
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, temp.position()))
                    .chain(once(Instruction::Decrement))

                    .chain(once(Instruction::JumpBackwardUnlessZero))
            }).collect())
        },
        Relocate {source, target} => {
            debug_assert!(source.size() == target.size());
            let size = source.size();

            let source = layout.position(&source.position());
            let target = layout.position(&target.position());

            (0..size).flat_map(|i| {
                move_to(current_cell, source + i).into_iter()
                    .chain(once(Instruction::JumpForwardIfZero))

                    .chain(move_to(current_cell, target + i))
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, source + i))
                    .chain(once(Instruction::Decrement))

                    .chain(once(Instruction::JumpBackwardUnlessZero))
            }).collect()
        },
    }).collect()
}

fn zero(current_cell: &mut CellIndex, layout: &mut MemoryLayout, target: MemoryBlock) -> Instructions {
    move_to(current_cell, layout.position(&target.position())).into_iter()
        .chain(consecutive(vec![
            Instruction::JumpForwardIfZero,
            Instruction::Decrement,
            Instruction::JumpBackwardUnlessZero,
        ], current_cell, target.size())).collect()
}

fn move_to(current_cell: &mut CellIndex, target: CellIndex) -> Vec<Instruction> {
    let current = *current_cell;
    *current_cell = target;

    if current > target {
        repeat(Instruction::Left).take(current - target).collect()
    }
    else if target > current {
        repeat(Instruction::Right).take(target - current).collect()
    }
    else {
        Vec::new()
    }
}

fn consecutive(instrs: Vec<Instruction>, current_cell: &mut CellIndex, size: MemSize) -> Vec<Instruction> {
    *current_cell += size;
    (0..size).flat_map(|_| instrs.clone().into_iter().chain(once(Instruction::Right))).collect()
}
<commit_msg>Made copying something to itself a no-op<commit_after>use std::fmt;
use std::iter::{once, repeat, empty, FromIterator};
use std::ops::Index;

use memory::{MemoryLayout, MemoryBlock, CellIndex, MemSize};
use operations::{Operation, Operations};

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Instructions(Vec<Instruction>);

impl Instructions {
    pub fn len(&self) -> usize {
        self.0.len()
    }

    pub fn last(&self) -> Option<&Instruction> {
        self.0.last()
    }

    pub fn iter(&self) -> ::std::slice::Iter<Instruction> {
        self.0.iter()
    }

    pub fn remove(&mut self, index: usize) -> Instruction {
        self.0.remove(index)
    }

    pub fn pop(&mut self) -> Option<Instruction> {
        self.0.pop()
    }

    pub fn truncate(&mut self, len: usize) {
        self.0.truncate(len)
    }

    pub fn clear(&mut self) {
        self.0.clear()
    }

}

impl Index<usize> for Instructions {
    type Output = Instruction;
    fn index(&self, index: usize) -> &Self::Output {
        &self.0[index]
    }
}

impl IntoIterator for Instructions {
    type Item = Instruction;
    type IntoIter = ::std::vec::IntoIter<Instruction>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl FromIterator<Instruction> for Instructions {
    fn from_iter<I: IntoIterator<Item=Instruction>>(iter: I) -> Self {
        Instructions(iter.into_iter().collect())
    }
}

impl FromIterator<Instruction> for String {
    fn from_iter<I: IntoIterator<Item=Instruction>>(iter: I) -> Self {
        iter.into_iter().map(|instr| instr.to_string()).collect()
    }
}

impl From<Instructions> for String {
    fn from(instrs: Instructions) -> String {
        instrs.into_iter().collect()
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Instruction {
    // ">" - increment the pointer (move it to the "right")
    Right,
    // "<" - decrement the pointer (move it to the "left")
    Left,
    // "+" - increment the byte at the pointer
    Increment,
    // "-" - decrement the byte at the pointer
    Decrement,
    // "." - output the byte at the pointer
    Write,
    // "," - input a byte and store it in the byte at the pointer
    Read,
    // "[" - jump forward past the matching ] if the byte at the pointer is zero
    JumpForwardIfZero,
    // "]" - jump backward to the matching [ unless the byte at the pointer is zero
    JumpBackwardUnlessZero,
}

impl fmt::Display for Instruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Instruction::*;
        f.write_str(match *self {
            Right => ">",
            Left => "<",
            Increment => "+",
            Decrement => "-",
            Write => ".",
            Read => ",",
            JumpForwardIfZero => "[",
            JumpBackwardUnlessZero => "]",
        })
    }
}

impl From<Operations> for Instructions {
    fn from(ops: Operations) -> Instructions {
        let mut current_cell = 0;
        let mut layout = MemoryLayout::new();

        into_instructions_index(ops, &mut layout, &mut current_cell)
    }
}

fn into_instructions_index(
    ops: Operations,
    layout: &mut MemoryLayout,
    current_cell: &mut CellIndex,
) -> Instructions {
    use self::Operation::*;
    ops.into_iter().flat_map(|op| match op {
        Block {body} => into_instructions_index(body, layout, current_cell),
        TempAllocate {temp, body, should_zero} => {
            let instrs = into_instructions_index(body, layout, current_cell);
            layout.remove(&temp);
            if should_zero {
                instrs.into_iter().chain(zero(current_cell, layout, temp)).collect()
            }
            else {
                instrs
            }
        },
        Increment {target, amount} => {
            move_to(current_cell, layout.position(&target)).into_iter()
                .chain(repeat(Instruction::Increment).take(amount as usize)).collect()
        },
        Decrement {target, amount} => {
            move_to(current_cell, layout.position(&target)).into_iter()
                .chain(repeat(Instruction::Decrement).take(amount as usize)).collect()
        },
        Read {target} => {
            move_to(current_cell, layout.position(&target.position())).into_iter()
                .chain(consecutive(vec![Instruction::Read], current_cell, target.size())).collect()
        },
        Write {target} => {
            move_to(current_cell, layout.position(&target.position())).into_iter()
                .chain(consecutive(vec![Instruction::Write], current_cell, target.size())).collect()
        },
        Zero {target} => zero(current_cell, layout, target),
        Branch {cond, if_body, else_body} => {
            // Algorithm from: https://esolangs.org/wiki/Brainfuck_algorithms#if_.28x.29_.7B_code1_.7D_else_.7B_code2_.7D
            //
            // temp0 and temp1 are consecutive in memory following cond
            // temp0[-]+
            // temp1[-]
            // cond[
            //  if_block
            //  cond>-]>
            // [<
            //  else_block
            //  cond>->]
            //
            // Three consecutive temporary cells:
            // 1. cond - the boolean result of the condition expression
            // 2. temp0 - used to go into the else block when necessary
            // 3. temp1 - used *not* to go into the else block when necessary
            //
            // The basic idea of the algorithm is that you can control which of two adjacent loops run
            // by "sending" them either temp0 or temp1 based on the condition result
            layout.consecutive(&cond, 2, |layout, cond, temp| {
                move_to(current_cell, temp.position()).into_iter()
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, cond))
                    .chain(once(Instruction::JumpForwardIfZero))

                    .chain(into_instructions_index(if_body, layout, current_cell))
                    .chain(move_to(current_cell, cond))
                    .chain(once(Instruction::Right))
                    .chain(once(Instruction::Decrement))

                    .chain(once(Instruction::JumpBackwardUnlessZero))

                    .chain(once(Instruction::Right))

                    .chain(once(Instruction::JumpForwardIfZero))
                    .chain(once(Instruction::Left))

                    .chain(into_instructions_index(else_body, layout, current_cell))
                    .chain(move_to(current_cell, cond))
                    .chain(once(Instruction::Right))
                    .chain(once(Instruction::Decrement))
                    .chain(once(Instruction::Right))

                    .chain(once(Instruction::JumpBackwardUnlessZero))
                    .chain(once(Instruction::Left))
                    .chain(once(Instruction::Left))

                    .collect()
            })
        },
        Loop {cond, body} => {
            move_to(current_cell, layout.position(&cond)).into_iter()
                .chain(once(Instruction::JumpForwardIfZero))
                .chain(into_instructions_index(body, layout, current_cell))
                .chain(move_to(current_cell, layout.position(&cond)))
                .chain(once(Instruction::JumpBackwardUnlessZero))
                .collect()
        },
        Copy {source, target, size} => {
            // Copying to the same position is a no-op
            if source == target {
                return empty().collect();
            }

            debug_assert!(source.associated_memory().size() - source.offset() == size);
            debug_assert!(target.associated_memory().size() - target.offset() == size);

            // Algorithm for copying cells:
            // 1. In a loop, decrement the source cell and increment both the target cell and a
            //    temporary cell until the source cell is zero
            // 2. In a loop, decrement the temporary cell and increment the source cell until the
            //    temporary cell is zero
            // 3. Repeat these steps for each cell to be copied

            let source = layout.position(&source);
            let target = layout.position(&target);
            layout.temporary(1, |temp| (0..size).flat_map(|i| {
                move_to(current_cell, source + i).into_iter()
                    // Fill the target and the temporary with the value of the source cell
                    .chain(once(Instruction::JumpForwardIfZero))

                    .chain(move_to(current_cell, target + i))
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, temp.position()))
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, source + i))
                    .chain(once(Instruction::Decrement))

                    .chain(once(Instruction::JumpBackwardUnlessZero))

                    // Refill the source cell with the temporary
                    .chain(move_to(current_cell, temp.position()))
                    .chain(once(Instruction::JumpForwardIfZero))

                    .chain(move_to(current_cell, source + i))
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, temp.position()))
                    .chain(once(Instruction::Decrement))

                    .chain(once(Instruction::JumpBackwardUnlessZero))
            }).collect())
        },
        Relocate {source, target} => {
            debug_assert!(source.size() == target.size());
            let size = source.size();

            let source = layout.position(&source.position());
            let target = layout.position(&target.position());

            (0..size).flat_map(|i| {
                move_to(current_cell, source + i).into_iter()
                    .chain(once(Instruction::JumpForwardIfZero))

                    .chain(move_to(current_cell, target + i))
                    .chain(once(Instruction::Increment))

                    .chain(move_to(current_cell, source + i))
                    .chain(once(Instruction::Decrement))

                    .chain(once(Instruction::JumpBackwardUnlessZero))
            }).collect()
        },
    }).collect()
}

fn zero(current_cell: &mut CellIndex, layout: &mut MemoryLayout, target: MemoryBlock) -> Instructions {
    move_to(current_cell, layout.position(&target.position())).into_iter()
        .chain(consecutive(vec![
            Instruction::JumpForwardIfZero,
            Instruction::Decrement,
            Instruction::JumpBackwardUnlessZero,
        ], current_cell, target.size())).collect()
}

fn move_to(current_cell: &mut CellIndex, target: CellIndex) -> Vec<Instruction> {
    let current = *current_cell;
    *current_cell = target;

    if current > target {
        repeat(Instruction::Left).take(current - target).collect()
    }
    else if target > current {
        repeat(Instruction::Right).take(target - current).collect()
    }
    else {
        Vec::new()
    }
}

fn consecutive(instrs: Vec<Instruction>, current_cell: &mut CellIndex, size: MemSize) -> Vec<Instruction> {
    *current_cell += size;
    (0..size).flat_map(|_| instrs.clone().into_iter().chain(once(Instruction::Right))).collect()
}
<|endoftext|>


<commit_before>extern crate tempfile;

use std::fmt::{ Display, Formatter, Error };
use std::iter::Iterator;
use std::collections::HashMap;
use std::collections::HashSet;
use std::vec::Vec;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;

use std::clone::Clone;

/**
 * test can be deleted.
 * clauses will house all clauses, key is int so that we can use occurrences
 * ID for simplifications later
 * occurrences tracks which clauses literals are used in
 */
#[derive(Debug)]
pub struct CNF {
    pub nvar        : i32,
    pub nclause     : i32,
    pub clauses     : HashMap<i32, Vec<i32>>,
    pub occurrences : HashMap<i32, Vec<i32>>,
    pub units       : HashSet<i32>
}

impl CNF {
    pub fn new(nvar: i32, nclause: i32) -> CNF {
        CNF {
            nvar        : nvar,
            nclause     : nclause,
            clauses     : HashMap::new(),
            occurrences : HashMap::new(),
            units       : HashSet::new(),
        }
    }

    /// Add a clause, return the ID of the inserted clause
    /// Right now, this isn't public; api is odd as we have an odd representation of literals.
    /// TODO: Mask this with public function?
    fn add_clause(&mut self, clause: Vec<i32>) -> i32 {
        assert!(clause.len() > 0);
        let id: i32 = self.clauses.len() as i32;
        if clause.len() == 1 { self.units.insert(id); }
        for var in &clause {
            let occ = self.occurrences.entry(*var).or_insert(Vec::new());
            occ.push(id);
        }
        self.clauses.insert(id, clause);
        id
    }

    /// Unit propagation: propagate the literal associated with the clause id `clause`, and remove
    /// it from `self.units`.
    pub fn unit_propagate(&mut self, unit: i32) {
        // Remove clauses with lit and remove lit from occurrences.
        let occurrences = &self.occurrences.remove(
            &self.clauses.get(&unit).expect("unit clause not found")[0]
        ).unwrap();
        for occ in occurrences {
            self.clauses.remove(&occ);
        }
        // This needs to be true, i.e. unit clause id needs to be in the unit clauses
        assert!(self.units.remove(&unit))
    }

    /// Remove all clauses containing literal `lit` from the CNF, and remove the negation of `lit`
    /// from the remaining clauses.
    pub fn propagate(&mut self, lit: i32) {
        // Remove clauses with lit and remove lit from occurrences.
        for occ in &self.occurrences.remove(&lit).unwrap() {
            self.clauses.remove(occ);
        }
    }
}

impl Clone for CNF {
    fn clone(&self) -> CNF {
        CNF {
            nvar        : self.nvar,
            nclause     : self.nclause,
            clauses     : self.clauses.clone(),
            occurrences : self.occurrences.clone(),
            units       : self.units.clone()
        }
    }
}

impl Display for CNF {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let formatted = format!("Nvar: {:?} Nclause: {:?}\nClauses: {:?}\nOccurrrences: {:?}",
                self.nvar, self.nclause,
                self.clauses, self.occurrences);
        write!(f, "{}", formatted)
    }
}

// End CNF

// Begin Assignemnts

pub type Assignment = Vec<bool>;

pub struct PartialAssignment {
    pub assignment : Vec<Option<bool>>,
    pub unassigned : HashSet<i32>,
}

impl PartialAssignment {
    pub fn new(n : usize) -> PartialAssignment {
        PartialAssignment {
            assignment : vec!(None; n),
            unassigned : (0..n as i32).collect(),
        }
    }

    pub fn assign(&mut self, v : usize, assn : bool) {
        // TODO: Error check
        self.assignment[v] = Some(assn);
    }

    pub fn assign_literal(&mut self, lit : i32){
        let polarity : bool = lit & 1 == 0;
        let v : usize = (lit >> 2) as usize;
        self.assign(v,polarity);
    }

    pub fn unassign(&mut self, v : usize) {
        self.assignment[v] = None;
    }
}

// TODO: Implement Display
impl Display for PartialAssignment {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let formatted = format!("Assignemnts: {:?}\nUnassigned: {:?}",
                self.assignment, self.unassigned);
        write!(f, "{}", formatted)
    }
}

// End Assignments

// Begin Parsing

// TODO: rename to from_dimacs or somehow isolate parsing
fn parse_dimacs(reader: &mut BufReader<File>) -> Result<CNF, &'static str> {
    let mut line_iterator = reader.lines();

    let mut nvar: i32 = -1;
    let mut nclause: i32 = -1;
    // DIMACS file must have a problem statement before other lines.
    // This first loop searches for the problem statement.
    for line in &mut line_iterator {
        let line = line.expect("could not read file");  // Unwrap result
        let words: Vec<&str> = line.split_whitespace().collect();
        if words.len() == 0 { continue; } // Ignore empty lines
        match words[0] {
            "c" => { }
            "p" => { // Problem statement
                // Must have format "p cnf nvar nclause"
                if words.len() != 4 || words[1] != "cnf" {
                    return Err("invalid problem statement");
                }
                nvar = words[2].parse()
                    .expect(&format!("invalid number of variables {}", words[2]));
                nclause = words[3].parse()
                    .expect(&format!("invalid number of clauses {}", words[3]));
                break;
            }
            // TODO: Add words[0] to this error message
            _ => { return Err("unknown statement beginning"); }
        }
    }
    // Then nvar, nclause were never initialized
    if nvar == -1 || nclause == -1 {
       return Err("no problem statement found");
    }
    // TODO: Different errors for different descriptions (hence why I've split up this if
    // statement)
    if nvar == 0 || nclause == 0 {
        return Err("invalid number of literals in problem")
    }

    // Initialize CNF and parse the rest of the file
    let mut cnf = CNF::new(nvar, nclause);
    let mut clauses_read: i32 = 0;
    for line in &mut line_iterator {
        let line = line.unwrap();
        let words: Vec<&str> = line.split_whitespace().collect();
        if words.len() == 0 { continue; }
        match words[0] {
            "c" => { }
            "p" => { return Err("duplicate problem statement"); }
            _   => {
                clauses_read = clauses_read + 1;
                if clauses_read > nclause { return Err("too many clauses in file"); }
                let tokens: Vec<i32> = words.iter()
                    .filter_map(|s| {
                        let n = s.parse::<i32>().unwrap();
                        // FIXME: This ignores zeros not just as line enders but in the formulas
                        // themselves. Split on zeros at the end here.
                        if n == 0 { return None; }
                        // FIXME: This should return an error instead of
                        // panicking, but I can't return an error
                        // in a closure
                        if n > nvar { panic!("variable out of range: {}", n); }
                        Some(if n < 0 { (-n) << 1 | 1 } else { n << 1 })
                    })
                    .collect();
                cnf.add_clause(tokens);
            }
        }
    }
    // Double check that the number of clauses read is equal
    if clauses_read != nclause { return Err("too few clauses in file"); }
    Ok(cnf)
}

pub fn parse_dimacs_file(f: File) -> Result<CNF, &'static str> {
    // Read the file
    let mut reader = BufReader::new(f);

    // TODO: This is definitely not the correct way to handle errors.
    // Should parse_dimacs have options for returning an error AND panicking?
    let line = parse_dimacs(&mut reader);
    line
}

#[cfg(test)]
mod tests {
    extern crate tempfile;
    use std::fs::File;
    use std::io::prelude::*;
    use std::io::SeekFrom;

    use super::parse_dimacs_file;

    macro_rules! create_tempfile {
        ($x: expr) => {{
            let mut tmpfile: File = tempfile::tempfile().unwrap();
            let _ = write!(tmpfile, $x);
            tmpfile.seek(SeekFrom::Start(0)).unwrap();

            tmpfile
        }};
    }

    #[test]
    #[should_panic(expected = "out of range")]
    fn variable_out_of_range() {
        let tmpfile = create_tempfile!("
            p cnf 2 3
            1 2 0
            4 1 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "invalid number")]
    fn invalid_nvar() {
        let tmpfile = create_tempfile!("
            p cnf gd 3
            1 2 0
            4 1 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "invalid number")]
    fn invalid_nclause() {
        let tmpfile = create_tempfile!("
            p cnf 2 gdd
            1 2 0
            4 1 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "too many")]
    fn too_many_clauses() {
        let tmpfile = create_tempfile!("
            p cnf 5 5
            1 2 0
            2 3 0
            3 4 0
            4 5 0
            1 3 0
            2 4 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "too few")]
    fn too_little_clauses() {
        let tmpfile = create_tempfile!("
            p cnf 5 5
            1 2 0
            2 3 0
            3 4 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    fn should_work() {
        let tmpfile = create_tempfile!("
            p cnf 3 3
            1 2 0
            2 3 0
            1 -3 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    fn should_ignore_comments() {
        let tmpfile = create_tempfile!("
            c comment
            p cnf 3 3
            c comment
            1 2 0
            2 3 0
            c comment
            1 -3 0
            c comment
            c comment
            c comment
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "duplicate problem")]
    fn duplicate_problem_statement() {
        let tmpfile = create_tempfile!("
            p cnf 3 3
            1 2 0
            p cnf 3 3
            2 3 0
            1 -3 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "duplicate problem")]
    fn duplicate_problem_statement_2() {
        let tmpfile = create_tempfile!("
            p cnf 3 3
            p cnf 3 3
            1 2 0
            2 3 0
            1 -3 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    fn adds_unit_clauses() {
        let tmpfile = create_tempfile!("
            p cnf 3 4
            1 0
            2 0
            3 0
            -1 -3 0
        ");
        let cnf = parse_dimacs_file(tmpfile).unwrap();
        assert_eq!(cnf.units.len(), 3);
    }

    // TODO: Make this doc test (with unit propagate); create_tempfile may need to be an importable
    // macro up there
    #[test]
    fn propagate_works() {
        let tmpfile = create_tempfile!("
            p cnf 2 2
            1 0
            1 2 0
        ");
        let mut cnf = parse_dimacs_file(tmpfile).unwrap();
        println!("{:?}", cnf);
        cnf.propagate(2);
        println!("{:?}", cnf);
    }
}
<commit_msg>Have unit_propagate call propagate, more tests<commit_after>extern crate tempfile;

use std::fmt::{ Display, Formatter, Error };
use std::iter::Iterator;
use std::collections::HashMap;
use std::collections::HashSet;
use std::vec::Vec;
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;

use std::clone::Clone;

/**
 * test can be deleted.
 * clauses will house all clauses, key is int so that we can use occurrences
 * ID for simplifications later
 * occurrences tracks which clauses literals are used in
 */
#[derive(Debug)]
pub struct CNF {
    pub nvar        : i32,
    pub nclause     : i32,
    pub clauses     : HashMap<i32, Vec<i32>>,
    pub occurrences : HashMap<i32, Vec<i32>>,
    pub units       : HashSet<i32>
}

impl CNF {
    pub fn new(nvar: i32, nclause: i32) -> CNF {
        CNF {
            nvar        : nvar,
            nclause     : nclause,
            clauses     : HashMap::new(),
            occurrences : HashMap::new(),
            units       : HashSet::new(),
        }
    }

    /// Add a clause, return the ID of the inserted clause
    /// Right now, this isn't public; api is odd as we have an odd representation of literals.
    /// TODO: Mask this with public function?
    fn add_clause(&mut self, clause: Vec<i32>) -> i32 {
        assert!(clause.len() > 0);
        let id: i32 = self.clauses.len() as i32;
        if clause.len() == 1 { self.units.insert(id); }
        for var in &clause {
            let occ = self.occurrences.entry(*var).or_insert(Vec::new());
            occ.push(id);
        }
        self.clauses.insert(id, clause);
        id
    }

    /// Unit propagation: propagate the literal associated with the clause id `clause`, and remove
    /// it from `self.units`.
    pub fn unit_propagate(&mut self, unit: i32) {
        // Remove clauses with lit and remove lit from occurrences.
        let lit = self.clauses.get(&unit).expect("unit clause not found")[0];
        self.propagate(lit);
        // This needs to be true, i.e. unit clause id needs to be in the unit clauses
        assert!(self.units.remove(&unit));
    }

    /// Remove all clauses containing literal `lit` from the CNF, and remove the negation of `lit`
    /// from the remaining clauses.
    pub fn propagate(&mut self, lit: i32) {
        // Remove clauses with lit and remove lit from occurrences.
        for occ in &self.occurrences.remove(&lit).unwrap() {
            self.clauses.remove(occ);
        }
    }
}

impl Clone for CNF {
    fn clone(&self) -> CNF {
        CNF {
            nvar        : self.nvar,
            nclause     : self.nclause,
            clauses     : self.clauses.clone(),
            occurrences : self.occurrences.clone(),
            units       : self.units.clone()
        }
    }
}

impl Display for CNF {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let formatted = format!("Nvar: {:?} Nclause: {:?}\nClauses: {:?}\nOccurrrences: {:?}",
                self.nvar, self.nclause,
                self.clauses, self.occurrences);
        write!(f, "{}", formatted)
    }
}

// End CNF

// Begin Assignemnts

pub type Assignment = Vec<bool>;

pub struct PartialAssignment {
    pub assignment : Vec<Option<bool>>,
    pub unassigned : HashSet<i32>,
}

impl PartialAssignment {
    pub fn new(n : usize) -> PartialAssignment {
        PartialAssignment {
            assignment : vec!(None; n),
            unassigned : (0..n as i32).collect(),
        }
    }

    pub fn assign(&mut self, v : usize, assn : bool) {
        // TODO: Error check
        self.assignment[v] = Some(assn);
    }

    pub fn assign_literal(&mut self, lit : i32){
        let polarity : bool = lit & 1 == 0;
        let v : usize = (lit >> 2) as usize;
        self.assign(v,polarity);
    }

    pub fn unassign(&mut self, v : usize) {
        self.assignment[v] = None;
    }
}

// TODO: Implement Display
impl Display for PartialAssignment {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let formatted = format!("Assignemnts: {:?}\nUnassigned: {:?}",
                self.assignment, self.unassigned);
        write!(f, "{}", formatted)
    }
}

// End Assignments

// Begin Parsing

// TODO: rename to from_dimacs or somehow isolate parsing
fn parse_dimacs(reader: &mut BufReader<File>) -> Result<CNF, &'static str> {
    let mut line_iterator = reader.lines();

    let mut nvar: i32 = -1;
    let mut nclause: i32 = -1;
    // DIMACS file must have a problem statement before other lines.
    // This first loop searches for the problem statement.
    for line in &mut line_iterator {
        let line = line.expect("could not read file");  // Unwrap result
        let words: Vec<&str> = line.split_whitespace().collect();
        if words.len() == 0 { continue; } // Ignore empty lines
        match words[0] {
            "c" => { }
            "p" => { // Problem statement
                // Must have format "p cnf nvar nclause"
                if words.len() != 4 || words[1] != "cnf" {
                    return Err("invalid problem statement");
                }
                nvar = words[2].parse()
                    .expect(&format!("invalid number of variables {}", words[2]));
                nclause = words[3].parse()
                    .expect(&format!("invalid number of clauses {}", words[3]));
                break;
            }
            // TODO: Add words[0] to this error message
            _ => { return Err("unknown statement beginning"); }
        }
    }
    // Then nvar, nclause were never initialized
    if nvar == -1 || nclause == -1 {
       return Err("no problem statement found");
    }
    // TODO: Different errors for different descriptions (hence why I've split up this if
    // statement)
    if nvar == 0 || nclause == 0 {
        return Err("invalid number of literals in problem")
    }

    // Initialize CNF and parse the rest of the file
    let mut cnf = CNF::new(nvar, nclause);
    let mut clauses_read: i32 = 0;
    for line in &mut line_iterator {
        let line = line.unwrap();
        let words: Vec<&str> = line.split_whitespace().collect();
        if words.len() == 0 { continue; }
        match words[0] {
            "c" => { }
            "p" => { return Err("duplicate problem statement"); }
            _   => {
                clauses_read = clauses_read + 1;
                if clauses_read > nclause { return Err("too many clauses in file"); }
                let tokens: Vec<i32> = words.iter()
                    .filter_map(|s| {
                        let n = s.parse::<i32>().unwrap();
                        // FIXME: This ignores zeros not just as line enders but in the formulas
                        // themselves. Split on zeros at the end here.
                        if n == 0 { return None; }
                        // FIXME: This should return an error instead of
                        // panicking, but I can't return an error
                        // in a closure
                        if n > nvar { panic!("variable out of range: {}", n); }
                        Some(if n < 0 { (-n) << 1 | 1 } else { n << 1 })
                    })
                    .collect();
                cnf.add_clause(tokens);
            }
        }
    }
    // Double check that the number of clauses read is equal
    if clauses_read != nclause { return Err("too few clauses in file"); }
    Ok(cnf)
}

pub fn parse_dimacs_file(f: File) -> Result<CNF, &'static str> {
    // Read the file
    let mut reader = BufReader::new(f);

    // TODO: This is definitely not the correct way to handle errors.
    // Should parse_dimacs have options for returning an error AND panicking?
    let line = parse_dimacs(&mut reader);
    line
}

#[cfg(test)]
mod tests {
    extern crate tempfile;
    use std::fs::File;
    use std::io::prelude::*;
    use std::io::SeekFrom;

    use super::parse_dimacs_file;

    macro_rules! create_tempfile {
        ($x: expr) => {{
            let mut tmpfile: File = tempfile::tempfile().unwrap();
            let _ = write!(tmpfile, $x);
            tmpfile.seek(SeekFrom::Start(0)).unwrap();

            tmpfile
        }};
    }

    #[test]
    #[should_panic(expected = "out of range")]
    fn variable_out_of_range() {
        let tmpfile = create_tempfile!("
            p cnf 2 3
            1 2 0
            4 1 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "invalid number")]
    fn invalid_nvar() {
        let tmpfile = create_tempfile!("
            p cnf gd 3
            1 2 0
            4 1 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "invalid number")]
    fn invalid_nclause() {
        let tmpfile = create_tempfile!("
            p cnf 2 gdd
            1 2 0
            4 1 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "too many")]
    fn too_many_clauses() {
        let tmpfile = create_tempfile!("
            p cnf 5 5
            1 2 0
            2 3 0
            3 4 0
            4 5 0
            1 3 0
            2 4 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "too few")]
    fn too_little_clauses() {
        let tmpfile = create_tempfile!("
            p cnf 5 5
            1 2 0
            2 3 0
            3 4 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    fn should_work() {
        let tmpfile = create_tempfile!("
            p cnf 3 3
            1 2 0
            2 3 0
            1 -3 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    fn should_ignore_comments() {
        let tmpfile = create_tempfile!("
            c comment
            p cnf 3 3
            c comment
            1 2 0
            2 3 0
            c comment
            1 -3 0
            c comment
            c comment
            c comment
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "duplicate problem")]
    fn duplicate_problem_statement() {
        let tmpfile = create_tempfile!("
            p cnf 3 3
            1 2 0
            p cnf 3 3
            2 3 0
            1 -3 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    #[should_panic(expected = "duplicate problem")]
    fn duplicate_problem_statement_2() {
        let tmpfile = create_tempfile!("
            p cnf 3 3
            p cnf 3 3
            1 2 0
            2 3 0
            1 -3 0
        ");
        let _ = parse_dimacs_file(tmpfile).unwrap();
    }

    #[test]
    fn adds_unit_clauses() {
        let tmpfile = create_tempfile!("
            p cnf 3 4
            1 0
            2 0
            3 0
            -1 -3 0
        ");
        let cnf = parse_dimacs_file(tmpfile).unwrap();
        assert_eq!(cnf.units.len(), 3);
    }

    // TODO: Make this doc test (with unit propagate); create_tempfile may need to be an importable
    // macro up there
    #[test]
    fn unit_propagate_works() {
        let tmpfile = create_tempfile!("
            p cnf 2 2
            1 0
            1 2 0
        ");
        let mut cnf = parse_dimacs_file(tmpfile).unwrap();
        cnf.unit_propagate(0);
        assert!(cnf.units.is_empty());
    }

    #[test]
    fn unit_propagate_works_2() {
        let tmpfile = create_tempfile!("
            p cnf 4 4
            1 0
            1 2 0
            2 3 0
            4 0
        ");
        let mut cnf = parse_dimacs_file(tmpfile).unwrap();
        cnf.unit_propagate(0);
        // Only one unit clause left
        assert_eq!(cnf.units.len(), 1);
        cnf.unit_propagate(3);
        // No more unit clauses
        assert!(cnf.units.is_empty());
    }

    #[test]
    #[should_panic(expected = "unit clause not found")]
    fn unit_clause_not_found() {
        let tmpfile = create_tempfile!("
            p cnf 2 2
            1 0
            1 2 0
        ");
        let mut cnf = parse_dimacs_file(tmpfile).unwrap();
        println!("{:?}", cnf);
        cnf.unit_propagate(2);
        println!("{:?}", cnf);
    }
}
<|endoftext|>


<commit_before>use std::time::{Duration, SystemTime, Instant};
use std::convert::TryFrom;

use crate::stacked_borrows::Tag;
use crate::*;
use helpers::{immty_from_int_checked, immty_from_uint_checked};

use rustc_middle::ty::layout::LayoutOf;

/// Returns the time elapsed between the provided time and the unix epoch as a `Duration`.
pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> {
    time.duration_since(SystemTime::UNIX_EPOCH)
        .map_err(|_| err_unsup_format!("times before the Unix epoch are not supported").into())
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn clock_gettime(
        &mut self,
        clk_id_op: OpTy<'tcx, Tag>,
        tp_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.assert_target_os("linux", "clock_gettime");
        this.check_no_isolation("clock_gettime")?;

        let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
        let tp = this.deref_operand(tp_op)?;

        let duration = if clk_id == this.eval_libc_i32("CLOCK_REALTIME")? {
            system_time_to_duration(&SystemTime::now())?
        } else if clk_id == this.eval_libc_i32("CLOCK_MONOTONIC")? {
            // Absolute time does not matter, only relative time does, so we can just
            // use our own time anchor here.
            Instant::now().duration_since(this.machine.time_anchor)
        } else {
            let einval = this.eval_libc("EINVAL")?;
            this.set_last_error(einval)?;
            return Ok(-1);
        };

        let tv_sec = duration.as_secs();
        let tv_nsec = duration.subsec_nanos();

        let imms = [
            immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
            immty_from_int_checked(tv_nsec, this.libc_ty_layout("c_long")?)?,
        ];

        this.write_packed_immediates(tp, &imms)?;

        Ok(0)
    }

    fn gettimeofday(
        &mut self,
        tv_op: OpTy<'tcx, Tag>,
        tz_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.assert_target_os("macos", "gettimeofday");
        this.check_no_isolation("gettimeofday")?;

        // Using tz is obsolete and should always be null
        let tz = this.read_scalar(tz_op)?.not_undef()?;
        if !this.is_null(tz)? {
            let einval = this.eval_libc("EINVAL")?;
            this.set_last_error(einval)?;
            return Ok(-1);
        }

        let tv = this.deref_operand(tv_op)?;

        let duration = system_time_to_duration(&SystemTime::now())?;
        let tv_sec = duration.as_secs();
        let tv_usec = duration.subsec_micros();

        let imms = [
            immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
            immty_from_int_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?,
        ];

        this.write_packed_immediates(tv, &imms)?;

        Ok(0)
    }

    #[allow(non_snake_case)]
    fn GetSystemTimeAsFileTime(&mut self, LPFILETIME_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx> {
        let this = self.eval_context_mut();

        this.assert_target_os("windows", "GetSystemTimeAsFileTime");
        this.check_no_isolation("GetSystemTimeAsFileTime")?;

        let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC")?;
        let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC")?;
        let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH")?;
        let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC;
        let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC;

        let duration = system_time_to_duration(&SystemTime::now())?
            .checked_add(Duration::from_secs(SECONDS_TO_UNIX_EPOCH))
            .unwrap();
        let duration_ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL))
            .map_err(|_| err_unsup_format!("programs running longer than 2^64 ticks are not supported"))?;

        let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap();
        let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap();
        let DWORD_tylayout = this.layout_of(this.tcx.types.u32)?;
        let imms = [
            immty_from_uint_checked(dwLowDateTime, DWORD_tylayout)?,
            immty_from_uint_checked(dwHighDateTime, DWORD_tylayout)?,
        ];
        this.write_packed_immediates(this.deref_operand(LPFILETIME_op)?, &imms)?;
        Ok(())
    }

    fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> {
        let this = self.eval_context_ref();

        this.assert_target_os("macos", "mach_absolute_time");
        this.check_no_isolation("mach_absolute_time")?;

        // This returns a u64, with time units determined dynamically by `mach_timebase_info`.
        // We return plain nanoseconds.
        let duration = Instant::now().duration_since(this.machine.time_anchor);
        u64::try_from(duration.as_nanos())
            .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported").into())
    }
}
<commit_msg>correct factual mistake in Windows message, and use "+" sugar<commit_after>use std::time::{Duration, SystemTime, Instant};
use std::convert::TryFrom;

use crate::stacked_borrows::Tag;
use crate::*;
use helpers::{immty_from_int_checked, immty_from_uint_checked};

use rustc_middle::ty::layout::LayoutOf;

/// Returns the time elapsed between the provided time and the unix epoch as a `Duration`.
pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> {
    time.duration_since(SystemTime::UNIX_EPOCH)
        .map_err(|_| err_unsup_format!("times before the Unix epoch are not supported").into())
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn clock_gettime(
        &mut self,
        clk_id_op: OpTy<'tcx, Tag>,
        tp_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.assert_target_os("linux", "clock_gettime");
        this.check_no_isolation("clock_gettime")?;

        let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
        let tp = this.deref_operand(tp_op)?;

        let duration = if clk_id == this.eval_libc_i32("CLOCK_REALTIME")? {
            system_time_to_duration(&SystemTime::now())?
        } else if clk_id == this.eval_libc_i32("CLOCK_MONOTONIC")? {
            // Absolute time does not matter, only relative time does, so we can just
            // use our own time anchor here.
            Instant::now().duration_since(this.machine.time_anchor)
        } else {
            let einval = this.eval_libc("EINVAL")?;
            this.set_last_error(einval)?;
            return Ok(-1);
        };

        let tv_sec = duration.as_secs();
        let tv_nsec = duration.subsec_nanos();

        let imms = [
            immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
            immty_from_int_checked(tv_nsec, this.libc_ty_layout("c_long")?)?,
        ];

        this.write_packed_immediates(tp, &imms)?;

        Ok(0)
    }

    fn gettimeofday(
        &mut self,
        tv_op: OpTy<'tcx, Tag>,
        tz_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.assert_target_os("macos", "gettimeofday");
        this.check_no_isolation("gettimeofday")?;

        // Using tz is obsolete and should always be null
        let tz = this.read_scalar(tz_op)?.not_undef()?;
        if !this.is_null(tz)? {
            let einval = this.eval_libc("EINVAL")?;
            this.set_last_error(einval)?;
            return Ok(-1);
        }

        let tv = this.deref_operand(tv_op)?;

        let duration = system_time_to_duration(&SystemTime::now())?;
        let tv_sec = duration.as_secs();
        let tv_usec = duration.subsec_micros();

        let imms = [
            immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?,
            immty_from_int_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?,
        ];

        this.write_packed_immediates(tv, &imms)?;

        Ok(0)
    }

    #[allow(non_snake_case)]
    fn GetSystemTimeAsFileTime(&mut self, LPFILETIME_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx> {
        let this = self.eval_context_mut();

        this.assert_target_os("windows", "GetSystemTimeAsFileTime");
        this.check_no_isolation("GetSystemTimeAsFileTime")?;

        let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC")?;
        let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC")?;
        let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH")?;
        let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC;
        let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC;

        let duration = system_time_to_duration(&SystemTime::now())? + Duration::from_secs(SECONDS_TO_UNIX_EPOCH);
        let duration_ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL))
            .map_err(|_| err_unsup_format!("programs running more than 2^64 Windows ticks after the Windows epoch are not supported"))?;

        let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap();
        let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap();
        let DWORD_tylayout = this.layout_of(this.tcx.types.u32)?;
        let imms = [
            immty_from_uint_checked(dwLowDateTime, DWORD_tylayout)?,
            immty_from_uint_checked(dwHighDateTime, DWORD_tylayout)?,
        ];
        this.write_packed_immediates(this.deref_operand(LPFILETIME_op)?, &imms)?;
        Ok(())
    }

    fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> {
        let this = self.eval_context_ref();

        this.assert_target_os("macos", "mach_absolute_time");
        this.check_no_isolation("mach_absolute_time")?;

        // This returns a u64, with time units determined dynamically by `mach_timebase_info`.
        // We return plain nanoseconds.
        let duration = Instant::now().duration_since(this.machine.time_anchor);
        u64::try_from(duration.as_nanos())
            .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported").into())
    }
}
<|endoftext|>


<commit_before>import front::ast;
import front::codemap;
import util::common::span;
import util::common::ty_mach;
import std::uint;
import std::term;
import std::io;
import std::map;

tag os {
    os_win32;
    os_macos;
    os_linux;
}

tag arch {
    arch_x86;
    arch_x64;
    arch_arm;
}

type config = rec(os os,
                  arch arch,
                  ty_mach int_type,
                  ty_mach uint_type,
                  ty_mach float_type);

type options = rec(bool shared,
                   uint optimize,
                   bool debuginfo,
                   bool verify,
                   bool run_typestate,
                   bool save_temps,
                   bool stats,
                   bool time_passes,
                   bool time_llvm_passes,
                   back::link::output_type output_type,
                   vec[str] library_search_paths,
                   str sysroot);

type crate_metadata = rec(str name,
                          vec[u8] data);

fn emit_diagnostic(span sp, str msg, str kind, u8 color,
                   codemap::codemap cm) {
    auto lo = codemap::lookup_pos(cm, sp.lo);
    auto hi = codemap::lookup_pos(cm, sp.hi);
    io::stdout().write_str(#fmt("%s:%u:%u:%u:%u: ", lo.filename, lo.line,
                               lo.col, hi.line, hi.col));

    if (term::color_supported()) {
        term::fg(io::stdout().get_buf_writer(), color);
    }

    io::stdout().write_str(#fmt("%s:", kind));

    if (term::color_supported()) {
        term::reset(io::stdout().get_buf_writer());
    }

    io::stdout().write_str(#fmt(" %s\n", msg));
}

state obj session(ast::crate_num cnum,
                  @config targ_cfg, @options opts,
                  map::hashmap[int, crate_metadata] crates,
                  mutable vec[@ast::meta_item] metadata,
                  codemap::codemap cm) {

    fn get_targ_cfg() -> @config {
        ret targ_cfg;
    }

    fn get_opts() -> @options {
        ret opts;
    }

    fn get_targ_crate_num() -> ast::crate_num {
        ret cnum;
    }

    fn span_err(span sp, str msg) -> ! {
        // FIXME: Use constants, but rustboot doesn't know how to export them.
        emit_diagnostic(sp, msg, "error", 9u8, cm);
        fail;
    }

    fn err(str msg) -> ! {
        log_err #fmt("error: %s", msg);
        fail;
    }

    fn add_metadata(vec[@ast::meta_item] data) {
        metadata = metadata + data;
    }
    fn get_metadata() -> vec[@ast::meta_item] {
        ret metadata;
    }

    fn span_warn(span sp, str msg) {
        // FIXME: Use constants, but rustboot doesn't know how to export them.
        emit_diagnostic(sp, msg, "warning", 11u8, cm);
    }

    fn span_note(span sp, str msg) {
        // FIXME: Use constants, but rustboot doesn't know how to export them.
        emit_diagnostic(sp, msg, "note", 10u8, cm);
    }

    fn bug(str msg) -> ! {
        log_err #fmt("error: internal compiler error %s", msg);
        fail;
    }

    fn span_unimpl(span sp, str msg) -> ! {
        // FIXME: Use constants, but rustboot doesn't know how to export them.
        emit_diagnostic(sp, "internal compiler error: unimplemented " + msg,
                        "error", 9u8, cm);
        fail;
    }

    fn unimpl(str msg) -> ! {
        log_err #fmt("error: unimplemented %s", msg);
        fail;
    }

    fn get_external_crate(int num) -> crate_metadata {
        ret crates.get(num);
    }

    fn set_external_crate(int num, &crate_metadata metadata) {
        crates.insert(num, metadata);
    }

    fn has_external_crate(int num) -> bool {
        ret crates.contains_key(num);
    }

    fn get_codemap() -> codemap::codemap {
        ret cm;
    }

    fn lookup_pos(uint pos) -> codemap::loc {
        ret codemap::lookup_pos(cm, pos);
    }
}

// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Add a span_str function in session<commit_after>import front::ast;
import front::codemap;
import util::common::span;
import util::common::ty_mach;
import std::uint;
import std::term;
import std::io;
import std::map;

tag os {
    os_win32;
    os_macos;
    os_linux;
}

tag arch {
    arch_x86;
    arch_x64;
    arch_arm;
}

type config = rec(os os,
                  arch arch,
                  ty_mach int_type,
                  ty_mach uint_type,
                  ty_mach float_type);

type options = rec(bool shared,
                   uint optimize,
                   bool debuginfo,
                   bool verify,
                   bool run_typestate,
                   bool save_temps,
                   bool stats,
                   bool time_passes,
                   bool time_llvm_passes,
                   back::link::output_type output_type,
                   vec[str] library_search_paths,
                   str sysroot);

type crate_metadata = rec(str name,
                          vec[u8] data);

fn span_to_str(span sp, codemap::codemap cm) -> str {
    auto lo = codemap::lookup_pos(cm, sp.lo);
    auto hi = codemap::lookup_pos(cm, sp.hi);
    ret (#fmt("%s:%u:%u:%u:%u", lo.filename, lo.line,
              lo.col, hi.line, hi.col));
}

fn emit_diagnostic(span sp, str msg, str kind, u8 color,
                   codemap::codemap cm) {
    io::stdout().write_str(span_to_str(sp, cm) + ": ");

    if (term::color_supported()) {
        term::fg(io::stdout().get_buf_writer(), color);
    }

    io::stdout().write_str(#fmt("%s:", kind));

    if (term::color_supported()) {
        term::reset(io::stdout().get_buf_writer());
    }

    io::stdout().write_str(#fmt(" %s\n", msg));
}

state obj session(ast::crate_num cnum,
                  @config targ_cfg, @options opts,
                  map::hashmap[int, crate_metadata] crates,
                  mutable vec[@ast::meta_item] metadata,
                  codemap::codemap cm) {

    fn get_targ_cfg() -> @config {
        ret targ_cfg;
    }

    fn get_opts() -> @options {
        ret opts;
    }

    fn get_targ_crate_num() -> ast::crate_num {
        ret cnum;
    }

    fn span_err(span sp, str msg) -> ! {
        // FIXME: Use constants, but rustboot doesn't know how to export them.
        emit_diagnostic(sp, msg, "error", 9u8, cm);
        fail;
    }

    fn err(str msg) -> ! {
        log_err #fmt("error: %s", msg);
        fail;
    }

    fn add_metadata(vec[@ast::meta_item] data) {
        metadata = metadata + data;
    }
    fn get_metadata() -> vec[@ast::meta_item] {
        ret metadata;
    }

    fn span_warn(span sp, str msg) {
        // FIXME: Use constants, but rustboot doesn't know how to export them.
        emit_diagnostic(sp, msg, "warning", 11u8, cm);
    }

    fn span_note(span sp, str msg) {
        // FIXME: Use constants, but rustboot doesn't know how to export them.
        emit_diagnostic(sp, msg, "note", 10u8, cm);
    }

    fn bug(str msg) -> ! {
        log_err #fmt("error: internal compiler error %s", msg);
        fail;
    }

    fn span_unimpl(span sp, str msg) -> ! {
        // FIXME: Use constants, but rustboot doesn't know how to export them.
        emit_diagnostic(sp, "internal compiler error: unimplemented " + msg,
                        "error", 9u8, cm);
        fail;
    }

    fn unimpl(str msg) -> ! {
        log_err #fmt("error: unimplemented %s", msg);
        fail;
    }

    fn get_external_crate(int num) -> crate_metadata {
        ret crates.get(num);
    }

    fn set_external_crate(int num, &crate_metadata metadata) {
        crates.insert(num, metadata);
    }

    fn has_external_crate(int num) -> bool {
        ret crates.contains_key(num);
    }

    fn get_codemap() -> codemap::codemap {
        ret cm;
    }

    fn lookup_pos(uint pos) -> codemap::loc {
        ret codemap::lookup_pos(cm, pos);
    }

    fn span_str(span sp) -> str {
        ret span_to_str(sp, self.get_codemap());
    }
}

// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>import std::{smallintmap, option};
import syntax::ast::*;
import syntax::{visit, codemap};
import visit::vt;

tag ast_node {
    node_item(@item);
    node_obj_ctor(@item);
    node_native_item(@native_item);
    node_expr(@expr);
}

type map = std::map::hashmap<node_id, ast_node>;

fn map_crate(c: crate) -> map {
    // FIXME: This is using an adapter to convert the smallintmap
    // interface to the hashmap interface. It would be better to just
    // convert everything to use the smallintmap.
    let map = new_smallintmap_int_adapter::<ast_node>();

    let v_map =
        @{visit_item: bind map_item(map, _, _, _),
          visit_native_item: bind map_native_item(map, _, _, _),
          visit_expr: bind map_expr(map, _, _, _)
             with *visit::default_visitor::<()>()};
    visit::visit_crate(c, (), visit::mk_vt(v_map));
    ret map;
}

fn map_item(map: map, i: @item, e: (), v: vt<()>) {
    map.insert(i.id, node_item(i));
    alt i.node {
      item_obj(_, _, ctor_id) { map.insert(ctor_id, node_obj_ctor(i)); }
      _ { }
    }
    visit::visit_item(i, e, v);
}

fn map_native_item(map: map, i: @native_item, e: (), v: vt<()>) {
    map.insert(i.id, node_native_item(i));
    visit::visit_native_item(i, e, v);
}

fn map_expr(map: map, ex: @expr, e: (), v: vt<()>) {
    map.insert(ex.id, node_expr(ex));
    visit::visit_expr(ex, e, v);
}

fn new_smallintmap_int_adapter<@V>() -> std::map::hashmap<int, V> {
    let key_idx = fn (key: int) -> uint { key as uint };
    let idx_key = fn (idx: uint) -> int { idx as int };
    ret new_smallintmap_adapter(key_idx, idx_key);
}

// This creates an object with the hashmap interface backed
// by the smallintmap type, because I don't want to go through
// the entire codebase adapting all the callsites to the different
// interface.
// FIXME: hashmap and smallintmap should support the same interface.
fn new_smallintmap_adapter<@K,
                           @V>(key_idx: fn(K) -> uint, idx_key: fn(uint) -> K)
   -> std::map::hashmap<K, V> {

    obj adapter<@K,
                @V>(map: smallintmap::smallintmap<V>,
                    key_idx: fn(K) -> uint,
                    idx_key: fn(uint) -> K) {

        fn size() -> uint { fail }

        fn insert(key: K, value: V) -> bool {
            let exists = smallintmap::contains_key(map, key_idx(key));
            smallintmap::insert(map, key_idx(key), value);
            ret !exists;
        }

        fn contains_key(key: K) -> bool {
            ret smallintmap::contains_key(map, key_idx(key));
        }

        fn get(key: K) -> V { ret smallintmap::get(map, key_idx(key)); }

        fn find(key: K) -> option::t<V> {
            ret smallintmap::find(map, key_idx(key));
        }

        fn remove(_key: K) -> option::t<V> { fail }

        fn rehash() { fail }

        iter items() -> @{key: K, val: V} {
            let idx = 0u;
            for item: option::t<V> in map.v {
                alt item {
                  option::some(elt) {
                    let value = elt;
                    let key = idx_key(idx);
                    put @{key: key, val: value};
                  }
                  option::none. { }
                }
                idx += 1u;
            }
        }
        iter keys() -> K {
            for each p: @{key: K, val: V} in self.items() { put p.key; }
        }
    }

    let map = smallintmap::mk::<V>();
    ret adapter(map, key_idx, idx_key);
}

fn node_span(node: ast_node) -> codemap::span {
    alt node {
      node_item(item) { item.span }
      node_obj_ctor(item) { item.span }
      node_native_item(nitem) { nitem.span }
      node_expr(expr) { expr.span }
    }
}

#[cfg(test)]
mod test {
    import syntax::ast_util;

    #[test]
    fn test_node_span_item() {
        let expected: codemap::span = ast_util::mk_sp(20u, 30u);
        let node =
            node_item(@{ident: "test",
                        attrs: [],
                        id: 0,
                        node: item_mod({view_items: [], items: []}),
                        span: expected});
        assert (node_span(node) == expected);
    }

    #[test]
    fn test_node_span_obj_ctor() {
        let expected: codemap::span = ast_util::mk_sp(20u, 30u);
        let node =
            node_obj_ctor(@{ident: "test",
                            attrs: [],
                            id: 0,
                            node: item_mod({view_items: [], items: []}),
                            span: expected});
        assert (node_span(node) == expected);
    }

    #[test]
    fn test_node_span_native_item() {
        let expected: codemap::span = ast_util::mk_sp(20u, 30u);
        let node =
            node_native_item(@{ident: "test",
                               attrs: [],
                               node: native_item_ty,
                               id: 0,
                               span: expected});
        assert (node_span(node) == expected);
    }

    #[test]
    fn test_node_span_expr() {
        let expected: codemap::span = ast_util::mk_sp(20u, 30u);
        let node = node_expr(@{id: 0, node: expr_break, span: expected});
        assert (node_span(node) == expected);
    }
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Make ast_map.rs index function args, switch it over to simple_visitor<commit_after>import std::{smallintmap, option};
import syntax::ast::*;
import syntax::{visit, codemap};
import visit::vt;

tag ast_node {
    node_item(@item);
    node_obj_ctor(@item);
    node_native_item(@native_item);
    node_expr(@expr);
    node_arg(arg);
}

type map = std::map::hashmap<node_id, ast_node>;

fn map_crate(c: crate) -> map {
    // FIXME: This is using an adapter to convert the smallintmap
    // interface to the hashmap interface. It would be better to just
    // convert everything to use the smallintmap.
    let map = new_smallintmap_int_adapter::<ast_node>();

    let v_map = visit::mk_simple_visitor
        (@{visit_item: bind map_item(map, _),
           visit_native_item: bind map_native_item(map, _),
           visit_expr: bind map_expr(map, _),
           visit_fn: bind map_fn(map, _, _, _, _, _)
               with *visit::default_simple_visitor()});
    visit::visit_crate(c, (), v_map);
    ret map;
}

fn map_fn(map: map, f: _fn, _tp: [ty_param], _sp: codemap::span,
          _name: fn_ident, _id: node_id) {
    for a in f.decl.inputs { map.insert(a.id, node_arg(a)); }
}

fn map_item(map: map, i: @item) {
    map.insert(i.id, node_item(i));
    alt i.node {
      item_obj(_, _, ctor_id) { map.insert(ctor_id, node_obj_ctor(i)); }
      _ { }
    }
}

fn map_native_item(map: map, i: @native_item) {
    map.insert(i.id, node_native_item(i));
}

fn map_expr(map: map, ex: @expr) {
    map.insert(ex.id, node_expr(ex));
}

fn new_smallintmap_int_adapter<@V>() -> std::map::hashmap<int, V> {
    let key_idx = fn (key: int) -> uint { key as uint };
    let idx_key = fn (idx: uint) -> int { idx as int };
    ret new_smallintmap_adapter(key_idx, idx_key);
}

// This creates an object with the hashmap interface backed
// by the smallintmap type, because I don't want to go through
// the entire codebase adapting all the callsites to the different
// interface.
// FIXME: hashmap and smallintmap should support the same interface.
fn new_smallintmap_adapter<@K,
                           @V>(key_idx: fn(K) -> uint, idx_key: fn(uint) -> K)
   -> std::map::hashmap<K, V> {

    obj adapter<@K,
                @V>(map: smallintmap::smallintmap<V>,
                    key_idx: fn(K) -> uint,
                    idx_key: fn(uint) -> K) {

        fn size() -> uint { fail }

        fn insert(key: K, value: V) -> bool {
            let exists = smallintmap::contains_key(map, key_idx(key));
            smallintmap::insert(map, key_idx(key), value);
            ret !exists;
        }

        fn contains_key(key: K) -> bool {
            ret smallintmap::contains_key(map, key_idx(key));
        }

        fn get(key: K) -> V { ret smallintmap::get(map, key_idx(key)); }

        fn find(key: K) -> option::t<V> {
            ret smallintmap::find(map, key_idx(key));
        }

        fn remove(_key: K) -> option::t<V> { fail }

        fn rehash() { fail }

        iter items() -> @{key: K, val: V} {
            let idx = 0u;
            for item: option::t<V> in map.v {
                alt item {
                  option::some(elt) {
                    let value = elt;
                    let key = idx_key(idx);
                    put @{key: key, val: value};
                  }
                  option::none. { }
                }
                idx += 1u;
            }
        }
        iter keys() -> K {
            for each p: @{key: K, val: V} in self.items() { put p.key; }
        }
    }

    let map = smallintmap::mk::<V>();
    ret adapter(map, key_idx, idx_key);
}

fn node_span(node: ast_node) -> codemap::span {
    alt node {
      node_item(item) { item.span }
      node_obj_ctor(item) { item.span }
      node_native_item(nitem) { nitem.span }
      node_expr(expr) { expr.span }
    }
}

#[cfg(test)]
mod test {
    import syntax::ast_util;

    #[test]
    fn test_node_span_item() {
        let expected: codemap::span = ast_util::mk_sp(20u, 30u);
        let node =
            node_item(@{ident: "test",
                        attrs: [],
                        id: 0,
                        node: item_mod({view_items: [], items: []}),
                        span: expected});
        assert (node_span(node) == expected);
    }

    #[test]
    fn test_node_span_obj_ctor() {
        let expected: codemap::span = ast_util::mk_sp(20u, 30u);
        let node =
            node_obj_ctor(@{ident: "test",
                            attrs: [],
                            id: 0,
                            node: item_mod({view_items: [], items: []}),
                            span: expected});
        assert (node_span(node) == expected);
    }

    #[test]
    fn test_node_span_native_item() {
        let expected: codemap::span = ast_util::mk_sp(20u, 30u);
        let node =
            node_native_item(@{ident: "test",
                               attrs: [],
                               node: native_item_ty,
                               id: 0,
                               span: expected});
        assert (node_span(node) == expected);
    }

    #[test]
    fn test_node_span_expr() {
        let expected: codemap::span = ast_util::mk_sp(20u, 30u);
        let node = node_expr(@{id: 0, node: expr_break, span: expected});
        assert (node_span(node) == expected);
    }
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>