<commit_before>//! The master module provides the Master struct which instructs Workers which
//! portions of the image they should render and collects their results to combine
//! into the final image.

use std::path::PathBuf;
use std::io::prelude::*;
use std::collections::HashMap;
use std::net::ToSocketAddrs;
use std::iter;

use bincode::rustc_serialize::decode;
use image;
use mio::tcp::{TcpStream, Shutdown};
use mio::*;

use film::Image;
use exec::Config;
use exec::distrib::{worker, Instructions};
use sampler::BlockQueue;

pub struct DistributedFrame {
    pub frame: usize,
    // The number of workers who have reported results for this
    // frame so far
    pub num_reporting: usize,
    pub render: Image,
    pub completed: bool,
}

#[derive(Clone, Debug)]
struct WorkerBuffer {
    pub buf: Vec<u8>,
    pub expected_size: usize,
    pub currently_read: usize,
}

impl WorkerBuffer {
    pub fn new() -> WorkerBuffer {
        WorkerBuffer { buf: Vec::new(), expected_size: 8, currently_read: 0 }
    }
}

pub struct Master {
    // Hostnames of the workers to send work too
    workers: Vec<String>,
    connections: Vec<TcpStream>,
    // Temporary buffers to store worker results in as they're
    // read in over TCP
    worker_buffers: Vec<WorkerBuffer>,
    config: Config,
    frames: HashMap<usize, DistributedFrame>,
    selected_frames: Option<(usize, usize)>,
    img_dim: (usize, usize),
    blocks_per_worker: usize,
    blocks_remainder: usize,
}

impl Master {
    /// Create a new master that will contact the worker nodes passed and
    /// send instructions on what parts of the scene to start rendering
    pub fn start_workers(workers: Vec<String>, config: Config, img_dim: (usize, usize),
                         frames: Option<(usize, usize)>) -> (Master, EventLoop<Master>) {
        // Figure out how many blocks we have for this image and assign them to our workers
        let queue = BlockQueue::new((img_dim.0 as u32, img_dim.1 as u32), (8, 8), (0, 0));
        let blocks_per_worker = queue.len() / workers.len();
        let blocks_remainder = queue.len() % workers.len();
        println!("Have {} workers, each worker does {} blocks w/ {} remainder",
                 workers.len(), blocks_per_worker, blocks_remainder);

        let mut event_loop = EventLoop::<Master>::new().unwrap();
        let mut connections = Vec::new();

        // Connect to each worker and send instructions on what to render
        // I guess this should also be queue'd up and the writes actually performed asynchronously?
        // Otherwise we need to loop on write_all while waiting for the connection to open
        for (i, host) in workers.iter().enumerate() {
            let addr = (&host[..], worker::PORT).to_socket_addrs().unwrap().next().unwrap();
            println!("Connecting too {:?}", addr);
            match TcpStream::connect(&addr) {
                Ok(stream) => {
                    println!("Connected and writing");
                    println!("Adding stream to event loop");
                    // Each worker is identified in the event loop by their index in the vec
                    match event_loop.register(&stream, Token(i)) {
                        Err(e) => println!("Error registering stream from {}: {}", host, e),
                        Ok(_) => {},
                    }
                    connections.push(stream);
                },
                Err(e) => println!("Failed to contact worker {}: {:?}", host, e),
            }
        }
        let worker_buffers: Vec<_> = iter::repeat(WorkerBuffer::new()).take(workers.len()).collect();
        let master = Master { workers: workers, connections: connections,
                              worker_buffers: worker_buffers, config: config,
                              frames: HashMap::new(), selected_frames: frames,
                              img_dim: img_dim,
                              blocks_per_worker: blocks_per_worker,
                              blocks_remainder: blocks_remainder };
        (master, event_loop)
    }
    /// Read a result frame from a worker and save it into the list of frames we're collecting from
    /// all workers. Will save out the final render if all workers have reported results for this
    /// frame.
    fn save_results(&mut self, frame: worker::Frame) {
        // Find the frame this worker is referring to and add its results
        let frame_num = frame.frame as usize;
        println!("Worker reporting frame {}", frame_num);
        if let Some(df) = self.frames.get_mut(&frame_num) {
            df.render.add_blocks(frame.block_size, &frame.blocks, &frame.pixels);
            df.num_reporting += 1;
            println!("We have parts of this frame already");
        }
        // TODO: Better way here? We get stuck because self.frames is counted as borrowed
        // from the if above, making this really awkward.
        if self.frames.get_mut(&frame_num).is_none() {
            // TODO: I need to seperate the render target from the actual image as the
            // filter here isn't used in this path and it doesn't make sense to have one
            let render = Image::new(self.img_dim);
            let mut df = DistributedFrame { frame: frame_num, num_reporting: 1, render: render, completed: false };
            df.render.add_blocks(frame.block_size, &frame.blocks, &frame.pixels);
            self.frames.insert(df.frame, df);
            println!("This is a new frame");
        }
        if let Some(df) = self.frames.get_mut(&frame_num) {
            if df.num_reporting == self.workers.len() {
                df.completed = true;
                println!("We have completed frame {}", frame_num);
                let out_file = match self.config.out_path.extension() {
                    Some(_) => self.config.out_path.clone(),
                    None => self.config.out_path.join(PathBuf::from(format!("frame{:05}.png", df.frame))),
                };
                println!("Frame {}: rendered to '{}'\n--------------------", frame_num, out_file.display());
                let img = df.render.get_srgb8();
                let dim = df.render.dimensions();
                match image::save_buffer(&out_file.as_path(), &img[..], dim.0 as u32, dim.1 as u32, image::RGB(8)) {
                    Ok(_) => {},
                    Err(e) => println!("Error saving image, {}", e),
                };
            }
        }
    }
    fn read_worker_buffer(&mut self, worker: usize) -> bool {
        let mut buf = &mut self.worker_buffers[worker];
        // If we haven't read the size of data being sent, read that now
        if buf.currently_read < 8 {
            // First 8 bytes are a u64 specifying the number of bytes being sent
            buf.buf.extend(iter::repeat(0u8).take(8));
            println!("Reading size header...");
            match self.connections[worker].read(&mut buf.buf[buf.currently_read..]) {
                Ok(n) => buf.currently_read += n,
                Err(e) => println!("Error reading results from worker {}: {}", self.workers[worker], e),
            }
            println!("Read {} bytes so far, must read {} in total", buf.currently_read, buf.expected_size);
            if buf.currently_read == buf.expected_size {
                println!("Got size header");
                // How many bytes we expect to get from the worker for a frame
                buf.expected_size = decode(&buf.buf[..]).unwrap();
                println!("Expecting {} bytes", buf.expected_size);
                // Extend the Vec so we've got enough room for the remaning bytes, minus the 8 for the
                // encoded size header
                buf.buf.extend(iter::repeat(0u8).take(buf.expected_size - 8));
            }
        }
        // If we've finished reading the size header we can now start reading the frame data
        if buf.currently_read >= 8 {
            println!("Reading from worker");
            match self.connections[worker].read(&mut buf.buf[buf.currently_read..]) {
                Ok(n) => buf.currently_read += n,
                Err(e) => println!("Error reading results from worker {}: {}", self.workers[worker], e),
            }
            println!("Read {} bytes so far, must read {} in total", buf.currently_read, buf.expected_size);
        }
        buf.currently_read == buf.expected_size
    }
}

impl Handler for Master {
    type Timeout = ();
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<Master>, token: Token, event: EventSet) {
        let worker = token.as_usize();
        println!("Event from {}: {:?}", worker, event);
        if event.is_error() {
            println!("Error connecting too {}", self.workers[worker]);
            match self.connections[worker].shutdown(Shutdown::Both) {
                Err(e) => println!("Error shutting down worker {}: {}", worker, e),
                Ok(_) => {},
            }
            // Remove the connection from the event loop
            match event_loop.deregister(&self.connections[worker]) {
                Err(e) => println!("Error deregistering worker {}: {}", worker, e),
                Ok(_) => {},
            }
        }
        // A worker is ready to receive instructions from us
        if event.is_writable() {
            let b_start = worker * self.blocks_per_worker;
            let b_count =
                if worker == self.workers.len() - 1 {
                    self.blocks_per_worker + self.blocks_remainder
                } else {
                    self.blocks_per_worker
                };
            let instr = Instructions::new(&self.config.scene_file, self.selected_frames, b_start, b_count);
            println!("Sending instructions {:?} to {}", instr, self.workers[worker]);
            let bytes = instr.to_json().into_bytes();
            // Loop until we successfully write the byes
            match self.connections[worker].write_all(&bytes[..]) {
                Err(e) => {
                    println!("Failed to send instructions to {}: {:?}", self.workers[worker], e);
                    return;
                },
                Ok(_) => println!("Instructions sent"),
            }
            // We no longer need to write anything, so close the write end
            match self.connections[worker].shutdown(Shutdown::Write) {
                Err(e) => panic!(format!("Failed to shutdown write end to worker {}: {}",
                                         self.workers[worker], e)),
                Ok(_) => {},
            }
        }
        // Some results are available from a worker
        if event.is_readable() {
            println!("Readable event from worker {}", worker);
            if self.read_worker_buffer(worker) {
                println!("Got all frame data, now parsing");
                let frame: worker::Frame = decode(&self.worker_buffers[worker].buf[..]).unwrap();
                println!("Saving frame results");
                self.save_results(frame);
                // Clean up our read buffer
                self.worker_buffers[worker].buf.clear();
                self.worker_buffers[worker].expected_size = 8;
                self.worker_buffers[worker].currently_read = 0;
            }
        }
        // If the worker has terminated, shutdown the read end of the connection
        if event.is_hup() {
            println!("Worker {} has hung up", worker);
            match self.connections[worker].shutdown(Shutdown::Both) {
                Err(e) => println!("Error shutting down worker {}: {}", worker, e),
                Ok(_) => {},
            }
            // Remove the connection from the event loop
            match event_loop.deregister(&self.connections[worker]) {
                Err(e) => println!("Error deregistering worker {}: {}", worker, e),
                Ok(_) => {},
            }
        }
        // After getting results from the worker we check if we've completed all our frames
        // and exit if so
        if self.frames.len() == self.config.frame_info.frames
            && self.frames.values().fold(true, |all, v| all && v.completed) {
                println!("All frames have been rendered, master exiting");
                event_loop.shutdown();
        }
    }
}

<commit_msg>Once we've sent instructions tell mio we don't care about write events<commit_after>//! The master module provides the Master struct which instructs Workers which
//! portions of the image they should render and collects their results to combine
//! into the final image.

use std::path::PathBuf;
use std::io::prelude::*;
use std::collections::HashMap;
use std::net::ToSocketAddrs;
use std::iter;

use bincode::rustc_serialize::decode;
use image;
use mio::tcp::{TcpStream, Shutdown};
use mio::*;

use film::Image;
use exec::Config;
use exec::distrib::{worker, Instructions};
use sampler::BlockQueue;

pub struct DistributedFrame {
    pub frame: usize,
    // The number of workers who have reported results for this
    // frame so far
    pub num_reporting: usize,
    pub render: Image,
    pub completed: bool,
}

#[derive(Clone, Debug)]
struct WorkerBuffer {
    pub buf: Vec<u8>,
    pub expected_size: usize,
    pub currently_read: usize,
}

impl WorkerBuffer {
    pub fn new() -> WorkerBuffer {
        WorkerBuffer { buf: Vec::new(), expected_size: 8, currently_read: 0 }
    }
}

pub struct Master {
    // Hostnames of the workers to send work too
    workers: Vec<String>,
    connections: Vec<TcpStream>,
    // Temporary buffers to store worker results in as they're
    // read in over TCP
    worker_buffers: Vec<WorkerBuffer>,
    config: Config,
    frames: HashMap<usize, DistributedFrame>,
    selected_frames: Option<(usize, usize)>,
    img_dim: (usize, usize),
    blocks_per_worker: usize,
    blocks_remainder: usize,
}

impl Master {
    /// Create a new master that will contact the worker nodes passed and
    /// send instructions on what parts of the scene to start rendering
    pub fn start_workers(workers: Vec<String>, config: Config, img_dim: (usize, usize),
                         frames: Option<(usize, usize)>) -> (Master, EventLoop<Master>) {
        // Figure out how many blocks we have for this image and assign them to our workers
        let queue = BlockQueue::new((img_dim.0 as u32, img_dim.1 as u32), (8, 8), (0, 0));
        let blocks_per_worker = queue.len() / workers.len();
        let blocks_remainder = queue.len() % workers.len();
        println!("Have {} workers, each worker does {} blocks w/ {} remainder",
                 workers.len(), blocks_per_worker, blocks_remainder);

        let mut event_loop = EventLoop::<Master>::new().unwrap();
        let mut connections = Vec::new();

        // Connect to each worker and send instructions on what to render
        // I guess this should also be queue'd up and the writes actually performed asynchronously?
        // Otherwise we need to loop on write_all while waiting for the connection to open
        for (i, host) in workers.iter().enumerate() {
            let addr = (&host[..], worker::PORT).to_socket_addrs().unwrap().next().unwrap();
            println!("Connecting too {:?}", addr);
            match TcpStream::connect(&addr) {
                Ok(stream) => {
                    println!("Connected and writing");
                    println!("Adding stream to event loop");
                    // Each worker is identified in the event loop by their index in the vec
                    match event_loop.register(&stream, Token(i)) {
                        Err(e) => println!("Error registering stream from {}: {}", host, e),
                        Ok(_) => {},
                    }
                    connections.push(stream);
                },
                Err(e) => println!("Failed to contact worker {}: {:?}", host, e),
            }
        }
        let worker_buffers: Vec<_> = iter::repeat(WorkerBuffer::new()).take(workers.len()).collect();
        let master = Master { workers: workers, connections: connections,
                              worker_buffers: worker_buffers, config: config,
                              frames: HashMap::new(), selected_frames: frames,
                              img_dim: img_dim,
                              blocks_per_worker: blocks_per_worker,
                              blocks_remainder: blocks_remainder };
        (master, event_loop)
    }
    /// Read a result frame from a worker and save it into the list of frames we're collecting from
    /// all workers. Will save out the final render if all workers have reported results for this
    /// frame.
    fn save_results(&mut self, frame: worker::Frame) {
        // Find the frame this worker is referring to and add its results
        let frame_num = frame.frame as usize;
        println!("Worker reporting frame {}", frame_num);
        if let Some(df) = self.frames.get_mut(&frame_num) {
            df.render.add_blocks(frame.block_size, &frame.blocks, &frame.pixels);
            df.num_reporting += 1;
            println!("We have parts of this frame already");
        }
        // TODO: Better way here? We get stuck because self.frames is counted as borrowed
        // from the if above, making this really awkward.
        if self.frames.get_mut(&frame_num).is_none() {
            // TODO: I need to seperate the render target from the actual image as the
            // filter here isn't used in this path and it doesn't make sense to have one
            let render = Image::new(self.img_dim);
            let mut df = DistributedFrame { frame: frame_num, num_reporting: 1, render: render, completed: false };
            df.render.add_blocks(frame.block_size, &frame.blocks, &frame.pixels);
            self.frames.insert(df.frame, df);
            println!("This is a new frame");
        }
        if let Some(df) = self.frames.get_mut(&frame_num) {
            if df.num_reporting == self.workers.len() {
                df.completed = true;
                println!("We have completed frame {}", frame_num);
                let out_file = match self.config.out_path.extension() {
                    Some(_) => self.config.out_path.clone(),
                    None => self.config.out_path.join(PathBuf::from(format!("frame{:05}.png", df.frame))),
                };
                println!("Frame {}: rendered to '{}'\n--------------------", frame_num, out_file.display());
                let img = df.render.get_srgb8();
                let dim = df.render.dimensions();
                match image::save_buffer(&out_file.as_path(), &img[..], dim.0 as u32, dim.1 as u32, image::RGB(8)) {
                    Ok(_) => {},
                    Err(e) => println!("Error saving image, {}", e),
                };
            }
        }
    }
    fn read_worker_buffer(&mut self, worker: usize) -> bool {
        let mut buf = &mut self.worker_buffers[worker];
        // If we haven't read the size of data being sent, read that now
        if buf.currently_read < 8 {
            // First 8 bytes are a u64 specifying the number of bytes being sent
            buf.buf.extend(iter::repeat(0u8).take(8));
            println!("Reading size header...");
            match self.connections[worker].read(&mut buf.buf[buf.currently_read..]) {
                Ok(n) => buf.currently_read += n,
                Err(e) => println!("Error reading results from worker {}: {}", self.workers[worker], e),
            }
            println!("Read {} bytes so far, must read {} in total", buf.currently_read, buf.expected_size);
            if buf.currently_read == buf.expected_size {
                println!("Got size header");
                // How many bytes we expect to get from the worker for a frame
                buf.expected_size = decode(&buf.buf[..]).unwrap();
                println!("Expecting {} bytes", buf.expected_size);
                // Extend the Vec so we've got enough room for the remaning bytes, minus the 8 for the
                // encoded size header
                buf.buf.extend(iter::repeat(0u8).take(buf.expected_size - 8));
            }
        }
        // If we've finished reading the size header we can now start reading the frame data
        if buf.currently_read >= 8 {
            println!("Reading from worker");
            match self.connections[worker].read(&mut buf.buf[buf.currently_read..]) {
                Ok(n) => buf.currently_read += n,
                Err(e) => println!("Error reading results from worker {}: {}", self.workers[worker], e),
            }
            println!("Read {} bytes so far, must read {} in total", buf.currently_read, buf.expected_size);
        }
        buf.currently_read == buf.expected_size
    }
}

impl Handler for Master {
    type Timeout = ();
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<Master>, token: Token, event: EventSet) {
        let worker = token.as_usize();
        println!("Event from {}: {:?}", worker, event);
        if event.is_error() {
            println!("Error connecting too {}", self.workers[worker]);
            match self.connections[worker].shutdown(Shutdown::Both) {
                Err(e) => println!("Error shutting down worker {}: {}", worker, e),
                Ok(_) => {},
            }
            // Remove the connection from the event loop
            match event_loop.deregister(&self.connections[worker]) {
                Err(e) => println!("Error deregistering worker {}: {}", worker, e),
                Ok(_) => {},
            }
        }
        // A worker is ready to receive instructions from us
        if event.is_writable() {
            let b_start = worker * self.blocks_per_worker;
            let b_count =
                if worker == self.workers.len() - 1 {
                    self.blocks_per_worker + self.blocks_remainder
                } else {
                    self.blocks_per_worker
                };
            let instr = Instructions::new(&self.config.scene_file, self.selected_frames, b_start, b_count);
            println!("Sending instructions {:?} to {}", instr, self.workers[worker]);
            let bytes = instr.to_json().into_bytes();
            // Loop until we successfully write the byes
            match self.connections[worker].write_all(&bytes[..]) {
                Err(e) => {
                    println!("Failed to send instructions to {}: {:?}", self.workers[worker], e);
                    return;
                },
                Ok(_) => println!("Instructions sent"),
            }
            // Register that we no longer care about writable events on this connection
            event_loop.reregister(&self.connections[worker], token,
                                  EventSet::readable() | EventSet::error() | EventSet::hup(),
                                  PollOpt::level()).expect("Re-registering failed");
            // We no longer need to write anything, so close the write end
            match self.connections[worker].shutdown(Shutdown::Write) {
                Err(e) => panic!(format!("Failed to shutdown write end to worker {}: {}",
                                         self.workers[worker], e)),
                Ok(_) => {},
            }
        }
        // Some results are available from a worker
        if event.is_readable() {
            println!("Readable event from worker {}", worker);
            if self.read_worker_buffer(worker) {
                println!("Got all frame data, now parsing");
                let frame: worker::Frame = decode(&self.worker_buffers[worker].buf[..]).unwrap();
                println!("Saving frame results");
                self.save_results(frame);
                // Clean up our read buffer
                self.worker_buffers[worker].buf.clear();
                self.worker_buffers[worker].expected_size = 8;
                self.worker_buffers[worker].currently_read = 0;
            }
        }
        // If the worker has terminated, shutdown the read end of the connection
        if event.is_hup() {
            println!("Worker {} has hung up", worker);
            match self.connections[worker].shutdown(Shutdown::Both) {
                Err(e) => println!("Error shutting down worker {}: {}", worker, e),
                Ok(_) => {},
            }
            // Remove the connection from the event loop
            match event_loop.deregister(&self.connections[worker]) {
                Err(e) => println!("Error deregistering worker {}: {}", worker, e),
                Ok(_) => {},
            }
        }
        // After getting results from the worker we check if we've completed all our frames
        // and exit if so
        if self.frames.len() == self.config.frame_info.frames
            && self.frames.values().fold(true, |all, v| all && v.completed) {
                println!("All frames have been rendered, master exiting");
                event_loop.shutdown();
        }
    }
}

<|endoftext|>


<commit_before>#![allow(unsafe_code)]
#![allow(unused)]

use std::{
    alloc::{alloc, dealloc, Layout},
    convert::TryFrom,
    mem::size_of,
    num::NonZeroU64,
};

const ACTUAL_HEADER_SZ: usize = 21;
const ALIGNMENT: usize = 8;

fn aligned_boxed_slice(size: usize) -> Box<[u8]> {
    let size = size.max(size_of::<Header>());
    let layout = Layout::from_size_align(size, ALIGNMENT).unwrap();

    unsafe {
        let ptr = alloc(layout);
        let fat_ptr = fatten(ptr, size);
        let ret = Box::from_raw(fat_ptr);
        assert_eq!(ret.len(), size);
        ret
    }
}

/// <https://users.rust-lang.org/t/construct-fat-pointer-to-struct/29198/9>
#[allow(trivial_casts)]
#[inline]
fn fatten(data: *const u8, len: usize) -> *mut [u8] {
    // Requirements of slice::from_raw_parts.
    assert!(!data.is_null());
    assert!(isize::try_from(len).is_ok());

    let slice = unsafe { core::slice::from_raw_parts(data as *const (), len) };
    slice as *const [()] as *mut _
}

#[repr(C)]
#[derive(Debug)]
struct Header {
    // NB always lay out fields from largest to smallest
    // to properly pack the struct
    pub next: Option<NonZeroU64>,
    pub merging_child: Option<NonZeroU64>,
    pub children: u16,
    pub prefix_len: u8,
    pub merging: bool,
    pub is_index: bool,
}

pub(crate) struct InlineRecords(Box<[u8]>);

impl InlineRecords {
    fn new() -> InlineRecords {
        let mut boxed_slice = aligned_boxed_slice(ACTUAL_HEADER_SZ);
        boxed_slice[..size_of::<Header>()]
            .copy_from_slice(&[0; size_of::<Header>()]);
        InlineRecords(boxed_slice)
    }

    fn header(&mut self) -> &Header {
        unsafe { &*(self.0.as_ptr() as *mut Header) }
    }

    fn header_mut(&mut self) -> &mut Header {
        unsafe { &mut *(self.0.as_ptr() as *mut Header) }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn simple() {
        let mut ir = InlineRecords::new();
        let header: &mut Header = ir.header_mut();
        header.next = Some(NonZeroU64::new(5).unwrap());
        header.is_index = true;
        dbg!(header);
        println!("ir: {:?}", ir.0);
    }
}
<commit_msg>Make Header Copy<commit_after>#![allow(unsafe_code)]
#![allow(unused)]

use std::{
    alloc::{alloc, dealloc, Layout},
    convert::TryFrom,
    mem::size_of,
    num::NonZeroU64,
};

const ACTUAL_HEADER_SZ: usize = 21;
const ALIGNMENT: usize = 8;

fn aligned_boxed_slice(size: usize) -> Box<[u8]> {
    let size = size.max(size_of::<Header>());
    let layout = Layout::from_size_align(size, ALIGNMENT).unwrap();

    unsafe {
        let ptr = alloc(layout);
        let fat_ptr = fatten(ptr, size);
        let ret = Box::from_raw(fat_ptr);
        assert_eq!(ret.len(), size);
        ret
    }
}

/// <https://users.rust-lang.org/t/construct-fat-pointer-to-struct/29198/9>
#[allow(trivial_casts)]
#[inline]
fn fatten(data: *const u8, len: usize) -> *mut [u8] {
    // Requirements of slice::from_raw_parts.
    assert!(!data.is_null());
    assert!(isize::try_from(len).is_ok());

    let slice = unsafe { core::slice::from_raw_parts(data as *const (), len) };
    slice as *const [()] as *mut _
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
struct Header {
    // NB always lay out fields from largest to smallest
    // to properly pack the struct
    pub next: Option<NonZeroU64>,
    pub merging_child: Option<NonZeroU64>,
    pub children: u16,
    pub prefix_len: u8,
    pub merging: bool,
    pub is_index: bool,
}

pub(crate) struct InlineRecords(Box<[u8]>);

impl InlineRecords {
    fn new() -> InlineRecords {
        let mut boxed_slice = aligned_boxed_slice(ACTUAL_HEADER_SZ);
        boxed_slice[..size_of::<Header>()]
            .copy_from_slice(&[0; size_of::<Header>()]);
        InlineRecords(boxed_slice)
    }

    fn header(&mut self) -> &Header {
        unsafe { &*(self.0.as_ptr() as *mut Header) }
    }

    fn header_mut(&mut self) -> &mut Header {
        unsafe { &mut *(self.0.as_ptr() as *mut Header) }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn simple() {
        let mut ir = InlineRecords::new();
        let header: &mut Header = ir.header_mut();
        header.next = Some(NonZeroU64::new(5).unwrap());
        header.is_index = true;
        dbg!(header);
        println!("ir: {:?}", ir.0);
    }
}
<|endoftext|>


<commit_before>use model::*;
use serde::de::{Deserialize, Error as DeError, MapAccess, Visitor};
use std::error::Error as StdError;
use std::fmt::{Display, Formatter, Result as FmtResult, Write as FmtWrite};
use std::str::FromStr;
use internal::prelude::*;

#[cfg(all(feature = "cache", feature = "model"))]
use CACHE;
#[cfg(feature = "model")]
use http;

/// An emoji reaction to a message.
#[derive(Clone, Debug, Deserialize)]
pub struct Reaction {
    /// The [`Channel`] of the associated [`Message`].
    ///
    /// [`Channel`]: enum.Channel.html
    /// [`Message`]: struct.Message.html
    pub channel_id: ChannelId,
    /// The reactive emoji used.
    pub emoji: ReactionType,
    /// The Id of the [`Message`] that was reacted to.
    ///
    /// [`Message`]: struct.Message.html
    pub message_id: MessageId,
    /// The Id of the [`User`] that sent the reaction.
    ///
    /// [`User`]: struct.User.html
    pub user_id: UserId,
}

#[cfg(feature = "model")]
impl Reaction {
    /// Deletes the reaction, but only if the current user is the user who made
    /// the reaction or has permission to.
    ///
    /// **Note**: Requires the [Manage Messages] permission, _if_ the current
    /// user did not perform the reaction.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, then returns a
    /// [`ModelError::InvalidPermissions`] if the current user does not have
    /// the required [permissions].
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
    /// [permissions]: permissions
    pub fn delete(&self) -> Result<()> {
        let user_id = feature_cache! {
            {
                let user = if self.user_id == CACHE.read().user.id {
                    None
                } else {
                    Some(self.user_id.0)
                };

                // If the reaction is one _not_ made by the current user, then ensure
                // that the current user has permission* to delete the reaction.
                //
                // Normally, users can only delete their own reactions.
                //
                // * The `Manage Messages` permission.
                if user.is_some() {
                    let req = Permissions::MANAGE_MESSAGES;

                    if !utils::user_has_perms(self.channel_id, req).unwrap_or(true) {
                        return Err(Error::Model(ModelError::InvalidPermissions(req)));
                    }
                }

                user
            } else {
                Some(self.user_id.0)
            }
        };

        http::delete_reaction(self.channel_id.0, self.message_id.0, user_id, &self.emoji)
    }

    /// Retrieves the list of [`User`]s who have reacted to a [`Message`] with a
    /// certain [`Emoji`].
    ///
    /// The default `limit` is `50` - specify otherwise to receive a different
    /// maximum number of users. The maximum that may be retrieve at a time is
    /// `100`, if a greater number is provided then it is automatically reduced.
    ///
    /// The optional `after` attribute is to retrieve the users after a certain
    /// user. This is useful for pagination.
    ///
    /// **Note**: Requires the [Read Message History] permission.
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::InvalidPermissions`] if the current user does
    /// not have the required [permissions].
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [`Emoji`]: struct.Emoji.html
    /// [`Message`]: struct.Message.html
    /// [`User`]: struct.User.html
    /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
    /// [permissions]: permissions
    pub fn users<R, U>(&self,
                       reaction_type: R,
                       limit: Option<u8>,
                       after: Option<U>)
                       -> Result<Vec<User>>
        where R: Into<ReactionType>, U: Into<UserId> {
        http::get_reaction_users(
            self.channel_id.0,
            self.message_id.0,
            &reaction_type.into(),
            limit.unwrap_or(50),
            after.map(|u| u.into().0),
        )
    }
}

/// The type of a [`Reaction`] sent.
///
/// [`Reaction`]: struct.Reaction.html
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ReactionType {
    /// A reaction with a [`Guild`]s custom [`Emoji`], which is unique to the
    /// guild.
    ///
    /// [`Emoji`]: struct.Emoji.html
    /// [`Guild`]: struct.Guild.html
    Custom {
        /// The Id of the custom [`Emoji`].
        ///
        /// [`Emoji`]: struct.Emoji.html
        id: EmojiId,
        /// The name of the custom emoji. This is primarily used for decoration
        /// and distinguishing the emoji client-side.
        name: Option<String>,
    },
    /// A reaction with a twemoji.
    Unicode(String),
}

impl<'de> Deserialize<'de> for ReactionType {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
        #[derive(Deserialize)]
        #[serde(field_identifier, rename_all = "snake_case")]
        enum Field {
            Id,
            Name,
        }

        struct ReactionTypeVisitor;

        impl<'de> Visitor<'de> for ReactionTypeVisitor {
            type Value = ReactionType;

            fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
                formatter.write_str("enum ReactionType")
            }

            fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> StdResult<Self::Value, V::Error> {
                let mut id = None;
                let mut name = None;

                while let Some(key) = map.next_key()? {
                    match key {
                        Field::Id => {
                            if id.is_some() {
                                return Err(DeError::duplicate_field("id"));
                            }

                            if let Ok(emoji_id) = map.next_value::<EmojiId>() {
                                id = Some(emoji_id)
                            }
                        },
                        Field::Name => {
                            if name.is_some() {
                                return Err(DeError::duplicate_field("name"));
                            }

                            name = Some(map.next_value()?);
                        },
                    }
                }

                let name = name.ok_or_else(|| DeError::missing_field("name"))?;

                Ok(if let Some(id) = id {
                    ReactionType::Custom {
                        id: id,
                        name: name,
                    }
                } else {
                    ReactionType::Unicode(name.unwrap())
                })
            }
        }

        deserializer.deserialize_map(ReactionTypeVisitor)
    }
}

#[cfg(any(feature = "model", feature = "http"))]
impl ReactionType {
    /// Creates a data-esque display of the type. This is not very useful for
    /// displaying, as the primary client can not render it, but can be useful
    /// for debugging.
    ///
    /// **Note**: This is mainly for use internally. There is otherwise most
    /// likely little use for it.
    pub fn as_data(&self) -> String {
        match *self {
            ReactionType::Custom {
                id,
                ref name,
            } => format!("{}:{}", name.as_ref().map_or("", |s| s.as_str()), id),
            ReactionType::Unicode(ref unicode) => unicode.clone(),
        }
    }
}

#[cfg(feature = "model")]
impl From<char> for ReactionType {
    /// Creates a `ReactionType` from a `char`.
    ///
    /// # Examples
    ///
    /// Reacting to a message with an apple:
    ///
    /// ```rust,no_run
    /// # use serenity::model::ChannelId;
    /// # use std::error::Error;
    /// #
    /// # fn try_main() -> Result<(), Box<Error>> {
    /// #     let message = ChannelId(0).message(0)?;
    /// #
    /// message.react('🍎')?;
    /// #     Ok(())
    /// # }
    /// #
    /// # fn main() {
    /// #     try_main().unwrap();
    /// # }
    /// ```
    fn from(ch: char) -> ReactionType { ReactionType::Unicode(ch.to_string()) }
}

impl From<Emoji> for ReactionType {
    fn from(emoji: Emoji) -> ReactionType {
        ReactionType::Custom {
            id: emoji.id,
            name: Some(emoji.name),
        }
    }
}

impl From<String> for ReactionType {
    fn from(unicode: String) -> ReactionType { ReactionType::Unicode(unicode) }
}

impl<'a> From<&'a str> for ReactionType {
    /// Creates a `ReactionType` from a string slice.
    ///
    /// # Examples
    ///
    /// Creating a `ReactionType` from a `🍎`, modeling a similar API as the
    /// rest of the library:
    ///
    /// ```rust
    /// use serenity::model::ReactionType;
    ///
    /// fn foo<R: Into<ReactionType>>(bar: R) {
    ///     println!("{:?}", bar.into());
    /// }
    ///
    /// foo("🍎");
    /// ```
    fn from(unicode: &str) -> ReactionType { ReactionType::Unicode(unicode.to_string()) }
}

// TODO: Change this to `!` once it becomes stable.

#[derive(Debug)]
pub enum NeverFails {}

impl Display for NeverFails {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "never fails")
    }
}

impl StdError for NeverFails {
    fn description(&self) -> &str {
        "never fails"
    }
}

impl FromStr for ReactionType {
    type Err = NeverFails;

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        Ok(ReactionType::from(s))
    }
}

impl Display for ReactionType {
    /// Formats the reaction type, displaying the associated emoji in a
    /// way that clients can understand.
    ///
    /// If the type is a [custom][`ReactionType::Custom`] emoji, then refer to
    /// the documentation for [emoji's formatter][`Emoji::fmt`] on how this is
    /// displayed. Otherwise, if the type is a
    /// [unicode][`ReactionType::Unicode`], then the inner unicode is displayed.
    ///
    /// [`Emoji::fmt`]: struct.Emoji.html#method.fmt
    /// [`ReactionType::Custom`]: enum.ReactionType.html#variant.Custom
    /// [`ReactionType::Unicode`]: enum.ReactionType.html#variant.Unicode
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            ReactionType::Custom {
                id,
                ref name,
            } => {
                f.write_char('<')?;
                f.write_char(':')?;
                f.write_str(name.as_ref().map_or("", |s| s.as_str()))?;
                f.write_char(':')?;
                Display::fmt(&id, f)?;
                f.write_char('>')
            },
            ReactionType::Unicode(ref unicode) => f.write_str(unicode),
        }
    }
}
<commit_msg>Implement From<EmojiId | EmojiIdentifier> for ReactionType (#217)<commit_after>use model::*;
use serde::de::{Deserialize, Error as DeError, MapAccess, Visitor};
use std::error::Error as StdError;
use std::fmt::{Display, Formatter, Result as FmtResult, Write as FmtWrite};
use std::str::FromStr;
use internal::prelude::*;

#[cfg(all(feature = "cache", feature = "model"))]
use CACHE;
#[cfg(feature = "model")]
use http;

/// An emoji reaction to a message.
#[derive(Clone, Debug, Deserialize)]
pub struct Reaction {
    /// The [`Channel`] of the associated [`Message`].
    ///
    /// [`Channel`]: enum.Channel.html
    /// [`Message`]: struct.Message.html
    pub channel_id: ChannelId,
    /// The reactive emoji used.
    pub emoji: ReactionType,
    /// The Id of the [`Message`] that was reacted to.
    ///
    /// [`Message`]: struct.Message.html
    pub message_id: MessageId,
    /// The Id of the [`User`] that sent the reaction.
    ///
    /// [`User`]: struct.User.html
    pub user_id: UserId,
}

#[cfg(feature = "model")]
impl Reaction {
    /// Deletes the reaction, but only if the current user is the user who made
    /// the reaction or has permission to.
    ///
    /// **Note**: Requires the [Manage Messages] permission, _if_ the current
    /// user did not perform the reaction.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, then returns a
    /// [`ModelError::InvalidPermissions`] if the current user does not have
    /// the required [permissions].
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [Manage Messages]: permissions/constant.MANAGE_MESSAGES.html
    /// [permissions]: permissions
    pub fn delete(&self) -> Result<()> {
        let user_id = feature_cache! {
            {
                let user = if self.user_id == CACHE.read().user.id {
                    None
                } else {
                    Some(self.user_id.0)
                };

                // If the reaction is one _not_ made by the current user, then ensure
                // that the current user has permission* to delete the reaction.
                //
                // Normally, users can only delete their own reactions.
                //
                // * The `Manage Messages` permission.
                if user.is_some() {
                    let req = Permissions::MANAGE_MESSAGES;

                    if !utils::user_has_perms(self.channel_id, req).unwrap_or(true) {
                        return Err(Error::Model(ModelError::InvalidPermissions(req)));
                    }
                }

                user
            } else {
                Some(self.user_id.0)
            }
        };

        http::delete_reaction(self.channel_id.0, self.message_id.0, user_id, &self.emoji)
    }

    /// Retrieves the list of [`User`]s who have reacted to a [`Message`] with a
    /// certain [`Emoji`].
    ///
    /// The default `limit` is `50` - specify otherwise to receive a different
    /// maximum number of users. The maximum that may be retrieve at a time is
    /// `100`, if a greater number is provided then it is automatically reduced.
    ///
    /// The optional `after` attribute is to retrieve the users after a certain
    /// user. This is useful for pagination.
    ///
    /// **Note**: Requires the [Read Message History] permission.
    ///
    /// # Errors
    ///
    /// Returns a [`ModelError::InvalidPermissions`] if the current user does
    /// not have the required [permissions].
    ///
    /// [`ModelError::InvalidPermissions`]: enum.ModelError.html#variant.InvalidPermissions
    /// [`Emoji`]: struct.Emoji.html
    /// [`Message`]: struct.Message.html
    /// [`User`]: struct.User.html
    /// [Read Message History]: permissions/constant.READ_MESSAGE_HISTORY.html
    /// [permissions]: permissions
    pub fn users<R, U>(&self,
                       reaction_type: R,
                       limit: Option<u8>,
                       after: Option<U>)
                       -> Result<Vec<User>>
        where R: Into<ReactionType>, U: Into<UserId> {
        http::get_reaction_users(
            self.channel_id.0,
            self.message_id.0,
            &reaction_type.into(),
            limit.unwrap_or(50),
            after.map(|u| u.into().0),
        )
    }
}

/// The type of a [`Reaction`] sent.
///
/// [`Reaction`]: struct.Reaction.html
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ReactionType {
    /// A reaction with a [`Guild`]s custom [`Emoji`], which is unique to the
    /// guild.
    ///
    /// [`Emoji`]: struct.Emoji.html
    /// [`Guild`]: struct.Guild.html
    Custom {
        /// The Id of the custom [`Emoji`].
        ///
        /// [`Emoji`]: struct.Emoji.html
        id: EmojiId,
        /// The name of the custom emoji. This is primarily used for decoration
        /// and distinguishing the emoji client-side.
        name: Option<String>,
    },
    /// A reaction with a twemoji.
    Unicode(String),
}

impl<'de> Deserialize<'de> for ReactionType {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
        #[derive(Deserialize)]
        #[serde(field_identifier, rename_all = "snake_case")]
        enum Field {
            Id,
            Name,
        }

        struct ReactionTypeVisitor;

        impl<'de> Visitor<'de> for ReactionTypeVisitor {
            type Value = ReactionType;

            fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
                formatter.write_str("enum ReactionType")
            }

            fn visit_map<V: MapAccess<'de>>(self, mut map: V) -> StdResult<Self::Value, V::Error> {
                let mut id = None;
                let mut name = None;

                while let Some(key) = map.next_key()? {
                    match key {
                        Field::Id => {
                            if id.is_some() {
                                return Err(DeError::duplicate_field("id"));
                            }

                            if let Ok(emoji_id) = map.next_value::<EmojiId>() {
                                id = Some(emoji_id)
                            }
                        },
                        Field::Name => {
                            if name.is_some() {
                                return Err(DeError::duplicate_field("name"));
                            }

                            name = Some(map.next_value()?);
                        },
                    }
                }

                let name = name.ok_or_else(|| DeError::missing_field("name"))?;

                Ok(if let Some(id) = id {
                    ReactionType::Custom {
                        id: id,
                        name: name,
                    }
                } else {
                    ReactionType::Unicode(name.unwrap())
                })
            }
        }

        deserializer.deserialize_map(ReactionTypeVisitor)
    }
}

#[cfg(any(feature = "model", feature = "http"))]
impl ReactionType {
    /// Creates a data-esque display of the type. This is not very useful for
    /// displaying, as the primary client can not render it, but can be useful
    /// for debugging.
    ///
    /// **Note**: This is mainly for use internally. There is otherwise most
    /// likely little use for it.
    pub fn as_data(&self) -> String {
        match *self {
            ReactionType::Custom {
                id,
                ref name,
            } => format!("{}:{}", name.as_ref().map_or("", |s| s.as_str()), id),
            ReactionType::Unicode(ref unicode) => unicode.clone(),
        }
    }
}

#[cfg(feature = "model")]
impl From<char> for ReactionType {
    /// Creates a `ReactionType` from a `char`.
    ///
    /// # Examples
    ///
    /// Reacting to a message with an apple:
    ///
    /// ```rust,no_run
    /// # use serenity::model::ChannelId;
    /// # use std::error::Error;
    /// #
    /// # fn try_main() -> Result<(), Box<Error>> {
    /// #     let message = ChannelId(0).message(0)?;
    /// #
    /// message.react('🍎')?;
    /// #     Ok(())
    /// # }
    /// #
    /// # fn main() {
    /// #     try_main().unwrap();
    /// # }
    /// ```
    fn from(ch: char) -> ReactionType { ReactionType::Unicode(ch.to_string()) }
}

impl From<Emoji> for ReactionType {
    fn from(emoji: Emoji) -> ReactionType {
        ReactionType::Custom {
            id: emoji.id,
            name: Some(emoji.name),
        }
    }
}

impl From<EmojiId> for ReactionType {
    fn from(emoji_id: EmojiId) -> ReactionType {
        ReactionType::Custom {
            id: emoji_id,
            name: None
        }
    }
}

impl From<EmojiIdentifier> for ReactionType {
    fn from(emoji_id: EmojiIdentifier) -> ReactionType {
        ReactionType::Custom {
            id: emoji_id.id,
            name: Some(emoji_id.name)
        }
    }
}

impl From<String> for ReactionType {
    fn from(unicode: String) -> ReactionType { ReactionType::Unicode(unicode) }
}

impl<'a> From<&'a str> for ReactionType {
    /// Creates a `ReactionType` from a string slice.
    ///
    /// # Examples
    ///
    /// Creating a `ReactionType` from a `🍎`, modeling a similar API as the
    /// rest of the library:
    ///
    /// ```rust
    /// use serenity::model::ReactionType;
    ///
    /// fn foo<R: Into<ReactionType>>(bar: R) {
    ///     println!("{:?}", bar.into());
    /// }
    ///
    /// foo("🍎");
    /// ```
    fn from(unicode: &str) -> ReactionType { ReactionType::Unicode(unicode.to_string()) }
}

// TODO: Change this to `!` once it becomes stable.

#[derive(Debug)]
pub enum NeverFails {}

impl Display for NeverFails {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "never fails")
    }
}

impl StdError for NeverFails {
    fn description(&self) -> &str {
        "never fails"
    }
}

impl FromStr for ReactionType {
    type Err = NeverFails;

    fn from_str(s: &str) -> ::std::result::Result<Self, Self::Err> {
        Ok(ReactionType::from(s))
    }
}

impl Display for ReactionType {
    /// Formats the reaction type, displaying the associated emoji in a
    /// way that clients can understand.
    ///
    /// If the type is a [custom][`ReactionType::Custom`] emoji, then refer to
    /// the documentation for [emoji's formatter][`Emoji::fmt`] on how this is
    /// displayed. Otherwise, if the type is a
    /// [unicode][`ReactionType::Unicode`], then the inner unicode is displayed.
    ///
    /// [`Emoji::fmt`]: struct.Emoji.html#method.fmt
    /// [`ReactionType::Custom`]: enum.ReactionType.html#variant.Custom
    /// [`ReactionType::Unicode`]: enum.ReactionType.html#variant.Unicode
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            ReactionType::Custom {
                id,
                ref name,
            } => {
                f.write_char('<')?;
                f.write_char(':')?;
                f.write_str(name.as_ref().map_or("", |s| s.as_str()))?;
                f.write_char(':')?;
                Display::fmt(&id, f)?;
                f.write_char('>')
            },
            ReactionType::Unicode(ref unicode) => f.write_str(unicode),
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate assert_cli;

const LINK_CHECKER: &'static str = "target/debug/anchor-link-checker";

#[test]
fn pass() {
    assert_cli!(
        LINK_CHECKER, &["tests/fixtures/pass.html"] =>
        Success, "Yay!"
    ).unwrap();
}

#[test]
fn missing_file() {
    assert_cli!(
        LINK_CHECKER, &["tests/fixtures/missing_file.html"] =>
        Error 1, "Couldn't read file"
    ).unwrap();
}

#[test]
fn fail() {
    assert_cli!(
        LINK_CHECKER, &["tests/fixtures/fail.html"] =>
        Error 1, "Missing links: [\"missing-link\"]"
    ).unwrap();
}
<commit_msg>Relative test paths<commit_after>#[macro_use] extern crate assert_cli;

const LINK_CHECKER: &'static str = "target/debug/anchor-link-checker";

#[test]
fn pass() {
    assert_cli!(
        LINK_CHECKER, &["./tests/fixtures/pass.html"] =>
        Success, "Yay!"
    ).unwrap();
}

#[test]
fn missing_file() {
    assert_cli!(
        LINK_CHECKER, &["./tests/fixtures/missing_file.html"] =>
        Error 1, "Couldn't read file"
    ).unwrap();
}

#[test]
fn fail() {
    assert_cli!(
        LINK_CHECKER, &["./tests/fixtures/fail.html"] =>
        Error 1, "Missing links: [\"missing-link\"]"
    ).unwrap();
}
<|endoftext|>


<commit_before>//! The Pact `Message` type, including associated matching rules and provider states.

/*===============================================================================================
 * # Imports
 *---------------------------------------------------------------------------------------------*/

use crate::models::pact_specification::PactSpecification;
use crate::util::*;
use crate::{as_mut, as_ref, ffi_fn, safe_str};
use anyhow::{anyhow, Context};
use libc::{c_char, c_int, c_uint, EXIT_FAILURE, EXIT_SUCCESS};
use pact_matching::models::OptionalBody;
use serde_json::from_str as from_json_str;
use serde_json::Value as JsonValue;
use std::ops::Drop;

/*===============================================================================================
 * # Re-Exports
 *---------------------------------------------------------------------------------------------*/

// Necessary to make 'cbindgen' generate an opaque struct on the C side.
pub use pact_matching::models::message::Message;
pub use pact_matching::models::provider_states::ProviderState;

/*===============================================================================================
 * # Message
 *---------------------------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------------------------
 * ## Constructors / Destructor
 */

ffi_fn! {
    /// Get a mutable pointer to a newly-created default message on the heap.
    fn message_new() -> *mut Message {
        let message = Message::default();
        ptr::raw_to(message)
    } {
        ptr::null_mut_to::<Message>()
    }
}

ffi_fn! {
    /// Constructs a `Message` from the JSON string
    fn message_new_from_json(
        index: c_uint,
        json_str: *const c_char,
        spec_version: PactSpecification
    ) -> *mut Message {
        let message = {
            let index = index as usize;
            let json_value: JsonValue = from_json_str(safe_str!(json_str))
                .context("error parsing json_str as JSON")?;
            let spec_version = spec_version.into();

            Message::from_json(index, &json_value, &spec_version)
                .map_err(|e| anyhow::anyhow!("{}", e))?
        };

        ptr::raw_to(message)
    } {
        ptr::null_mut_to::<Message>()
    }
}

ffi_fn! {
    /// Destroy the `Message` being pointed to.
    fn message_delete(message: *mut Message) {
        ptr::drop_raw(message);
    }
}

/*-----------------------------------------------------------------------------------------------
 * ## Contents
 */

ffi_fn! {
    /// Get the contents of a `Message`.
    fn message_get_contents(message: *const Message) -> *const c_char {
        let message = as_ref!(message);

        match message.contents {
            // If it's missing, return a null pointer.
            OptionalBody::Missing => ptr::null_to::<c_char>(),
            // If empty or null, return an empty string on the heap.
            OptionalBody::Empty | OptionalBody::Null => {
                let content = string::to_c("")?;
                content as *const c_char
            }
            // Otherwise, get the contents, possibly still empty.
            _ => {
                let content = string::to_c(message.contents.str_value())?;
                content as *const c_char
            }
        }
    } {
        ptr::null_to::<c_char>()
    }
}

/*-----------------------------------------------------------------------------------------------
 * ## Description
 */

ffi_fn! {
    /// Get a copy of the description.
    /// The returned string must be deleted with `string_delete`.
    ///
    /// Since it is a copy, the returned string may safely outlive
    /// the `Message`.
    ///
    /// # Errors
    ///
    /// On failure, this function will return a NULL pointer.
    ///
    /// This function may fail if the Rust string contains embedded
    /// null ('\0') bytes.
    fn message_get_description(message: *const Message) -> *const c_char {
        let message = as_ref!(message);
        let description = string::to_c(&message.description)?;
        description as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Write the `description` field on the `Message`.
    ///
    /// `description` must contain valid UTF-8. Invalid UTF-8
    /// will be replaced with U+FFFD REPLACEMENT CHARACTER.
    ///
    /// This function will only reallocate if the new string
    /// does not fit in the existing buffer.
    fn message_set_description(message: *mut Message, description: *const c_char) -> c_int {
        let message = as_mut!(message);
        let description = safe_str!(description);

        // Wipe out the previous contents of the string, without
        // deallocating, and set the new description.
        message.description.clear();
        message.description.push_str(description);

        EXIT_SUCCESS
    } {
        EXIT_FAILURE
    }
}

/*-----------------------------------------------------------------------------------------------
 * ## Provider States
 */

ffi_fn! {
    /// Get a copy of the provider state at the given index from this message.
    /// A pointer to the structure will be written to `out_provider_state`,
    /// only if no errors are encountered.
    ///
    /// The returned structure must be deleted with `provider_state_delete`.
    ///
    /// Since it is a copy, the returned structure may safely outlive
    /// the `Message`.
    ///
    /// # Errors
    ///
    /// On failure, this function will return a variant other than Success.
    ///
    /// This function may fail if the index requested is out of bounds,
    /// or if any of the Rust strings contain embedded null ('\0') bytes.
    fn message_get_provider_state(message: *const Message, index: c_uint) -> *const ProviderState {
        let message = as_ref!(message);
        let index = index as usize;

        // Get a raw pointer directly, rather than boxing it, as its owned by the `Message`
        // and will be cleaned up when the `Message` is cleaned up.
        let provider_state = message
            .provider_states
            .get(index)
            .ok_or(anyhow!("index is out of bounds"))?;

        provider_state as *const ProviderState
    } {
        ptr::null_to::<ProviderState>()
    }
}

ffi_fn! {
    /// Get an iterator over provider states.
    fn message_get_provider_state_iter(message: *mut Message) -> *mut ProviderStateIterator {
        let message = as_mut!(message);
        let iter = ProviderStateIterator { current: 0, message };
        ptr::raw_to(iter)
    } {
        ptr::null_mut_to::<ProviderStateIterator>()
    }
}

ffi_fn! {
    /// Get the next value from the iterator.
    fn provider_state_iter_next(iter: *mut ProviderStateIterator) -> *mut ProviderState {
        let iter = as_mut!(iter);
        let message = as_mut!(iter.message);
        let index = iter.next();
        let provider_state = message
            .provider_states
            .get_mut(index)
            .ok_or(anyhow::anyhow!("iter past the end of provider states"))?;
       provider_state as *mut ProviderState
    } {
        ptr::null_mut_to::<ProviderState>()
    }
}

ffi_fn! {
    /// Delete the iterator.
    fn provider_state_iter_delete(iter: *mut ProviderStateIterator) {
        ptr::drop_raw(iter);
    }
}

/// Iterator over individual provider states.
#[allow(missing_copy_implementations)]
#[allow(missing_debug_implementations)]
pub struct ProviderStateIterator {
    current: usize,
    message: *mut Message,
}

impl ProviderStateIterator {
    fn next(&mut self) -> usize {
        let idx = self.current;
        self.current += 1;
        idx
    }
}

/*-----------------------------------------------------------------------------------------------
 * ## Metadata
 */

ffi_fn! {
    /// Get a copy of the metadata value indexed by `key`.
    /// The returned string must be deleted with `string_delete`.
    ///
    /// Since it is a copy, the returned string may safely outlive
    /// the `Message`.
    ///
    /// The returned pointer will be NULL if the metadata does not contain
    /// the given key, or if an error occurred.
    ///
    /// # Errors
    ///
    /// On failure, this function will return a NULL pointer.
    ///
    /// This function may fail if the provided `key` string contains
    /// invalid UTF-8, or if the Rust string contains embedded null ('\0')
    /// bytes.
    fn message_find_metadata(message: *const Message, key: *const c_char) -> *const c_char {
        let message = as_ref!(message);
        let key = safe_str!(key);
        let value = message.metadata.get(key).ok_or(anyhow::anyhow!("invalid metadata key"))?;
        let value_ptr = string::to_c(value)?;
        value_ptr as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Insert the (`key`, `value`) pair into this Message's
    /// `metadata` HashMap.
    /// This function returns an enum indicating the result;
    /// see the comments on HashMapInsertStatus for details.
    ///
    /// # Errors
    ///
    /// This function may fail if the provided `key` or `value` strings
    /// contain invalid UTF-8.
    fn message_insert_metadata(
        message: *mut Message,
        key: *const c_char,
        value: *const c_char
    ) -> c_int {
        let message = as_mut!(message);
        let key = safe_str!(key);
        let value = safe_str!(value);

        match message.metadata.insert(key.to_string(), value.to_string()) {
            None => HashMapInsertStatus::SuccessNew as c_int,
            Some(_) => HashMapInsertStatus::SuccessOverwrite as c_int,
        }
    } {
        HashMapInsertStatus::Error as c_int
    }
}

ffi_fn! {
    /// Get an iterator over the metadata of a message.
    ///
    /// This iterator carries a pointer to the message, and must
    /// not outlive the message.
    ///
    /// The message metadata also must not be modified during iteration. If it is,
    /// the old iterator must be deleted and a new iterator created.
    ///
    /// # Errors
    ///
    /// On failure, this function will return a NULL pointer.
    ///
    /// This function may fail if any of the Rust strings contain
    /// embedded null ('\0') bytes.
    fn message_get_metadata_iter(message: *mut Message) -> *mut MessageMetadataIterator {
        let message = as_mut!(message);

        let iter = MessageMetadataIterator {
            keys:  message.metadata.keys().cloned().collect(),
            current: 0,
            message: message as *const Message,
        };

        ptr::raw_to(iter)
    } {
        ptr::null_mut_to::<MessageMetadataIterator>()
    }
}

ffi_fn! {
    /// Get the next key and value out of the iterator, if possible
    fn message_metadata_iter_next(iter: *mut MessageMetadataIterator) -> *mut MessageMetadataPair {
        let iter = as_mut!(iter);
        let message = as_ref!(iter.message);
        let key = iter.next().ok_or(anyhow::anyhow!("iter past the end of metadata"))?;
        let (key, value) = message
            .metadata
            .get_key_value(key)
            .ok_or(anyhow::anyhow!("iter provided invalid metadata key"))?;
        let pair = MessageMetadataPair::new(key, value)?;
        ptr::raw_to(pair)
    } {
        ptr::null_mut_to::<MessageMetadataPair>()
    }
}

ffi_fn! {
    /// Free the metadata iterator when you're done using it.
    fn message_metadata_iter_delete(iter: *mut MessageMetadataIterator) {
        ptr::drop_raw(iter);
    }
}

ffi_fn! {
    /// Free a pair of key and value returned from `message_metadata_iter_next`.
    fn message_metadata_pair_delete(pair: *mut MessageMetadataPair) {
        ptr::drop_raw(pair);
    }
}

/// An iterator that enables FFI iteration over metadata by putting all the keys on the heap
/// and tracking which one we're currently at.
///
/// This assumes no mutation of the underlying metadata happens while the iterator is live.
#[derive(Debug)]
pub struct MessageMetadataIterator {
    /// The metadata keys
    keys: Vec<String>,
    /// The current key
    current: usize,
    /// Pointer to the message.
    message: *const Message,
}

impl MessageMetadataIterator {
    fn next(&mut self) -> Option<&String> {
        let idx = self.current;
        self.current += 1;
        self.keys.get(idx)
    }
}

/// A single key-value pair exported to the C-side.
#[derive(Debug)]
#[repr(C)]
#[allow(missing_copy_implementations)]
pub struct MessageMetadataPair {
    /// The metadata key.
    key: *const c_char,
    /// The metadata value.
    value: *const c_char,
}

impl MessageMetadataPair {
    fn new(
        key: &str,
        value: &str,
    ) -> anyhow::Result<MessageMetadataPair> {
        Ok(MessageMetadataPair {
            key: string::to_c(key)? as *const c_char,
            value: string::to_c(value)? as *const c_char,
        })
    }
}

// Ensure that the owned strings are freed when the pair is dropped.
//
// Notice that we're casting from a `*const c_char` to a `*mut c_char`.
// This may seem wrong, but is safe so long as it doesn't violate Rust's
// guarantees around immutable references, which this doesn't. In this case,
// the underlying data came from `CString::into_raw` which takes ownership
// of the `CString` and hands it off via a `*mut pointer`. We cast that pointer
// back to `*const` to limit the C-side from doing any shenanigans, since the
// pointed-to values live inside of the `Message` metadata `HashMap`, but
// cast back to `*mut` here so we can free the memory.
//
// The discussion here helps explain: https://github.com/rust-lang/rust-clippy/issues/4774
impl Drop for MessageMetadataPair {
    fn drop(&mut self) {
        string::string_delete(self.key as *mut c_char);
        string::string_delete(self.value as *mut c_char);
    }
}

/*===============================================================================================
 * # Status Types
 *---------------------------------------------------------------------------------------------*/

/// Result from an attempt to insert into a HashMap
enum HashMapInsertStatus {
    /// The value was inserted, and the key was unset
    SuccessNew = 0,
    /// The value was inserted, and the key was previously set
    SuccessOverwrite = -1,
    /// An error occured, and the value was not inserted
    Error = -2,
}
<commit_msg>Added message_new_from_body (#61)<commit_after>//! The Pact `Message` type, including associated matching rules and provider states.

/*===============================================================================================
 * # Imports
 *---------------------------------------------------------------------------------------------*/

use crate::models::pact_specification::PactSpecification;
use crate::util::*;
use crate::{as_mut, as_ref, cstr, ffi_fn, safe_str};
use anyhow::{anyhow, Context};
use libc::{c_char, c_int, c_uint, EXIT_FAILURE, EXIT_SUCCESS};
use pact_matching::models::{content_types::ContentType, OptionalBody};
use serde_json::from_str as from_json_str;
use serde_json::Value as JsonValue;
use std::collections::HashMap;
use std::ops::Drop;

/*===============================================================================================
 * # Re-Exports
 *---------------------------------------------------------------------------------------------*/

// Necessary to make 'cbindgen' generate an opaque struct on the C side.
pub use pact_matching::models::message::Message;
pub use pact_matching::models::provider_states::ProviderState;

/*===============================================================================================
 * # Message
 *---------------------------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------------------------
 * ## Constructors / Destructor
 */

ffi_fn! {
    /// Get a mutable pointer to a newly-created default message on the heap.
    fn message_new() -> *mut Message {
        let message = Message::default();
        ptr::raw_to(message)
    } {
        ptr::null_mut_to::<Message>()
    }
}

ffi_fn! {
    /// Constructs a `Message` from the JSON string
    fn message_new_from_json(
        index: c_uint,
        json_str: *const c_char,
        spec_version: PactSpecification
    ) -> *mut Message {
        let message = {
            let index = index as usize;
            let json_value: JsonValue = from_json_str(safe_str!(json_str))
                .context("error parsing json_str as JSON")?;
            let spec_version = spec_version.into();

            Message::from_json(index, &json_value, &spec_version)
                .map_err(|e| anyhow::anyhow!("{}", e))?
        };

        ptr::raw_to(message)
    } {
        ptr::null_mut_to::<Message>()
    }
}

ffi_fn! {
    /// Constructs a `Message` from a body with a given content-type.
    fn message_new_from_body(body: *const c_char, content_type: *const c_char) -> *mut Message {
        // Get the body as a Vec<u8>.
        let body = cstr!(body)
            .to_bytes()
            .to_owned();

        // Parse the content type.
        let content_type = ContentType::parse(safe_str!(content_type))
            .map_err(|s| anyhow!("invalid content type '{}'", s))?;

        // Populate the Message metadata.
        let mut metadata = HashMap::new();
        metadata.insert(String::from("contentType"), content_type.to_string());

        // Populate the OptionalBody with our content and content type.
        let contents = OptionalBody::Present(body, Some(content_type));

        // Construct and return the message.
        let message = Message {
            contents,
            metadata,
            .. Message::default()
        };

        ptr::raw_to(message)
    } {
        ptr::null_mut_to::<Message>()
    }
}

ffi_fn! {
    /// Destroy the `Message` being pointed to.
    fn message_delete(message: *mut Message) {
        ptr::drop_raw(message);
    }
}

/*-----------------------------------------------------------------------------------------------
 * ## Contents
 */

ffi_fn! {
    /// Get the contents of a `Message`.
    fn message_get_contents(message: *const Message) -> *const c_char {
        let message = as_ref!(message);

        match message.contents {
            // If it's missing, return a null pointer.
            OptionalBody::Missing => ptr::null_to::<c_char>(),
            // If empty or null, return an empty string on the heap.
            OptionalBody::Empty | OptionalBody::Null => {
                let content = string::to_c("")?;
                content as *const c_char
            }
            // Otherwise, get the contents, possibly still empty.
            _ => {
                let content = string::to_c(message.contents.str_value())?;
                content as *const c_char
            }
        }
    } {
        ptr::null_to::<c_char>()
    }
}

/*-----------------------------------------------------------------------------------------------
 * ## Description
 */

ffi_fn! {
    /// Get a copy of the description.
    /// The returned string must be deleted with `string_delete`.
    ///
    /// Since it is a copy, the returned string may safely outlive
    /// the `Message`.
    ///
    /// # Errors
    ///
    /// On failure, this function will return a NULL pointer.
    ///
    /// This function may fail if the Rust string contains embedded
    /// null ('\0') bytes.
    fn message_get_description(message: *const Message) -> *const c_char {
        let message = as_ref!(message);
        let description = string::to_c(&message.description)?;
        description as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Write the `description` field on the `Message`.
    ///
    /// `description` must contain valid UTF-8. Invalid UTF-8
    /// will be replaced with U+FFFD REPLACEMENT CHARACTER.
    ///
    /// This function will only reallocate if the new string
    /// does not fit in the existing buffer.
    fn message_set_description(message: *mut Message, description: *const c_char) -> c_int {
        let message = as_mut!(message);
        let description = safe_str!(description);

        // Wipe out the previous contents of the string, without
        // deallocating, and set the new description.
        message.description.clear();
        message.description.push_str(description);

        EXIT_SUCCESS
    } {
        EXIT_FAILURE
    }
}

/*-----------------------------------------------------------------------------------------------
 * ## Provider States
 */

ffi_fn! {
    /// Get a copy of the provider state at the given index from this message.
    /// A pointer to the structure will be written to `out_provider_state`,
    /// only if no errors are encountered.
    ///
    /// The returned structure must be deleted with `provider_state_delete`.
    ///
    /// Since it is a copy, the returned structure may safely outlive
    /// the `Message`.
    ///
    /// # Errors
    ///
    /// On failure, this function will return a variant other than Success.
    ///
    /// This function may fail if the index requested is out of bounds,
    /// or if any of the Rust strings contain embedded null ('\0') bytes.
    fn message_get_provider_state(message: *const Message, index: c_uint) -> *const ProviderState {
        let message = as_ref!(message);
        let index = index as usize;

        // Get a raw pointer directly, rather than boxing it, as its owned by the `Message`
        // and will be cleaned up when the `Message` is cleaned up.
        let provider_state = message
            .provider_states
            .get(index)
            .ok_or(anyhow!("index is out of bounds"))?;

        provider_state as *const ProviderState
    } {
        ptr::null_to::<ProviderState>()
    }
}

ffi_fn! {
    /// Get an iterator over provider states.
    fn message_get_provider_state_iter(message: *mut Message) -> *mut ProviderStateIterator {
        let message = as_mut!(message);
        let iter = ProviderStateIterator { current: 0, message };
        ptr::raw_to(iter)
    } {
        ptr::null_mut_to::<ProviderStateIterator>()
    }
}

ffi_fn! {
    /// Get the next value from the iterator.
    fn provider_state_iter_next(iter: *mut ProviderStateIterator) -> *mut ProviderState {
        let iter = as_mut!(iter);
        let message = as_mut!(iter.message);
        let index = iter.next();
        let provider_state = message
            .provider_states
            .get_mut(index)
            .ok_or(anyhow::anyhow!("iter past the end of provider states"))?;
       provider_state as *mut ProviderState
    } {
        ptr::null_mut_to::<ProviderState>()
    }
}

ffi_fn! {
    /// Delete the iterator.
    fn provider_state_iter_delete(iter: *mut ProviderStateIterator) {
        ptr::drop_raw(iter);
    }
}

/// Iterator over individual provider states.
#[allow(missing_copy_implementations)]
#[allow(missing_debug_implementations)]
pub struct ProviderStateIterator {
    current: usize,
    message: *mut Message,
}

impl ProviderStateIterator {
    fn next(&mut self) -> usize {
        let idx = self.current;
        self.current += 1;
        idx
    }
}

/*-----------------------------------------------------------------------------------------------
 * ## Metadata
 */

ffi_fn! {
    /// Get a copy of the metadata value indexed by `key`.
    /// The returned string must be deleted with `string_delete`.
    ///
    /// Since it is a copy, the returned string may safely outlive
    /// the `Message`.
    ///
    /// The returned pointer will be NULL if the metadata does not contain
    /// the given key, or if an error occurred.
    ///
    /// # Errors
    ///
    /// On failure, this function will return a NULL pointer.
    ///
    /// This function may fail if the provided `key` string contains
    /// invalid UTF-8, or if the Rust string contains embedded null ('\0')
    /// bytes.
    fn message_find_metadata(message: *const Message, key: *const c_char) -> *const c_char {
        let message = as_ref!(message);
        let key = safe_str!(key);
        let value = message.metadata.get(key).ok_or(anyhow::anyhow!("invalid metadata key"))?;
        let value_ptr = string::to_c(value)?;
        value_ptr as *const c_char
    } {
        ptr::null_to::<c_char>()
    }
}

ffi_fn! {
    /// Insert the (`key`, `value`) pair into this Message's
    /// `metadata` HashMap.
    /// This function returns an enum indicating the result;
    /// see the comments on HashMapInsertStatus for details.
    ///
    /// # Errors
    ///
    /// This function may fail if the provided `key` or `value` strings
    /// contain invalid UTF-8.
    fn message_insert_metadata(
        message: *mut Message,
        key: *const c_char,
        value: *const c_char
    ) -> c_int {
        let message = as_mut!(message);
        let key = safe_str!(key);
        let value = safe_str!(value);

        match message.metadata.insert(key.to_string(), value.to_string()) {
            None => HashMapInsertStatus::SuccessNew as c_int,
            Some(_) => HashMapInsertStatus::SuccessOverwrite as c_int,
        }
    } {
        HashMapInsertStatus::Error as c_int
    }
}

ffi_fn! {
    /// Get an iterator over the metadata of a message.
    ///
    /// This iterator carries a pointer to the message, and must
    /// not outlive the message.
    ///
    /// The message metadata also must not be modified during iteration. If it is,
    /// the old iterator must be deleted and a new iterator created.
    ///
    /// # Errors
    ///
    /// On failure, this function will return a NULL pointer.
    ///
    /// This function may fail if any of the Rust strings contain
    /// embedded null ('\0') bytes.
    fn message_get_metadata_iter(message: *mut Message) -> *mut MessageMetadataIterator {
        let message = as_mut!(message);

        let iter = MessageMetadataIterator {
            keys:  message.metadata.keys().cloned().collect(),
            current: 0,
            message: message as *const Message,
        };

        ptr::raw_to(iter)
    } {
        ptr::null_mut_to::<MessageMetadataIterator>()
    }
}

ffi_fn! {
    /// Get the next key and value out of the iterator, if possible
    fn message_metadata_iter_next(iter: *mut MessageMetadataIterator) -> *mut MessageMetadataPair {
        let iter = as_mut!(iter);
        let message = as_ref!(iter.message);
        let key = iter.next().ok_or(anyhow::anyhow!("iter past the end of metadata"))?;
        let (key, value) = message
            .metadata
            .get_key_value(key)
            .ok_or(anyhow::anyhow!("iter provided invalid metadata key"))?;
        let pair = MessageMetadataPair::new(key, value)?;
        ptr::raw_to(pair)
    } {
        ptr::null_mut_to::<MessageMetadataPair>()
    }
}

ffi_fn! {
    /// Free the metadata iterator when you're done using it.
    fn message_metadata_iter_delete(iter: *mut MessageMetadataIterator) {
        ptr::drop_raw(iter);
    }
}

ffi_fn! {
    /// Free a pair of key and value returned from `message_metadata_iter_next`.
    fn message_metadata_pair_delete(pair: *mut MessageMetadataPair) {
        ptr::drop_raw(pair);
    }
}

/// An iterator that enables FFI iteration over metadata by putting all the keys on the heap
/// and tracking which one we're currently at.
///
/// This assumes no mutation of the underlying metadata happens while the iterator is live.
#[derive(Debug)]
pub struct MessageMetadataIterator {
    /// The metadata keys
    keys: Vec<String>,
    /// The current key
    current: usize,
    /// Pointer to the message.
    message: *const Message,
}

impl MessageMetadataIterator {
    fn next(&mut self) -> Option<&String> {
        let idx = self.current;
        self.current += 1;
        self.keys.get(idx)
    }
}

/// A single key-value pair exported to the C-side.
#[derive(Debug)]
#[repr(C)]
#[allow(missing_copy_implementations)]
pub struct MessageMetadataPair {
    /// The metadata key.
    key: *const c_char,
    /// The metadata value.
    value: *const c_char,
}

impl MessageMetadataPair {
    fn new(
        key: &str,
        value: &str,
    ) -> anyhow::Result<MessageMetadataPair> {
        Ok(MessageMetadataPair {
            key: string::to_c(key)? as *const c_char,
            value: string::to_c(value)? as *const c_char,
        })
    }
}

// Ensure that the owned strings are freed when the pair is dropped.
//
// Notice that we're casting from a `*const c_char` to a `*mut c_char`.
// This may seem wrong, but is safe so long as it doesn't violate Rust's
// guarantees around immutable references, which this doesn't. In this case,
// the underlying data came from `CString::into_raw` which takes ownership
// of the `CString` and hands it off via a `*mut pointer`. We cast that pointer
// back to `*const` to limit the C-side from doing any shenanigans, since the
// pointed-to values live inside of the `Message` metadata `HashMap`, but
// cast back to `*mut` here so we can free the memory.
//
// The discussion here helps explain: https://github.com/rust-lang/rust-clippy/issues/4774
impl Drop for MessageMetadataPair {
    fn drop(&mut self) {
        string::string_delete(self.key as *mut c_char);
        string::string_delete(self.value as *mut c_char);
    }
}

/*===============================================================================================
 * # Status Types
 *---------------------------------------------------------------------------------------------*/

/// Result from an attempt to insert into a HashMap
enum HashMapInsertStatus {
    /// The value was inserted, and the key was unset
    SuccessNew = 0,
    /// The value was inserted, and the key was previously set
    SuccessOverwrite = -1,
    /// An error occured, and the value was not inserted
    Error = -2,
}
<|endoftext|>


<commit_before>extern crate clap;

use std::env;
use std::ffi::OsStr;

use clap::{App, Arg};

#[test]
fn env() {
    env::set_var("CLP_TEST_ENV", "env");

    let r = App::new("df")
        .arg(Arg::from_usage("[arg] 'some opt'").env("CLP_TEST_ENV"))
        .get_matches_from_safe(vec![""]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 0);
    assert_eq!(m.value_of("arg").unwrap(), "env");
}

#[test]
fn env_os() {
    env::set_var("CLP_TEST_ENV", "env");

    let r = App::new("df")
        .arg(
            Arg::from_usage("[arg] 'some opt'").env_os(OsStr::new("CLP_TEST_ENV")),
        )
        .get_matches_from_safe(vec![""]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 0);
    assert_eq!(m.value_of("arg").unwrap(), "env");
}

#[test]
fn no_env() {
    // All the other tests use the presence of the Environment variable...
    // we need another variable just in case one of the others is running at the same time...
    env::remove_var("CLP_TEST_ENV_NONE");

    let r = App::new("df")
        .arg(Arg::from_usage("[arg] 'some opt'").env("CLP_TEST_ENV_NONE"))
        .get_matches_from_safe(vec![""]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(!m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 0);
    assert_eq!(m.value_of("arg"), None);
}

#[test]
fn with_default() {
    env::set_var("CLP_TEST_ENV", "env");

    let r = App::new("df")
        .arg(
            Arg::from_usage("[arg] 'some opt'")
                .env("CLP_TEST_ENV")
                .default_value("default"),
        )
        .get_matches_from_safe(vec![""]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 0);
    assert_eq!(m.value_of("arg").unwrap(), "env");
}

#[test]
fn opt_user_override() {
    env::set_var("CLP_TEST_ENV", "env");

    let r = App::new("df")
        .arg(
            Arg::from_usage("--arg [FILE] 'some arg'").env("CLP_TEST_ENV"),
        )
        .get_matches_from_safe(vec!["", "--arg", "opt"]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 1);
    assert_eq!(m.value_of("arg").unwrap(), "opt");
}

#[test]
fn positionals() {
    env::set_var("CLP_TEST_ENV", "env");

    let r = App::new("df")
        .arg(Arg::from_usage("[arg] 'some opt'").env("CLP_TEST_ENV"))
        .get_matches_from_safe(vec![""]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 0);
    assert_eq!(m.value_of("arg").unwrap(), "env");
}

#[test]
fn positionals_user_override() {
    env::set_var("CLP_TEST_ENV", "env");

    let r = App::new("df")
        .arg(Arg::from_usage("[arg] 'some opt'").env("CLP_TEST_ENV"))
        .get_matches_from_safe(vec!["", "opt"]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 1);
    assert_eq!(m.value_of("arg").unwrap(), "opt");
}

#[test]
fn multiple_one() {
    env::set_var("CLP_TEST_ENV", "env");

    let r = App::new("df")
        .arg(
            Arg::from_usage("[arg] 'some opt'")
                .env("CLP_TEST_ENV")
                .use_delimiter(true)
                .multiple(true),
        )
        .get_matches_from_safe(vec![""]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 0);
    assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), vec!["env"]);
}

#[test]
fn multiple_three() {
    env::set_var("CLP_TEST_ENV_MULTI1", "env1,env2,env3");

    let r = App::new("df")
        .arg(
            Arg::from_usage("[arg] 'some opt'")
                .env("CLP_TEST_ENV_MULTI1")
                .use_delimiter(true)
                .multiple(true),
        )
        .get_matches_from_safe(vec![""]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 0);
    assert_eq!(
        m.values_of("arg").unwrap().collect::<Vec<_>>(),
        vec!["env1", "env2", "env3"]
    );
}

#[test]
fn multiple_no_delimiter() {
    env::set_var("CLP_TEST_ENV_MULTI2", "env1 env2 env3");

    let r = App::new("df")
        .arg(
            Arg::from_usage("[arg] 'some opt'")
                .env("CLP_TEST_ENV_MULTI2")
                .multiple(true),
        )
        .get_matches_from_safe(vec![""]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 0);
    assert_eq!(
        m.values_of("arg").unwrap().collect::<Vec<_>>(),
        vec!["env1 env2 env3"]
    );
}
<commit_msg>add validation tests<commit_after>extern crate clap;

use std::env;
use std::ffi::OsStr;

use clap::{App, Arg};

#[test]
fn env() {
    env::set_var("CLP_TEST_ENV", "env");

    let r = App::new("df")
        .arg(Arg::from_usage("[arg] 'some opt'").env("CLP_TEST_ENV"))
        .get_matches_from_safe(vec![""]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 0);
    assert_eq!(m.value_of("arg").unwrap(), "env");
}

#[test]
fn env_os() {
    env::set_var("CLP_TEST_ENV", "env");

    let r = App::new("df")
        .arg(
            Arg::from_usage("[arg] 'some opt'").env_os(OsStr::new("CLP_TEST_ENV")),
        )
        .get_matches_from_safe(vec![""]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 0);
    assert_eq!(m.value_of("arg").unwrap(), "env");
}

#[test]
fn no_env() {
    // All the other tests use the presence of the Environment variable...
    // we need another variable just in case one of the others is running at the same time...
    env::remove_var("CLP_TEST_ENV_NONE");

    let r = App::new("df")
        .arg(Arg::from_usage("[arg] 'some opt'").env("CLP_TEST_ENV_NONE"))
        .get_matches_from_safe(vec![""]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(!m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 0);
    assert_eq!(m.value_of("arg"), None);
}

#[test]
fn with_default() {
    env::set_var("CLP_TEST_ENV", "env");

    let r = App::new("df")
        .arg(
            Arg::from_usage("[arg] 'some opt'")
                .env("CLP_TEST_ENV")
                .default_value("default"),
        )
        .get_matches_from_safe(vec![""]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 0);
    assert_eq!(m.value_of("arg").unwrap(), "env");
}

#[test]
fn opt_user_override() {
    env::set_var("CLP_TEST_ENV", "env");

    let r = App::new("df")
        .arg(
            Arg::from_usage("--arg [FILE] 'some arg'").env("CLP_TEST_ENV"),
        )
        .get_matches_from_safe(vec!["", "--arg", "opt"]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 1);
    assert_eq!(m.value_of("arg").unwrap(), "opt");
}

#[test]
fn positionals() {
    env::set_var("CLP_TEST_ENV", "env");

    let r = App::new("df")
        .arg(Arg::from_usage("[arg] 'some opt'").env("CLP_TEST_ENV"))
        .get_matches_from_safe(vec![""]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 0);
    assert_eq!(m.value_of("arg").unwrap(), "env");
}

#[test]
fn positionals_user_override() {
    env::set_var("CLP_TEST_ENV", "env");

    let r = App::new("df")
        .arg(Arg::from_usage("[arg] 'some opt'").env("CLP_TEST_ENV"))
        .get_matches_from_safe(vec!["", "opt"]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 1);
    assert_eq!(m.value_of("arg").unwrap(), "opt");
}

#[test]
fn multiple_one() {
    env::set_var("CLP_TEST_ENV", "env");

    let r = App::new("df")
        .arg(
            Arg::from_usage("[arg] 'some opt'")
                .env("CLP_TEST_ENV")
                .use_delimiter(true)
                .multiple(true),
        )
        .get_matches_from_safe(vec![""]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 0);
    assert_eq!(m.values_of("arg").unwrap().collect::<Vec<_>>(), vec!["env"]);
}

#[test]
fn multiple_three() {
    env::set_var("CLP_TEST_ENV_MULTI1", "env1,env2,env3");

    let r = App::new("df")
        .arg(
            Arg::from_usage("[arg] 'some opt'")
                .env("CLP_TEST_ENV_MULTI1")
                .use_delimiter(true)
                .multiple(true),
        )
        .get_matches_from_safe(vec![""]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 0);
    assert_eq!(
        m.values_of("arg").unwrap().collect::<Vec<_>>(),
        vec!["env1", "env2", "env3"]
    );
}

#[test]
fn multiple_no_delimiter() {
    env::set_var("CLP_TEST_ENV_MULTI2", "env1 env2 env3");

    let r = App::new("df")
        .arg(
            Arg::from_usage("[arg] 'some opt'")
                .env("CLP_TEST_ENV_MULTI2")
                .multiple(true),
        )
        .get_matches_from_safe(vec![""]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 0);
    assert_eq!(
        m.values_of("arg").unwrap().collect::<Vec<_>>(),
        vec!["env1 env2 env3"]
    );
}

#[test]
fn possible_value() {
    env::set_var("CLP_TEST_ENV", "env");

    let r = App::new("df")
        .arg(
            Arg::from_usage("[arg] 'some opt'")
                .env("CLP_TEST_ENV")
                .possible_value("env"),
        )
        .get_matches_from_safe(vec![""]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 0);
    assert_eq!(m.value_of("arg").unwrap(), "env");
}

#[test]
fn not_possible_value() {
    env::set_var("CLP_TEST_ENV", "env");

    let r = App::new("df")
        .arg(
            Arg::from_usage("[arg] 'some opt'")
                .env("CLP_TEST_ENV")
                .possible_value("never"),
        )
        .get_matches_from_safe(vec![""]);

    assert!(r.is_err());
}

#[test]
fn validator() {
    env::set_var("CLP_TEST_ENV", "env");

    let r = App::new("df")
        .arg(
            Arg::from_usage("[arg] 'some opt'")
                .env("CLP_TEST_ENV")
                .validator(|s| if s == "env" {
                    Ok(())
                } else {
                    Err("not equal".to_string())
                }),
        )
        .get_matches_from_safe(vec![""]);

    assert!(r.is_ok());
    let m = r.unwrap();
    assert!(m.is_present("arg"));
    assert_eq!(m.occurrences_of("arg"), 0);
    assert_eq!(m.value_of("arg").unwrap(), "env");
}

#[test]
fn validator_invalid() {
    env::set_var("CLP_TEST_ENV", "env");

    let r = App::new("df")
        .arg(
            Arg::from_usage("[arg] 'some opt'")
                .env("CLP_TEST_ENV")
                .validator(|s| if s != "env" {
                    Ok(())
                } else {
                    Err("is equal".to_string())
                }),
        )
        .get_matches_from_safe(vec![""]);

    assert!(r.is_err());
}
<|endoftext|>