<commit_before>#![doc(html_logo_url = "https://raw.githubusercontent.com/clap-rs/clap/master/assets/clap.png")]
#![doc = include_str!("../README.md")]
#![warn(missing_docs, trivial_casts, unused_allocation, trivial_numeric_casts)]
#![forbid(unsafe_code)]
#![deny(missing_docs)]

mod render;

pub use roff;

use render::subcommand_heading;
use roff::{roman, Roff};
use std::io::Write;

/// Generate a manual page and write it out.
pub fn generate_manpage<'a>(app: clap::App<'a>, buf: &mut dyn Write) -> Result<(), std::io::Error> {
    let meta = Meta::from_clap("1", "", &app);
    let man = Man::new(meta, app);
    man.render(buf)
}

/// Metadata about a manual page.
pub struct Meta {
    title: String,
    section: String,
    date: String,
    source: String,
    manual: String,
}

impl Meta {
    /// Create metadata from a clap::App.
    pub fn from_clap(section: &str, manual: &str, app: &clap::App) -> Self {
        Self {
            title: app.get_name().to_string(),
            section: section.to_string(),
            date: "".to_string(), // FIXME
            source: format!(
                "{} {}",
                app.get_name(),
                app.get_version().unwrap_or_default()
            ),
            manual: manual.to_string(),
        }
    }

    // Turn metadata into arguments for a .TH macro.
    fn to_args(&self) -> Vec<&str> {
        vec![
            &self.title,
            &self.section,
            &self.date,
            &self.source,
            &self.manual,
        ]
    }
}

/// A manual page as constructed from a clap::App.
pub struct Man<'a> {
    meta: Meta,
    app: clap::App<'a>,
}

impl<'a> Man<'a> {
    /// Create a new manual page.
    pub fn new(meta: Meta, mut app: clap::App<'a>) -> Self {
        app._build_all();
        Self { meta, app }
    }

    /// Render a manual page into writer.
    pub fn render(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        roff.control("TH", self.meta.to_args());
        roff.control("SH", ["NAME"]);
        render::about(&mut roff, &self.app);
        roff.control("SH", ["SYNOPSIS"]);
        render::synopsis(&mut roff, &self.app);
        roff.control("SH", ["DESCRIPTION"]);
        render::description(&mut roff, &self.app);

        if app_has_arguments(&self.app) {
            roff.control("SH", ["OPTIONS"]);
            render::options(&mut roff, &self.app);
        }

        if app_has_subcommands(&self.app) {
            let heading = subcommand_heading(&self.app);
            roff.control("SH", [heading.as_str()]);
            render::subcommands(&mut roff, &self.app, &self.meta.section);
        }

        if self.app.get_after_long_help().is_some() || self.app.get_after_help().is_some() {
            roff.control("SH", ["EXTRA"]);
            render::after_help(&mut roff, &self.app);
        }

        if app_has_version(&self.app) {
            let version = roman(&render::version(&self.app));
            roff.control("SH", ["VERSION"]);
            roff.text([version]);
        }

        if self.app.get_author().is_some() {
            let author = roman(self.app.get_author().unwrap_or_default());
            roff.control("SH", ["AUTHORS"]);
            roff.text([author]);
        }
        roff.to_writer(w)
    }
}

// Does the application have a version?
fn app_has_version(app: &clap::App) -> bool {
    app.get_version()
        .or_else(|| app.get_long_version())
        .is_some()
}

// Does the application have any command line arguments?
fn app_has_arguments(app: &clap::App) -> bool {
    app.get_arguments()
        .any(|i| !i.is_set(clap::ArgSettings::Hidden))
}

// Does the application have any subcommands?
fn app_has_subcommands(app: &clap::App) -> bool {
    app.get_subcommands()
        .any(|i| !i.is_set(clap::AppSettings::Hidden))
}
<commit_msg>feat(man): Allow customizing man page<commit_after>#![doc(html_logo_url = "https://raw.githubusercontent.com/clap-rs/clap/master/assets/clap.png")]
#![doc = include_str!("../README.md")]
#![warn(missing_docs, trivial_casts, unused_allocation, trivial_numeric_casts)]
#![forbid(unsafe_code)]
#![deny(missing_docs)]

mod render;

pub use roff;

use render::subcommand_heading;
use roff::{roman, Roff};
use std::io::Write;

/// Generate a manual page and write it out.
pub fn generate_manpage(app: clap::App<'_>, buf: &mut dyn Write) -> Result<(), std::io::Error> {
    let meta = Meta::from_clap("1", "", &app);
    let man = Man::new(meta, app);
    man.render(buf)
}

/// Metadata about a manual page.
pub struct Meta {
    title: String,
    section: String,
    date: String,
    source: String,
    manual: String,
}

impl Meta {
    /// Create metadata from a clap::App.
    pub fn from_clap(section: &str, manual: &str, app: &clap::App) -> Self {
        Self {
            title: app.get_name().to_string(),
            section: section.to_string(),
            date: "".to_string(), // FIXME
            source: format!(
                "{} {}",
                app.get_name(),
                app.get_version().unwrap_or_default()
            ),
            manual: manual.to_string(),
        }
    }

    // Turn metadata into arguments for a .TH macro.
    fn to_args(&self) -> Vec<&str> {
        vec![
            &self.title,
            &self.section,
            &self.date,
            &self.source,
            &self.manual,
        ]
    }
}

/// A manual page as constructed from a clap::App.
pub struct Man<'a> {
    meta: Meta,
    app: clap::App<'a>,
}

impl<'a> Man<'a> {
    /// Create a new manual page.
    pub fn new(meta: Meta, mut app: clap::App<'a>) -> Self {
        app._build_all();
        Self { meta, app }
    }

    /// Render a manual page into writer.
    pub fn render(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        roff.control("TH", self.meta.to_args());
        self._render_name_section(&mut roff);
        self._render_synopsis_section(&mut roff);
        self._render_description_section(&mut roff);

        if app_has_arguments(&self.app) {
            self._render_options_section(&mut roff);
        }

        if app_has_subcommands(&self.app) {
            self._render_subcommands_section(&mut roff);
        }

        if self.app.get_after_long_help().is_some() || self.app.get_after_help().is_some() {
            self._render_extra_section(&mut roff);
        }

        if app_has_version(&self.app) {
            self._render_version_section(&mut roff);
        }

        if self.app.get_author().is_some() {
            self._render_authors_section(&mut roff);
        }

        roff.to_writer(w)
    }

    /// Render the NAME section into the writer.
    pub fn render_name_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_name_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_name_section(&self, roff: &mut Roff) {
        roff.control("SH", ["NAME"]);
        render::about(roff, &self.app);
    }

    /// Render the SYNOPSIS section into the writer.
    pub fn render_synopsis_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_synopsis_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_synopsis_section(&self, roff: &mut Roff) {
        roff.control("SH", ["SYNOPSIS"]);
        render::synopsis(roff, &self.app);
    }

    /// Render the DESCRIPTION section into the writer.
    pub fn render_description_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_description_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_description_section(&self, roff: &mut Roff) {
        roff.control("SH", ["DESCRIPTION"]);
        render::description(roff, &self.app);
    }

    /// Render the OPTIONS section into the writer.
    pub fn render_options_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_options_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_options_section(&self, roff: &mut Roff) {
        roff.control("SH", ["OPTIONS"]);
        render::options(roff, &self.app);
    }

    /// Render the SUBCOMMANDS section into the writer.
    pub fn render_subcommands_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_subcommands_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_subcommands_section(&self, roff: &mut Roff) {
        let heading = subcommand_heading(&self.app);
        roff.control("SH", [heading.as_str()]);
        render::subcommands(roff, &self.app, &self.meta.section);
    }

    /// Render the EXTRA section into the writer.
    pub fn render_extra_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_extra_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_extra_section(&self, roff: &mut Roff) {
        roff.control("SH", ["EXTRA"]);
        render::after_help(roff, &self.app);
    }

    /// Render the VERSION section into the writer.
    pub fn render_version_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_version_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_version_section(&self, roff: &mut Roff) {
        let version = roman(&render::version(&self.app));
        roff.control("SH", ["VERSION"]);
        roff.text([version]);
    }

    /// Render the AUTHORS section into the writer.
    pub fn render_authors_section(&self, w: &mut dyn Write) -> Result<(), std::io::Error> {
        let mut roff = Roff::default();
        self._render_authors_section(&mut roff);
        roff.to_writer(w)
    }

    fn _render_authors_section(&self, roff: &mut Roff) {
        let author = roman(self.app.get_author().unwrap_or_default());
        roff.control("SH", ["AUTHORS"]);
        roff.text([author]);
    }
}

// Does the application have a version?
fn app_has_version(app: &clap::App) -> bool {
    app.get_version()
        .or_else(|| app.get_long_version())
        .is_some()
}

// Does the application have any command line arguments?
fn app_has_arguments(app: &clap::App) -> bool {
    app.get_arguments()
        .any(|i| !i.is_set(clap::ArgSettings::Hidden))
}

// Does the application have any subcommands?
fn app_has_subcommands(app: &clap::App) -> bool {
    app.get_subcommands()
        .any(|i| !i.is_set(clap::AppSettings::Hidden))
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! A linked-list implementation using `RawLink`s.
use super::rawlink::RawLink;

use core::marker::PhantomData;
use core::ptr::Unique;
#[cfg(test)] mod test;

pub unsafe trait OwnedRef<T> {
    unsafe fn from_raw(ptr: *mut T) -> Self;
    unsafe fn take(self);
    fn get(&self) -> &T;
    fn get_mut(&mut self) -> &mut T;
}

pub trait Node: Sized {
    fn next(&self) -> &RawLink<Self>;
    fn prev(&self) -> &RawLink<Self>;

    fn next_mut(&mut self) -> &mut RawLink<Self>;
    fn prev_mut(&mut self) -> &mut RawLink<Self>;
}

pub struct List<T, N>
where T: OwnedRef<N>
    , N: Node {
    head: RawLink<N>
  , tail: RawLink<N>
  , _ty_marker: PhantomData<T>
  , length: usize
 }

 // impl<T> Node for List<T>
 // where T: OwnedRef
 //     , T: Node {
 //
 //    fn next(&self) -> &RawLink<Self> { &self.head }
 //    fn prev(&self) -> &RawLink<Self> { &self.tail }
 //
 //    fn next_mut(&mut self) -> &mut RawLink<Self> { self.head }
 //    fn prev_mut(&mut self) -> &mut RawLink<Self> { self.tail }
 // }
impl<T, N> List<T, N>
where T: OwnedRef<N>
    , N: Node {

    pub const fn new() -> Self {
        List { head: RawLink::none()
             , tail: RawLink::none()
             , _ty_marker: PhantomData
             , length: 0 }
    }

    #[inline] pub fn len(&self) -> usize {
        self.length
    }

    #[inline] pub fn front(&self) -> Option<&N> {
        unsafe { self.head.resolve() }
    }

    #[inline] pub fn back(&self) -> Option<&N> {
        unsafe { self.tail.resolve() }
    }

    #[inline] pub fn front_mut(&mut self) -> Option<&mut N> {
        unsafe { self.head.resolve_mut() }
    }

    #[inline] pub fn back_mut(&mut self) -> Option<&mut N> {
        unsafe { self.tail.resolve_mut() }
    }

    #[inline] pub fn is_empty(&self) -> bool {
        self.head.is_none()
    }

    pub fn push_front(&mut self, mut item: T) {
        unsafe {
            match self.head.resolve_mut() {
                None => {
                    // If this node's head is empty, set the pushed item's
                    // links to None, and make this node's tail point to the
                    // pushed item
                    *item.get_mut().next_mut() = RawLink::none();
                    *item.get_mut().prev_mut() = RawLink::none();
                    self.tail = RawLink::some(item.get_mut());
                }
              , Some(head) => {
                    // If this node is not empty, set the pushed item's tail
                    // to point at the head node, and make the head node's tail
                    // point to the pushed item
                    *item.get_mut().next_mut() = RawLink::some(head);
                    *item.get_mut().prev_mut() = RawLink::none();
                    *head.prev_mut() = RawLink::some(item.get_mut());
                }
            }
            // then, set this node's head pointer to point to the pushed item
            self.head = RawLink::some(item.get_mut());
            item.take();
            self.length += 1;
        }
    }

    pub fn push_back(&mut self, mut item: T) {
        unsafe {
            match self.tail.resolve_mut() {
                None => {
                    // If this node's tail is empty, set the pushed item's
                    // links to  None, and make this node's head point to the
                    // pushed item
                    *item.get_mut().next_mut() = RawLink::none();
                    *item.get_mut().prev_mut() = RawLink::none();
                    self.head = RawLink::some(item.get_mut());
                }
              , Some(tail) => {
                    // If this node is not empty, set the pushed item's head
                    // to point at the tail node, and make the tail node's head
                    // point to the pushed item
                    *item.get_mut().next_mut() = RawLink::none();
                    *item.get_mut().prev_mut() = RawLink::some(tail);
                    *tail.next_mut() = RawLink::some(item.get_mut());
                }
            }
            // then, set this node's head pointer to point to the pushed item
            self.tail = RawLink::some(item.get_mut());
            item.take();
            self.length += 1;
        }
    }

    pub fn pop_front(&mut self) -> Option<T> {
        unsafe {
            self.head.take().resolve_mut()
                .map(|head| {
                    // mem::swap( &mut self.head
                    //          , head.next_mut().resolve_mut()
                    //                .map(|next| next.prev_mut())
                    //                .unwrap_or(&mut RawLink::none()) );
                    match head.next_mut().resolve_mut() {
                        None => self.tail = RawLink::none()
                      , Some(next) => {
                            *next.prev_mut() = RawLink::none();
                            self.head = RawLink::some(next);
                        }
                    }
                    self.length -= 1;
                    T::from_raw(head)
                })
        }
    }

    pub fn pop_back(&mut self) -> Option<T> {
        unsafe {
            self.tail.take().resolve_mut()
                .map(|tail| {
                    match tail.prev_mut().resolve_mut() {
                        None => self.head = RawLink::none()
                      , Some(prev) => {
                            *prev.next_mut() = RawLink::none();
                            self.tail = RawLink::some(prev);
                        }
                    }
                    self.length -= 1;
                    T::from_raw(tail)
                })
        }
    }

    pub fn peek_front(&self) -> Option<&N> {
        unsafe { self.tail.resolve() }
    }

    pub fn cursor<'a>(&'a mut self) -> ListCursor<'a, T, N> {
        ListCursor { list: self
                   , current: RawLink::none() }
    }
}

pub struct ListCursor<'a, T, N>
where T: OwnedRef<N>
    , T: 'a
    , N: Node
    , N: 'a {
        list: &'a mut List<T, N>
      , current: RawLink<N>
}

impl<'a, T, N> ListCursor<'a, T, N>
where T: OwnedRef<N>
    , T: 'a
    , N: Node
    , N: 'a {

    pub fn next(&mut self) -> Option<&mut N> {
        unsafe {
            match self.current.take().resolve_mut() {
                None => self.list.head.resolve_mut()
                            .and_then(|head| {
                                self.current = RawLink::some(head);
                                self.current.resolve_mut()
                            })
              , Some(thing) => {
                    self.current = match thing.next_mut().resolve_mut() {
                        None => RawLink::none()
                      , Some(other_thing) => RawLink::some(other_thing)
                    };
                    self.current.resolve_mut()
                }
            }
        }
    }

    pub fn peek_next(&mut self) -> Option<&mut N> {
        unsafe {
            self.current.resolve_mut()
                .map_or( self.list.front_mut()
                       , |next| next.next_mut().resolve_mut())
        }
    }

    pub fn remove(&mut self) -> Option<T> {
        unsafe {
            match self.current.resolve_mut() {
                None    => self.list.pop_front()
              , Some(c) =>
                    c.next_mut().take().resolve_mut()
                     .map(|p| {
                        match p.next_mut().resolve_mut() {
                            None => self.list.tail = RawLink::some(c)
                          , Some(n) => {
                                *n.prev_mut() = RawLink::some(c);
                                *c.next_mut() = RawLink::some(n);
                            }
                        }
                        T::from_raw(p)
                    })
            }
        }
    }

}

// impl<'a, T, N> Iterator for ListCursor<'a, T, N>
// where T: OwnedRef<N>
//     , T: 'a
//     , N: Node
//     , N: 'a {
//     type Item = &'a mut N;
//
//     fn next<'b: 'a>(&'b mut self) -> Option<&'a mut N> {
//         self.next()
//     }
// }

//
// unsafe impl<T> OwnedRef for Unique<T> where T: Node {
//
//     #[inline]
//     fn take(self) {}
//
//     unsafe fn from_raw(ptr: *mut T) -> Self {
//         Unique::new(ptr)
//     }
// }
//
// unsafe impl<'a, T> OwnedRef<T> for &'a mut T {
//     #
//     #[inline] unsafe fn from_raw(raw: *mut T) -> &'a mut T {
//         &mut *raw
//     }
//
//     #[inline] unsafe fn take(self) {
//         forget(self);
//     }
// }
//

unsafe impl<T> OwnedRef<T> for Unique<T>  {
    #[inline]
    fn get(&self) -> &T { unsafe { self.get() } }

    #[inline]
    fn get_mut(&mut self) -> &mut T { unsafe { self.get_mut() } }

    #[inline]
    unsafe fn take(self) {}

    unsafe fn from_raw(ptr: *mut T) -> Self {
        Unique::new(ptr)
    }
}

#[cfg(any(test, feature = "use-std"))]
unsafe impl<T> OwnedRef<T> for ::std::boxed::Box<T> {

    fn get(&self) -> &T { &**self }
    fn get_mut(&mut self) -> &mut T { &mut **self }

    #[inline] unsafe fn take(self) {
        ::std::boxed::Box::into_raw(self);
    }

    unsafe fn from_raw(ptr: *mut T) -> Self {
        ::std::boxed::Box::from_raw(ptr)
    }
}
<commit_msg>[intrusive] ListCursor.peek_next() no longer borrows as mut<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! A linked-list implementation using `RawLink`s.
use super::rawlink::RawLink;

use core::marker::PhantomData;
use core::ptr::Unique;
#[cfg(test)] mod test;

pub unsafe trait OwnedRef<T> {
    unsafe fn from_raw(ptr: *mut T) -> Self;
    unsafe fn take(self);
    fn get(&self) -> &T;
    fn get_mut(&mut self) -> &mut T;
}

pub trait Node: Sized {
    fn next(&self) -> &RawLink<Self>;
    fn prev(&self) -> &RawLink<Self>;

    fn next_mut(&mut self) -> &mut RawLink<Self>;
    fn prev_mut(&mut self) -> &mut RawLink<Self>;
}

pub struct List<T, N>
where T: OwnedRef<N>
    , N: Node {
    head: RawLink<N>
  , tail: RawLink<N>
  , _ty_marker: PhantomData<T>
  , length: usize
 }

 // impl<T> Node for List<T>
 // where T: OwnedRef
 //     , T: Node {
 //
 //    fn next(&self) -> &RawLink<Self> { &self.head }
 //    fn prev(&self) -> &RawLink<Self> { &self.tail }
 //
 //    fn next_mut(&mut self) -> &mut RawLink<Self> { self.head }
 //    fn prev_mut(&mut self) -> &mut RawLink<Self> { self.tail }
 // }
impl<T, N> List<T, N>
where T: OwnedRef<N>
    , N: Node {

    pub const fn new() -> Self {
        List { head: RawLink::none()
             , tail: RawLink::none()
             , _ty_marker: PhantomData
             , length: 0 }
    }

    #[inline] pub fn len(&self) -> usize {
        self.length
    }

    #[inline] pub fn front(&self) -> Option<&N> {
        unsafe { self.head.resolve() }
    }

    #[inline] pub fn back(&self) -> Option<&N> {
        unsafe { self.tail.resolve() }
    }

    #[inline] pub fn front_mut(&mut self) -> Option<&mut N> {
        unsafe { self.head.resolve_mut() }
    }

    #[inline] pub fn back_mut(&mut self) -> Option<&mut N> {
        unsafe { self.tail.resolve_mut() }
    }

    #[inline] pub fn is_empty(&self) -> bool {
        self.head.is_none()
    }

    pub fn push_front(&mut self, mut item: T) {
        unsafe {
            match self.head.resolve_mut() {
                None => {
                    // If this node's head is empty, set the pushed item's
                    // links to None, and make this node's tail point to the
                    // pushed item
                    *item.get_mut().next_mut() = RawLink::none();
                    *item.get_mut().prev_mut() = RawLink::none();
                    self.tail = RawLink::some(item.get_mut());
                }
              , Some(head) => {
                    // If this node is not empty, set the pushed item's tail
                    // to point at the head node, and make the head node's tail
                    // point to the pushed item
                    *item.get_mut().next_mut() = RawLink::some(head);
                    *item.get_mut().prev_mut() = RawLink::none();
                    *head.prev_mut() = RawLink::some(item.get_mut());
                }
            }
            // then, set this node's head pointer to point to the pushed item
            self.head = RawLink::some(item.get_mut());
            item.take();
            self.length += 1;
        }
    }

    pub fn push_back(&mut self, mut item: T) {
        unsafe {
            match self.tail.resolve_mut() {
                None => {
                    // If this node's tail is empty, set the pushed item's
                    // links to  None, and make this node's head point to the
                    // pushed item
                    *item.get_mut().next_mut() = RawLink::none();
                    *item.get_mut().prev_mut() = RawLink::none();
                    self.head = RawLink::some(item.get_mut());
                }
              , Some(tail) => {
                    // If this node is not empty, set the pushed item's head
                    // to point at the tail node, and make the tail node's head
                    // point to the pushed item
                    *item.get_mut().next_mut() = RawLink::none();
                    *item.get_mut().prev_mut() = RawLink::some(tail);
                    *tail.next_mut() = RawLink::some(item.get_mut());
                }
            }
            // then, set this node's head pointer to point to the pushed item
            self.tail = RawLink::some(item.get_mut());
            item.take();
            self.length += 1;
        }
    }

    pub fn pop_front(&mut self) -> Option<T> {
        unsafe {
            self.head.take().resolve_mut()
                .map(|head| {
                    // mem::swap( &mut self.head
                    //          , head.next_mut().resolve_mut()
                    //                .map(|next| next.prev_mut())
                    //                .unwrap_or(&mut RawLink::none()) );
                    match head.next_mut().resolve_mut() {
                        None => self.tail = RawLink::none()
                      , Some(next) => {
                            *next.prev_mut() = RawLink::none();
                            self.head = RawLink::some(next);
                        }
                    }
                    self.length -= 1;
                    T::from_raw(head)
                })
        }
    }

    pub fn pop_back(&mut self) -> Option<T> {
        unsafe {
            self.tail.take().resolve_mut()
                .map(|tail| {
                    match tail.prev_mut().resolve_mut() {
                        None => self.head = RawLink::none()
                      , Some(prev) => {
                            *prev.next_mut() = RawLink::none();
                            self.tail = RawLink::some(prev);
                        }
                    }
                    self.length -= 1;
                    T::from_raw(tail)
                })
        }
    }

    pub fn peek_front(&self) -> Option<&N> {
        unsafe { self.tail.resolve() }
    }

    pub fn cursor<'a>(&'a mut self) -> ListCursor<'a, T, N> {
        ListCursor { list: self
                   , current: RawLink::none() }
    }
}

pub struct ListCursor<'a, T, N>
where T: OwnedRef<N>
    , T: 'a
    , N: Node
    , N: 'a {
        list: &'a mut List<T, N>
      , current: RawLink<N>
}

impl<'a, T, N> ListCursor<'a, T, N>
where T: OwnedRef<N>
    , T: 'a
    , N: Node
    , N: 'a {

    pub fn next(&mut self) -> Option<&mut N> {
        unsafe {
            match self.current.take().resolve_mut() {
                None => self.list.head.resolve_mut()
                            .and_then(|head| {
                                self.current = RawLink::some(head);
                                self.current.resolve_mut()
                            })
              , Some(thing) => {
                    self.current = match thing.next_mut().resolve_mut() {
                        None => RawLink::none()
                      , Some(other_thing) => RawLink::some(other_thing)
                    };
                    self.current.resolve_mut()
                }
            }
        }
    }

    pub fn peek_next(&self) -> Option<&N> {
        unsafe {
            self.current.resolve()
                .map_or( self.list.front()
                       , |next| next.next().resolve())
        }
    }

    pub fn remove(&mut self) -> Option<T> {
        unsafe {
            match self.current.resolve_mut() {
                None    => self.list.pop_front()
              , Some(c) =>
                    c.next_mut().take().resolve_mut()
                     .map(|p| {
                        match p.next_mut().resolve_mut() {
                            None => self.list.tail = RawLink::some(c)
                          , Some(n) => {
                                *n.prev_mut() = RawLink::some(c);
                                *c.next_mut() = RawLink::some(n);
                            }
                        }
                        T::from_raw(p)
                    })
            }
        }
    }

}

// impl<'a, T, N> Iterator for ListCursor<'a, T, N>
// where T: OwnedRef<N>
//     , T: 'a
//     , N: Node
//     , N: 'a {
//     type Item = &'a mut N;
//
//     fn next<'b: 'a>(&'b mut self) -> Option<&'a mut N> {
//         self.next()
//     }
// }

//
// unsafe impl<T> OwnedRef for Unique<T> where T: Node {
//
//     #[inline]
//     fn take(self) {}
//
//     unsafe fn from_raw(ptr: *mut T) -> Self {
//         Unique::new(ptr)
//     }
// }
//
// unsafe impl<'a, T> OwnedRef<T> for &'a mut T {
//     #
//     #[inline] unsafe fn from_raw(raw: *mut T) -> &'a mut T {
//         &mut *raw
//     }
//
//     #[inline] unsafe fn take(self) {
//         forget(self);
//     }
// }
//

unsafe impl<T> OwnedRef<T> for Unique<T>  {
    #[inline]
    fn get(&self) -> &T { unsafe { self.get() } }

    #[inline]
    fn get_mut(&mut self) -> &mut T { unsafe { self.get_mut() } }

    #[inline]
    unsafe fn take(self) {}

    unsafe fn from_raw(ptr: *mut T) -> Self {
        Unique::new(ptr)
    }
}

#[cfg(any(test, feature = "use-std"))]
unsafe impl<T> OwnedRef<T> for ::std::boxed::Box<T> {

    fn get(&self) -> &T { &**self }
    fn get_mut(&mut self) -> &mut T { &mut **self }

    #[inline] unsafe fn take(self) {
        ::std::boxed::Box::into_raw(self);
    }

    unsafe fn from_raw(ptr: *mut T) -> Self {
        ::std::boxed::Box::from_raw(ptr)
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

use quote::Tokens;
use syn::{Attribute, Body, Ident, MacroInput, Path, VariantData};
use syn::Body::{Enum, Struct};
use syn::MetaItem::{List, Word};
use syn::Ty;

use attributes::to_metadata_impl;
use string::{snake_to_camel, to_dash_name};

/// Expand the required trais for the derive Setting attribute.
pub fn expand_setting_enum(mut ast: MacroInput) -> Tokens {
    let name = ast.ident.clone();
    let mut default = None;

    let mut variant_names = vec![];
    if let Enum(ref mut variants) = ast.body {
        for variant in variants {
            variant_names.push(variant.ident.clone());
            if !variant.attrs.is_empty() {
                for attribute in &variant.attrs {
                    if let &Attribute { value: Word(ref ident), .. } = attribute {
                        if ident == "default" {
                            default = Some(variant.ident.clone());
                        }
                    }
                }
                variant.attrs.clear();
            }
        }
    }
    let choice_names: Vec<_> = variant_names.iter()
        .map(|name| to_dash_name(&name.to_string()))
        .collect();
    let choice_names1 = &choice_names;
    let choice_names2 = &choice_names;

    let qualified_names = variant_names.iter()
        .map(|variant_name| quote! {
            #name::#variant_name
        });

    let from_str_fn = quote! {
        fn from_str(string: &str) -> Result<Self, Self::Err> {
            match string {
                #(#choice_names1 => Ok(#qualified_names),)*
                _ => Err(::mg_settings::error::SettingError::UnknownChoice {
                    actual: string.to_string(),
                    expected: vec![#(#choice_names2),*],
                }),
            }
        }
    };

    let default_impl =
        if let Some(ident) = default {
            quote! {
                impl Default for #name {
                    fn default() -> Self {
                        #name::#ident
                    }
                }
            }
        }
        else {
            quote! {
            }
        };

    let completion_values_impl = quote! {
        impl CompletionValues for #name {
            fn completion_values() -> Vec<String> {
                vec![#(#choice_names1.to_string()),*]
            }
        }
    };

    quote! {
        #[derive(Clone)]
        #ast

        #default_impl

        #completion_values_impl

        impl ::std::str::FromStr for #name {
            type Err = ::mg_settings::error::SettingError;

            #from_str_fn
        }
    }
}

/// Expand the required traits for the derive Settings attribute.
pub fn expand_settings_enum(mut ast: MacroInput) -> Tokens {
    let name = &ast.ident;
    let completion_fn = to_setting_completion_fn(name, &ast.body);
    let variant_name = Ident::new(format!("{}Variant", name));
    let variant_enum = to_enums(&ast.ident, &variant_name, &ast.body);
    let settings_impl = to_settings_impl(name, &variant_name, &ast.body);
    let (metadata_impl, _) = to_metadata_impl(name, &mut ast.body);
    quote! {
        #[derive(Default)]
        #ast

        #variant_enum

        #settings_impl

        #metadata_impl

        #completion_fn
    }
}

/// Check if a type is a custom type (including enum).
fn is_custom_type(ident: &Ident) -> bool {
    match ident.to_string().as_ref() {
        "bool" | "f64" | "i64" | "String" => false,
        _ => true,
    }
}

/// Create the variant enums for getters and setters.
fn to_enums(name: &Ident, variant_name: &Ident, settings_struct: &Body) -> Tokens {
    if let &Struct(VariantData::Struct(ref strct)) = settings_struct {
        let mut field_names = vec![];
        let mut names = vec![];
        let mut types = vec![];
        for field in strct {
            if let Some(ref ident) = field.ident {
                field_names.push(ident);
                let ident = Ident::new(snake_to_camel(&ident.to_string()));
                names.push(ident);
                types.push(field.ty.clone());
            }
        }
        let names1 = &names;
        quote! {
            #[derive(Clone)]
            pub enum #variant_name {
                #(#names1(#types)),*
            }

            impl #name {
                pub fn new() -> #name {
                    #name::default()
                }
            }
        }
    }
    else {
        panic!("Not a struct");
    }
}

/// Create the impl Settings.
fn to_settings_impl(name: &Ident, variant_name: &Ident, settings_struct: &Body) -> Tokens {
    if let &Struct(VariantData::Struct(ref strct)) = settings_struct {
        let mut names = vec![];
        let mut capitalized_names = vec![];
        let mut original_types = vec![];
        let mut types = vec![];
        for field in strct {
            if let Some(ref ident) = field.ident {
                let ident_string = ident.to_string();
                let ident = Ident::new(ident_string.clone());
                names.push(ident);
                let ident = Ident::new(snake_to_camel(&ident_string));
                capitalized_names.push(
                    quote! {
                        #variant_name::#ident
                    });

                if let Ty::Path(_, Path { ref segments, .. }) = field.ty {
                    original_types.push(&segments[0].ident);
                    types.push(to_value_type(&segments[0].ident));
                }
            }
        }
        let string_names: Vec<_> = names.iter()
            .map(|ident| ident.to_string().replace("_", "-"))
            .collect();
        let string_names = &string_names;
        let capitalized_names = &capitalized_names;
        let names1 = &names;
        let variant_exprs = names.iter().zip(original_types.iter())
            .map(|(name, typ)|
                 if is_custom_type(typ) {
                     quote! {
                         ::std::str::FromStr::from_str(&#name)?
                     }
                 }
                 else {
                     quote! { #name }
                 }
            );
        let names2 = &names;
        let names3 = &names;
        let types1 = &types;
        let type_names = types.iter()
            .map(|ident| value_type_to_type(&ident));

        let to_variant_fn_variant = quote! {
            #(#string_names => {
                if let ::mg_settings::Value::#types1(#names1) = value {
                    Ok(#capitalized_names(#variant_exprs))
                }
                else {
                    Err(::mg_settings::error::SettingError::WrongType {
                        actual: value.to_type().to_string(),
                        expected: #type_names.to_string(),
                    })
                }
            },)*
        };

        let to_variant_fn = quote! {
            fn to_variant(name: &str, value: ::mg_settings::Value) -> Result<Self::Variant, ::mg_settings::error::SettingError> {
                match name {
                    #to_variant_fn_variant
                    _ => Err(::mg_settings::error::SettingError::UnknownSetting(name.to_string())),
                }
            }
        };

        quote! {
            impl ::mg_settings::settings::Settings for #name {
                type Variant = #variant_name;

                #to_variant_fn

                fn set_value(&mut self, value: Self::Variant) {
                    match value {
                        #(#capitalized_names(#names1) => {
                            self.#names2 = #names3
                        }),*
                    }
                }
            }
        }
    }
    else {
        panic!("Not a struct");
    }
}

/// Create the function returing the completion of the setting values.
pub fn to_setting_completion_fn(name: &Ident, body: &Body) -> Tokens {
    let mut completions = vec![];
    if let Struct(VariantData::Struct(ref fields)) = *body {
        'field_loop:
        for field in fields {
            for attribute in &field.attrs {
                if let &Attribute { value: List(ref ident, ref args), .. } = attribute {
                    if ident == "completion" {
                        if let Word(ref arg_ident) = args[0] {
                            if arg_ident == "hidden" {
                                continue 'field_loop;
                            }
                        }
                    }
                }
            }

            let field_name = field.ident.as_ref().unwrap().to_string();
            let field_type = &field.ty;

            completions.push(quote! {
                (#field_name.to_string(), #field_type::completion_values())
            });
        }
    }

    quote! {
        use mg_settings::CompletionValues;

        impl ::mg_settings::SettingCompletion for #name {
            fn get_value_completions() -> ::std::collections::HashMap<String, Vec<String>> {
                let mut vec = vec![#(#completions),*];
                let iter = vec.drain(..);
                iter.collect()
            }
        }
    }
}

/// Convert a Rust type to a `Value` type.
fn to_value_type(ident: &Ident) -> Ident {
    let value_type =
        match ident.to_string().as_ref() {
            "bool" => "Bool",
            "f64" => "Float",
            "i64" => "Int",
            _ => "Str",
        };
    Ident::new(value_type)
}

/// Convert a `Value` type to a string representation of the type.
fn value_type_to_type(ident: &Ident) -> &str {
    match ident.to_string().as_ref() {
        "Bool" => "bool",
        "Float" => "float",
        "Int" => "integer",
        "Str" => "string",
        ty => panic!("Unknown Value type {}", ty),
    }
}
<commit_msg>Fixed setting completions.<commit_after>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

use quote::Tokens;
use syn::{Attribute, Body, Ident, MacroInput, Path, VariantData};
use syn::Body::{Enum, Struct};
use syn::MetaItem::{List, Word};
use syn::Ty;

use attributes::to_metadata_impl;
use string::{snake_to_camel, to_dash_name};

/// Expand the required trais for the derive Setting attribute.
pub fn expand_setting_enum(mut ast: MacroInput) -> Tokens {
    let name = ast.ident.clone();
    let mut default = None;

    let mut variant_names = vec![];
    if let Enum(ref mut variants) = ast.body {
        for variant in variants {
            variant_names.push(variant.ident.clone());
            if !variant.attrs.is_empty() {
                for attribute in &variant.attrs {
                    if let &Attribute { value: Word(ref ident), .. } = attribute {
                        if ident == "default" {
                            default = Some(variant.ident.clone());
                        }
                    }
                }
                variant.attrs.clear();
            }
        }
    }
    let choice_names: Vec<_> = variant_names.iter()
        .map(|name| to_dash_name(&name.to_string()))
        .collect();
    let choice_names1 = &choice_names;
    let choice_names2 = &choice_names;

    let qualified_names = variant_names.iter()
        .map(|variant_name| quote! {
            #name::#variant_name
        });

    let from_str_fn = quote! {
        fn from_str(string: &str) -> Result<Self, Self::Err> {
            match string {
                #(#choice_names1 => Ok(#qualified_names),)*
                _ => Err(::mg_settings::error::SettingError::UnknownChoice {
                    actual: string.to_string(),
                    expected: vec![#(#choice_names2),*],
                }),
            }
        }
    };

    let default_impl =
        if let Some(ident) = default {
            quote! {
                impl Default for #name {
                    fn default() -> Self {
                        #name::#ident
                    }
                }
            }
        }
        else {
            quote! {
            }
        };

    let completion_values_impl = quote! {
        impl CompletionValues for #name {
            fn completion_values() -> Vec<String> {
                vec![#(#choice_names1.to_string()),*]
            }
        }
    };

    quote! {
        #[derive(Clone)]
        #ast

        #default_impl

        #completion_values_impl

        impl ::std::str::FromStr for #name {
            type Err = ::mg_settings::error::SettingError;

            #from_str_fn
        }
    }
}

/// Expand the required traits for the derive Settings attribute.
pub fn expand_settings_enum(mut ast: MacroInput) -> Tokens {
    let name = &ast.ident;
    let completion_fn = to_setting_completion_fn(name, &ast.body);
    let variant_name = Ident::new(format!("{}Variant", name));
    let variant_enum = to_enums(&ast.ident, &variant_name, &ast.body);
    let settings_impl = to_settings_impl(name, &variant_name, &ast.body);
    let (metadata_impl, _) = to_metadata_impl(name, &mut ast.body);
    quote! {
        #[derive(Default)]
        #ast

        #variant_enum

        #settings_impl

        #metadata_impl

        #completion_fn
    }
}

/// Check if a type is a custom type (including enum).
fn is_custom_type(ident: &Ident) -> bool {
    match ident.to_string().as_ref() {
        "bool" | "f64" | "i64" | "String" => false,
        _ => true,
    }
}

/// Create the variant enums for getters and setters.
fn to_enums(name: &Ident, variant_name: &Ident, settings_struct: &Body) -> Tokens {
    if let &Struct(VariantData::Struct(ref strct)) = settings_struct {
        let mut field_names = vec![];
        let mut names = vec![];
        let mut types = vec![];
        for field in strct {
            if let Some(ref ident) = field.ident {
                field_names.push(ident);
                let ident = Ident::new(snake_to_camel(&ident.to_string()));
                names.push(ident);
                types.push(field.ty.clone());
            }
        }
        let names1 = &names;
        quote! {
            #[derive(Clone)]
            pub enum #variant_name {
                #(#names1(#types)),*
            }

            impl #name {
                pub fn new() -> #name {
                    #name::default()
                }
            }
        }
    }
    else {
        panic!("Not a struct");
    }
}

/// Create the impl Settings.
fn to_settings_impl(name: &Ident, variant_name: &Ident, settings_struct: &Body) -> Tokens {
    if let &Struct(VariantData::Struct(ref strct)) = settings_struct {
        let mut names = vec![];
        let mut capitalized_names = vec![];
        let mut original_types = vec![];
        let mut types = vec![];
        for field in strct {
            if let Some(ref ident) = field.ident {
                let ident_string = ident.to_string();
                let ident = Ident::new(ident_string.clone());
                names.push(ident);
                let ident = Ident::new(snake_to_camel(&ident_string));
                capitalized_names.push(
                    quote! {
                        #variant_name::#ident
                    });

                if let Ty::Path(_, Path { ref segments, .. }) = field.ty {
                    original_types.push(&segments[0].ident);
                    types.push(to_value_type(&segments[0].ident));
                }
            }
        }
        let string_names: Vec<_> = names.iter()
            .map(|ident| ident.to_string().replace("_", "-"))
            .collect();
        let string_names = &string_names;
        let capitalized_names = &capitalized_names;
        let names1 = &names;
        let names2 = &names;
        let names3 = &names;
        let variant_exprs = names.iter().zip(original_types.iter())
            .map(|(name, typ)|
                 if is_custom_type(typ) {
                     quote! {
                         ::std::str::FromStr::from_str(&#name)?
                     }
                 }
                 else {
                     quote! { #name }
                 }
            );
        let types1 = &types;
        let type_names = types.iter()
            .map(|ident| value_type_to_type(&ident));

        let to_variant_fn_variant = quote! {
            #(#string_names => {
                if let ::mg_settings::Value::#types1(#names1) = value {
                    Ok(#capitalized_names(#variant_exprs))
                }
                else {
                    Err(::mg_settings::error::SettingError::WrongType {
                        actual: value.to_type().to_string(),
                        expected: #type_names.to_string(),
                    })
                }
            },)*
        };

        let to_variant_fn = quote! {
            fn to_variant(name: &str, value: ::mg_settings::Value) -> Result<Self::Variant, ::mg_settings::error::SettingError> {
                match name {
                    #to_variant_fn_variant
                    _ => Err(::mg_settings::error::SettingError::UnknownSetting(name.to_string())),
                }
            }
        };

        quote! {
            impl ::mg_settings::settings::Settings for #name {
                type Variant = #variant_name;

                #to_variant_fn

                fn set_value(&mut self, value: Self::Variant) {
                    match value {
                        #(#capitalized_names(#names1) => {
                            self.#names2 = #names3
                        }),*
                    }
                }
            }
        }
    }
    else {
        panic!("Not a struct");
    }
}

/// Create the function returing the completion of the setting values.
pub fn to_setting_completion_fn(name: &Ident, body: &Body) -> Tokens {
    let mut completions = vec![];
    if let Struct(VariantData::Struct(ref fields)) = *body {
        'field_loop:
        for field in fields {
            for attribute in &field.attrs {
                if let &Attribute { value: List(ref ident, ref args), .. } = attribute {
                    if ident == "completion" {
                        if let Word(ref arg_ident) = args[0] {
                            if arg_ident == "hidden" {
                                continue 'field_loop;
                            }
                        }
                    }
                }
            }

            let setting_name = field.ident.as_ref().unwrap().to_string().replace('_', "-");
            let field_type = &field.ty;

            completions.push(quote! {
                (#setting_name.to_string(), #field_type::completion_values())
            });
        }
    }

    quote! {
        use mg_settings::CompletionValues;

        impl ::mg_settings::SettingCompletion for #name {
            fn get_value_completions() -> ::std::collections::HashMap<String, Vec<String>> {
                let mut vec = vec![#(#completions),*];
                let iter = vec.drain(..);
                iter.collect()
            }
        }
    }
}

/// Convert a Rust type to a `Value` type.
fn to_value_type(ident: &Ident) -> Ident {
    let value_type =
        match ident.to_string().as_ref() {
            "bool" => "Bool",
            "f64" => "Float",
            "i64" => "Int",
            _ => "Str",
        };
    Ident::new(value_type)
}

/// Convert a `Value` type to a string representation of the type.
fn value_type_to_type(ident: &Ident) -> &str {
    match ident.to_string().as_ref() {
        "Bool" => "bool",
        "Float" => "float",
        "Int" => "integer",
        "Str" => "string",
        ty => panic!("Unknown Value type {}", ty),
    }
}
<|endoftext|>


<commit_before>// Validation forces more allocation; disable it.
// compile-flags: -Zmir-emit-validate=0
#![feature(box_syntax, custom_attribute, attr_literals)]
#![miri(memory_size=2048)]

fn main() {
    loop {
        ::std::mem::forget(box 42); //~ ERROR tried to allocate 4 more bytes
    }
}
<commit_msg>fix oom2 test<commit_after>// Validation forces more allocation; disable it.
// compile-flags: -Zmir-emit-validate=0
#![feature(box_syntax, custom_attribute, attr_literals)]
#![miri(memory_size=1024)]

// On 64bit platforms, the allocator needs 32 bytes allocated to pass a return value, so that's the error we see.
// On 32bit platforms, it's just 16 bytes.
// error-pattern: tried to allocate

fn main() {
    loop {
        ::std::mem::forget(box 42);
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 The Tink-Rust Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

use prost::Message;
use std::sync::Arc;

#[test]
fn test_register_key_manager() {
    tink_mac::init();
    tink_aead::init();
    // get HMACKeyManager
    tink::registry::get_key_manager(tink_testutil::HMAC_TYPE_URL).unwrap();
    // get AESGCMKeyManager
    tink::registry::get_key_manager(tink_testutil::AES_GCM_TYPE_URL).unwrap();
    // some random typeurl
    assert!(
        tink::registry::get_key_manager("some url").is_err(),
        "expect an error when a type url doesn't exist in the registry"
    );
}

#[test]
fn test_register_key_manager_with_collision() {
    tink_aead::init();
    // dummy_key_manager's type_url is equal to that of AES-GCM by default.
    let dummy_key_manager = Arc::new(tink_testutil::DummyAeadKeyManager::default());
    // This should fail because overwriting is disallowed.
    assert!(
        tink::registry::register_key_manager(dummy_key_manager).is_err(),
        "AES_GCM_TYPE_URL shouldn't be registered again",
    );
}

#[test]
fn test_register_key_manager_duplicate() {
    let dummy_key_manager = Arc::new(tink_testutil::DummyAeadKeyManager { type_url: "blah" });
    tink::registry::register_key_manager(dummy_key_manager.clone()).unwrap();

    // This should fail because overwriting is disallowed.
    assert!(
        tink::registry::register_key_manager(dummy_key_manager).is_err(),
        "Shouldn't allow double registration",
    );
}

#[test]
fn test_new_key_data() {
    tink_mac::init();
    // new KeyData from a Hmac KeyTemplate
    let key_data =
        tink::registry::new_key_data(&tink_mac::hmac_sha256_tag128_key_template()).unwrap();
    assert_eq!(
        tink_testutil::HMAC_TYPE_URL,
        key_data.type_url,
        "invalid key data"
    );
    let _key = tink::proto::HmacKey::decode(key_data.value.as_ref())
        .expect("unexpected error when unmarshal HmacKey");

    // unregistered type url
    let template = tink::proto::KeyTemplate {
        type_url: "some url".to_string(),
        output_prefix_type: tink::proto::OutputPrefixType::Tink as i32,
        value: vec![0],
    };
    assert!(
        tink::registry::new_key_data(&template).is_err(),
        "expect an error when key template contains unregistered type_url"
    );
}

#[test]
fn test_new_key() {
    tink_aead::init();
    // aead template
    let aes_gcm_template = tink_aead::aes128_gcm_key_template();
    let key = tink::registry::new_key(&aes_gcm_template).unwrap();

    let aes_gcm_key = tink::proto::AesGcmKey::decode(key.as_ref()).unwrap();

    let aes_gcm_format =
        tink::proto::AesGcmKeyFormat::decode(aes_gcm_template.value.as_ref()).unwrap();
    assert_eq!(
        aes_gcm_key.key_value.len(),
        aes_gcm_format.key_size as usize
    );

    // unregistered type url
    let template = tink::proto::KeyTemplate {
        type_url: "some url".to_string(),
        output_prefix_type: tink::proto::OutputPrefixType::Tink as i32,
        value: vec![0],
    };
    assert!(
        tink::registry::new_key(&template).is_err(),
        "expect an error when key template is not registered"
    );
}

#[test]
fn test_primitive_from_key_data() {
    tink_mac::init();
    // hmac keydata
    let mut key_data = tink_testutil::new_hmac_key_data(tink::proto::HashType::Sha256, 16);
    let p = tink::registry::primitive_from_key_data(&key_data).unwrap();
    if let tink::Primitive::Mac(_) = p {
    } else {
        panic!("Primitive not a Mac");
    }

    // unregistered url
    key_data.type_url = "some url".to_string();
    assert!(
        tink::registry::primitive_from_key_data(&key_data).is_err(),
        "expect an error when type_url has not been registered"
    );
    // unmatched url
    key_data.type_url = tink_testutil::AES_GCM_TYPE_URL.to_string();
    assert!(
        tink::registry::primitive_from_key_data(&key_data).is_err(),
        "expect an error when type_url doesn't match key"
    );
}

#[test]
fn test_primitive() {
    tink_mac::init();
    // hmac key
    let key = tink_testutil::new_hmac_key(tink::proto::HashType::Sha256, 16);
    let mut serialized_key = vec![];
    key.encode(&mut serialized_key).unwrap();
    let p = tink::registry::primitive(tink_testutil::HMAC_TYPE_URL, &serialized_key).unwrap();
    if let tink::Primitive::Mac(_) = p {
    } else {
        panic!("Primitive not a Mac");
    }

    // unregistered url
    assert!(
        tink::registry::primitive("some url", &serialized_key).is_err(),
        "expect an error when type_url has not been registered"
    );
    // unmatched url
    assert!(
        tink::registry::primitive(tink_testutil::AES_GCM_TYPE_URL, &serialized_key).is_err(),
        "expect an error when type_url doesn't match key"
    );
    // empty key
    assert!(
        tink::registry::primitive(tink_testutil::AES_GCM_TYPE_URL, &[]).is_err(),
        "expect an error when key is empty"
    );
    assert!(
        tink::registry::primitive(tink_testutil::AES_GCM_TYPE_URL, &[0]).is_err(),
        "expect an error when key is short"
    );
}

#[test]
fn test_register_kms_client() {
    let kms = tink_testutil::DummyKmsClient {};
    tink::registry::register_kms_client(kms);

    tink::registry::get_kms_client("dummy").expect("error fetching dummy kms client");
}
<commit_msg>tink::registry: extra tests<commit_after>// Copyright 2020 The Tink-Rust Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

use prost::Message;
use std::sync::Arc;

#[test]
fn test_register_key_manager() {
    tink_mac::init();
    tink_aead::init();
    // get HMACKeyManager
    let km = tink::registry::get_key_manager(tink_testutil::HMAC_TYPE_URL).unwrap();
    // get AESGCMKeyManager
    tink::registry::get_key_manager(tink_testutil::AES_GCM_TYPE_URL).unwrap();
    // some random typeurl
    assert!(
        tink::registry::get_key_manager("some url").is_err(),
        "expect an error when a type url doesn't exist in the registry"
    );

    // HMACKeyManager is symmetric
    assert!(!km.supports_private_keys());
    assert!(km.public_key_data(&[]).is_err());
}

#[test]
fn test_register_key_manager_with_collision() {
    tink_aead::init();
    // dummy_key_manager's type_url is equal to that of AES-GCM by default.
    let dummy_key_manager = Arc::new(tink_testutil::DummyAeadKeyManager::default());
    // This should fail because overwriting is disallowed.
    assert!(
        tink::registry::register_key_manager(dummy_key_manager).is_err(),
        "AES_GCM_TYPE_URL shouldn't be registered again",
    );
}

#[test]
fn test_register_key_manager_duplicate() {
    let dummy_key_manager = Arc::new(tink_testutil::DummyAeadKeyManager { type_url: "blah" });
    tink::registry::register_key_manager(dummy_key_manager.clone()).unwrap();

    // This should fail because overwriting is disallowed.
    assert!(
        tink::registry::register_key_manager(dummy_key_manager).is_err(),
        "Shouldn't allow double registration",
    );
}

#[test]
fn test_new_key_data() {
    tink_mac::init();
    // new KeyData from a Hmac KeyTemplate
    let key_data =
        tink::registry::new_key_data(&tink_mac::hmac_sha256_tag128_key_template()).unwrap();
    assert_eq!(
        tink_testutil::HMAC_TYPE_URL,
        key_data.type_url,
        "invalid key data"
    );
    let _key = tink::proto::HmacKey::decode(key_data.value.as_ref())
        .expect("unexpected error when unmarshal HmacKey");

    // unregistered type url
    let template = tink::proto::KeyTemplate {
        type_url: "some url".to_string(),
        output_prefix_type: tink::proto::OutputPrefixType::Tink as i32,
        value: vec![0],
    };
    assert!(
        tink::registry::new_key_data(&template).is_err(),
        "expect an error when key template contains unregistered type_url"
    );
}

#[test]
fn test_new_key() {
    tink_aead::init();
    // aead template
    let aes_gcm_template = tink_aead::aes128_gcm_key_template();
    let key = tink::registry::new_key(&aes_gcm_template).unwrap();

    let aes_gcm_key = tink::proto::AesGcmKey::decode(key.as_ref()).unwrap();

    let aes_gcm_format =
        tink::proto::AesGcmKeyFormat::decode(aes_gcm_template.value.as_ref()).unwrap();
    assert_eq!(
        aes_gcm_key.key_value.len(),
        aes_gcm_format.key_size as usize
    );

    // unregistered type url
    let template = tink::proto::KeyTemplate {
        type_url: "some url".to_string(),
        output_prefix_type: tink::proto::OutputPrefixType::Tink as i32,
        value: vec![0],
    };
    assert!(
        tink::registry::new_key(&template).is_err(),
        "expect an error when key template is not registered"
    );
}

#[test]
fn test_primitive_from_key_data() {
    tink_mac::init();
    // hmac keydata
    let mut key_data = tink_testutil::new_hmac_key_data(tink::proto::HashType::Sha256, 16);
    let p = tink::registry::primitive_from_key_data(&key_data).unwrap();
    if let tink::Primitive::Mac(_) = p {
    } else {
        panic!("Primitive not a Mac");
    }

    // unregistered url
    key_data.type_url = "some url".to_string();
    assert!(
        tink::registry::primitive_from_key_data(&key_data).is_err(),
        "expect an error when type_url has not been registered"
    );
    // unmatched url
    key_data.type_url = tink_testutil::AES_GCM_TYPE_URL.to_string();
    assert!(
        tink::registry::primitive_from_key_data(&key_data).is_err(),
        "expect an error when type_url doesn't match key"
    );
}

#[test]
fn test_primitive() {
    tink_mac::init();
    // hmac key
    let key = tink_testutil::new_hmac_key(tink::proto::HashType::Sha256, 16);
    let mut serialized_key = vec![];
    key.encode(&mut serialized_key).unwrap();
    let p = tink::registry::primitive(tink_testutil::HMAC_TYPE_URL, &serialized_key).unwrap();
    if let tink::Primitive::Mac(_) = p {
    } else {
        panic!("Primitive not a Mac");
    }

    // unregistered url
    assert!(
        tink::registry::primitive("some url", &serialized_key).is_err(),
        "expect an error when type_url has not been registered"
    );
    // unmatched url
    assert!(
        tink::registry::primitive(tink_testutil::AES_GCM_TYPE_URL, &serialized_key).is_err(),
        "expect an error when type_url doesn't match key"
    );
    // empty key
    assert!(
        tink::registry::primitive(tink_testutil::AES_GCM_TYPE_URL, &[]).is_err(),
        "expect an error when key is empty"
    );
    assert!(
        tink::registry::primitive(tink_testutil::AES_GCM_TYPE_URL, &[0]).is_err(),
        "expect an error when key is short"
    );
}

#[test]
fn test_register_kms_client() {
    let kms = tink_testutil::DummyKmsClient {};
    tink::registry::register_kms_client(kms);

    tink::registry::get_kms_client("dummy").expect("error fetching dummy kms client");
}

fn dummy_key_generator() -> tink::proto::KeyTemplate {
    tink::proto::KeyTemplate {
        type_url: "TEST".to_string(),
        value: vec![],
        output_prefix_type: 0,
    }
}

#[test]
fn test_get_template_generator() {
    let dummy_name = "TEST".to_string();
    tink::registry::register_template_generator(&dummy_name, dummy_key_generator);
    let generator = tink::registry::get_template_generator(&dummy_name).unwrap();
    assert_eq!(generator().type_url, "TEST");
    let names = tink::registry::template_names();
    assert!(names.contains(&dummy_name));
}
<|endoftext|>


<commit_before>use ffi::prelude::LLVMTypeRef;
use ffi::{core, target, LLVMTypeKind};
use libc::{c_int, c_uint};
use compile::Compile;
use context::{Context, GetContext};
use target::TargetData;
use util::{self, CastFrom};
use std::{fmt, mem};
use std::iter::Iterator;
use std::ops::Deref;

/// Defines how a value should be laid out in memory.
pub struct Type;
native_ref!(&Type = LLVMTypeRef);
impl Type {
    #[inline(always)]
    /// Get the type given as an LLVM type descriptor in the context given.
    pub fn get<'a, T>(context:&'a Context) -> &'a Type where T:Compile<'a> {
        T::get_type(context)
    }
    /// Make a new function signature with the return type and arguments given.
    pub fn new_function<'a>(ret: &'a Type, args: &[&'a Type]) -> &'a FunctionType {
        unsafe { core::LLVMFunctionType(ret.into(), args.as_ptr() as *mut LLVMTypeRef, args.len() as c_uint, 0) }.into()
    }
    /// Make a new array with the length given.
    pub fn new_array<'a>(element: &'a Type, length: usize) -> &'a Type {
        unsafe { core::LLVMArrayType(element.into(), length as c_uint) }.into()
    }
    /// Make a new vector with the length given.
    pub fn new_vector<'a>(element: &'a Type, length: usize) -> &'a Type {
        unsafe { core::LLVMVectorType(element.into(), length as c_uint) }.into()
    }
    /// Make a new pointer with the given element type.
    pub fn new_pointer<'a>(elem: &'a Type) -> &'a Type {
        unsafe { core::LLVMPointerType(elem.into(), 0 as c_uint) }.into()
    }
    /// Make a new structure type with the given types.
    pub fn new_struct<'a>(elems: &[&'a Type], packed: bool) -> &'a Type {
        unsafe { core::LLVMStructType(elems.as_ptr() as *mut LLVMTypeRef, elems.len() as c_uint, packed as c_int) }.into()
    }
    /// Returns true if the size of the type is known at compile-time.
    ///
    /// This is equivalent to the type implementing `Sized` in Rust
    pub fn is_sized(&self) -> bool {
        unsafe { core::LLVMTypeIsSized(self.into()) != 0 }
    }
    /// Returns true if this type is a function.
    pub fn is_function(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMFunctionTypeKind as c_uint
    }
    /// Returns true if this type is a struct.
    pub fn is_struct(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMStructTypeKind as c_uint
    }
    /// Returns true if this type is void.
    pub fn is_void(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMVoidTypeKind as c_uint
    }
    /// Returns true if this type is a pointer.
    pub fn is_pointer(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMPointerTypeKind as c_uint
    }
    /// Returns true if this type is an integer.
    pub fn is_integer(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMIntegerTypeKind as c_uint
    }
    /// Returns true if this type is any floating-point number.
    pub fn is_float(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) } as c_uint;
        kind == LLVMTypeKind::LLVMHalfTypeKind as c_uint ||
        kind == LLVMTypeKind::LLVMFloatTypeKind as c_uint ||
        kind == LLVMTypeKind::LLVMDoubleTypeKind as c_uint
    }
    /// Returns the size of the type in bytes.
    pub fn get_size(&self, target: &TargetData) -> usize {
        unsafe { target::LLVMABISizeOfType(target.into(), self.into()) as usize }
    }
    /// Returns the element of this pointer type.
    pub fn get_element(&self) -> Option<&Type> {
        unsafe { mem::transmute(core::LLVMGetElementType(self.into())) }
    }
}
get_context!(Type, LLVMGetTypeContext);
to_str!(Type, LLVMPrintTypeToString);

/// A structure type, such as a tuple or struct
pub struct StructType;
native_ref!(&StructType = LLVMTypeRef);
impl StructType {
    /// Make a new struct with the given fields and packed representation.
    pub fn new<'a>(context: &'a Context, fields: &[&'a Type], packed: bool) -> &'a StructType {
        unsafe { core::LLVMStructTypeInContext(context.into(), fields.as_ptr() as *mut LLVMTypeRef, fields.len() as c_uint, packed as c_int) }.into()
    }
    /// Make a new named struct with the given fields and packed representation.
    pub fn new_named<'a>(context: &'a Context, name: &str, fields: &[&'a Type], packed: bool) -> &'a StructType {
        util::with_cstr(name, |name| unsafe {
            let ty = core::LLVMStructCreateNamed(context.into(), name);
            core::LLVMStructSetBody(ty, fields.as_ptr() as *mut LLVMTypeRef, fields.len() as c_uint, packed as c_int);
            ty.into()
        })
    }
    /// Returns the elements (AKA fields) that make up this struct.
    pub fn get_elements(&self) -> Vec<Type> {
        unsafe {
            let size = core::LLVMCountStructElementTypes(self.into());
            let mut els:Vec<_> = (0..size).map(|_| mem::uninitialized()).collect();
            core::LLVMGetStructElementTypes(self.into(), els.as_mut_ptr() as *mut LLVMTypeRef);
            els
        }
    }
}
impl CastFrom for StructType {
    type From = Type;
    fn cast(ty: &Type) -> Option<&StructType> {
        unsafe {
            let kind = core::LLVMGetTypeKind(ty.into());
            if kind as c_uint == LLVMTypeKind::LLVMStructTypeKind as c_uint {
                mem::transmute(ty)
            } else {
                None
            }
        }
    }
}
deref!(StructType, Type);
get_context!(StructType, LLVMGetTypeContext);
to_str!(StructType, LLVMPrintTypeToString);

/// A function signature type
pub struct FunctionType;
native_ref!(&FunctionType = LLVMTypeRef);
deref!(FunctionType, Type);
impl CastFrom for FunctionType {
    type From = Type;
    fn cast(mut ty: &Type) -> Option<&FunctionType> {
        unsafe {
            use libc::c_uint;
            while let Some(elem) = ty.get_element() {
                ty = elem;
            }
            let kind = core::LLVMGetTypeKind(ty.into());
            if kind as c_uint == LLVMTypeKind::LLVMFunctionTypeKind as c_uint {
                mem::transmute(ty)
            } else {
                None
            }
        }
    }
}
impl FunctionType {
    /// Returns how many parameters this signature takes.
    pub fn num_params(&self) -> usize {
        unsafe { core::LLVMCountParamTypes(self.into()) as usize }
    }
    /// Returns a vector of this signature's parameters' types.
    pub fn get_params(&self) -> Vec<&Type> {
        unsafe {
            let count = core::LLVMCountParamTypes(self.into());
            let mut types:Vec<_> = (0..count).map(|_| mem::uninitialized()).collect();
            core::LLVMGetParamTypes(self.into(), types.as_mut_ptr() as *mut LLVMTypeRef);
            types
        }
    }
    /// Returns the type that this function returns.
    pub fn get_return(&self) -> &Type {
        unsafe { core::LLVMGetReturnType(self.into()).into() }
    }
}
get_context!(FunctionType, LLVMGetTypeContext);
to_str!(FunctionType, LLVMPrintTypeToString);
<commit_msg>Fix a StructType typo and corresponding segfault<commit_after>use ffi::prelude::LLVMTypeRef;
use ffi::{core, target, LLVMTypeKind};
use libc::{c_int, c_uint};
use compile::Compile;
use context::{Context, GetContext};
use target::TargetData;
use util::{self, CastFrom};
use std::{fmt, mem};
use std::iter::Iterator;
use std::ops::Deref;

/// Defines how a value should be laid out in memory.
pub struct Type;
native_ref!(&Type = LLVMTypeRef);
impl Type {
    #[inline(always)]
    /// Get the type given as an LLVM type descriptor in the context given.
    pub fn get<'a, T>(context:&'a Context) -> &'a Type where T:Compile<'a> {
        T::get_type(context)
    }
    /// Make a new function signature with the return type and arguments given.
    pub fn new_function<'a>(ret: &'a Type, args: &[&'a Type]) -> &'a FunctionType {
        unsafe { core::LLVMFunctionType(ret.into(), args.as_ptr() as *mut LLVMTypeRef, args.len() as c_uint, 0) }.into()
    }
    /// Make a new array with the length given.
    pub fn new_array<'a>(element: &'a Type, length: usize) -> &'a Type {
        unsafe { core::LLVMArrayType(element.into(), length as c_uint) }.into()
    }
    /// Make a new vector with the length given.
    pub fn new_vector<'a>(element: &'a Type, length: usize) -> &'a Type {
        unsafe { core::LLVMVectorType(element.into(), length as c_uint) }.into()
    }
    /// Make a new pointer with the given element type.
    pub fn new_pointer<'a>(elem: &'a Type) -> &'a Type {
        unsafe { core::LLVMPointerType(elem.into(), 0 as c_uint) }.into()
    }
    /// Make a new structure type with the given types.
    pub fn new_struct<'a>(elems: &[&'a Type], packed: bool) -> &'a Type {
        unsafe { core::LLVMStructType(elems.as_ptr() as *mut LLVMTypeRef, elems.len() as c_uint, packed as c_int) }.into()
    }
    /// Returns true if the size of the type is known at compile-time.
    ///
    /// This is equivalent to the type implementing `Sized` in Rust
    pub fn is_sized(&self) -> bool {
        unsafe { core::LLVMTypeIsSized(self.into()) != 0 }
    }
    /// Returns true if this type is a function.
    pub fn is_function(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMFunctionTypeKind as c_uint
    }
    /// Returns true if this type is a struct.
    pub fn is_struct(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMStructTypeKind as c_uint
    }
    /// Returns true if this type is void.
    pub fn is_void(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMVoidTypeKind as c_uint
    }
    /// Returns true if this type is a pointer.
    pub fn is_pointer(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMPointerTypeKind as c_uint
    }
    /// Returns true if this type is an integer.
    pub fn is_integer(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) };
        kind as c_uint == LLVMTypeKind::LLVMIntegerTypeKind as c_uint
    }
    /// Returns true if this type is any floating-point number.
    pub fn is_float(&self) -> bool {
        let kind = unsafe { core::LLVMGetTypeKind(self.into()) } as c_uint;
        kind == LLVMTypeKind::LLVMHalfTypeKind as c_uint ||
        kind == LLVMTypeKind::LLVMFloatTypeKind as c_uint ||
        kind == LLVMTypeKind::LLVMDoubleTypeKind as c_uint
    }
    /// Returns the size of the type in bytes.
    pub fn get_size(&self, target: &TargetData) -> usize {
        unsafe { target::LLVMABISizeOfType(target.into(), self.into()) as usize }
    }
    /// Returns the element of this pointer type.
    pub fn get_element(&self) -> Option<&Type> {
        unsafe { mem::transmute(core::LLVMGetElementType(self.into())) }
    }
}
get_context!(Type, LLVMGetTypeContext);
to_str!(Type, LLVMPrintTypeToString);

/// A structure type, such as a tuple or struct
pub struct StructType;
native_ref!(&StructType = LLVMTypeRef);
impl StructType {
    /// Make a new struct with the given fields and packed representation.
    pub fn new<'a>(context: &'a Context, fields: &[&'a Type], packed: bool) -> &'a StructType {
        unsafe { core::LLVMStructTypeInContext(context.into(), fields.as_ptr() as *mut LLVMTypeRef, fields.len() as c_uint, packed as c_int) }.into()
    }
    /// Make a new named struct with the given fields and packed representation.
    pub fn new_named<'a>(context: &'a Context, name: &str, fields: &[&'a Type], packed: bool) -> &'a StructType {
        util::with_cstr(name, |name| unsafe {
            let ty = core::LLVMStructCreateNamed(context.into(), name);
            core::LLVMStructSetBody(ty, fields.as_ptr() as *mut LLVMTypeRef, fields.len() as c_uint, packed as c_int);
            ty.into()
        })
    }
    /// Returns the elements (AKA fields) that make up this struct.
    pub fn get_elements(&self) -> Vec<&Type> {
        unsafe {
            let size = core::LLVMCountStructElementTypes(self.into());
            let mut els:Vec<_> = (0..size).map(|_| mem::uninitialized()).collect();
            core::LLVMGetStructElementTypes(self.into(), els.as_mut_ptr() as *mut LLVMTypeRef);
            els
        }
    }
}
impl CastFrom for StructType {
    type From = Type;
    fn cast(ty: &Type) -> Option<&StructType> {
        unsafe {
            let kind = core::LLVMGetTypeKind(ty.into());
            if kind as c_uint == LLVMTypeKind::LLVMStructTypeKind as c_uint {
                mem::transmute(ty)
            } else {
                None
            }
        }
    }
}
deref!(StructType, Type);
get_context!(StructType, LLVMGetTypeContext);
to_str!(StructType, LLVMPrintTypeToString);

/// A function signature type
pub struct FunctionType;
native_ref!(&FunctionType = LLVMTypeRef);
deref!(FunctionType, Type);
impl CastFrom for FunctionType {
    type From = Type;
    fn cast(mut ty: &Type) -> Option<&FunctionType> {
        unsafe {
            use libc::c_uint;
            while let Some(elem) = ty.get_element() {
                ty = elem;
            }
            let kind = core::LLVMGetTypeKind(ty.into());
            if kind as c_uint == LLVMTypeKind::LLVMFunctionTypeKind as c_uint {
                mem::transmute(ty)
            } else {
                None
            }
        }
    }
}
impl FunctionType {
    /// Returns how many parameters this signature takes.
    pub fn num_params(&self) -> usize {
        unsafe { core::LLVMCountParamTypes(self.into()) as usize }
    }
    /// Returns a vector of this signature's parameters' types.
    pub fn get_params(&self) -> Vec<&Type> {
        unsafe {
            let count = core::LLVMCountParamTypes(self.into());
            let mut types:Vec<_> = (0..count).map(|_| mem::uninitialized()).collect();
            core::LLVMGetParamTypes(self.into(), types.as_mut_ptr() as *mut LLVMTypeRef);
            types
        }
    }
    /// Returns the type that this function returns.
    pub fn get_return(&self) -> &Type {
        unsafe { core::LLVMGetReturnType(self.into()).into() }
    }
}
get_context!(FunctionType, LLVMGetTypeContext);
to_str!(FunctionType, LLVMPrintTypeToString);
<|endoftext|>


<commit_before>use crate::common::Result;
use crate::config::Config;
use crate::state::{State, StateUpdate};
use async_std::io;
use async_std::prelude::*;
use async_std::task;
use std::fmt::{self, Write};
use termion::{clear, cursor, style};
use unicode_truncate::UnicodeTruncateStr;

const ALTERNATE_SCREEN: &'static str = csi!("?1049h");
const MAIN_SCREEN: &'static str = csi!("?1049l");

trait Component {
    fn render(&mut self, state: &State) -> Result<()>;
}

#[derive(Debug, Clone, Default)]
struct Prompt {
    symbol: String,
    query: String,
}

// TODO: From Config
impl Prompt {
    fn new(_config: &Config) -> Self {
        let symbol = "$".into();
        let query = "".into();

        Self { symbol, query }
    }
}

impl Component for Prompt {
    fn render(&mut self, state: &State) -> Result<()> {
        self.query = state.query();

        Ok(())
    }
}

impl fmt::Display for Prompt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} {}", self.symbol, self.query)
    }
}

#[derive(Debug, Clone)]
enum Mode {
    Full,
    Inline(usize),
}

impl Mode {
    pub fn setup(&self) -> Option<String> {
        let setup = match self {
            Self::Full => format!("{}{}", ALTERNATE_SCREEN, cursor::Goto(1, 1)),
            Self::Inline(height) => {
                let room = std::iter::repeat("\n")
                    .take(*height)
                    .collect::<Vec<&str>>()
                    .join("");

                let up = *height as u16;

                format!("{}{}\r", room, cursor::Up(up))
            }
        };

        Some(setup)
    }

    pub fn teardown(&self) -> Option<String> {
        let teardown = match self {
            Self::Full => MAIN_SCREEN.to_string(),
            Self::Inline(_) => format!("{}{}{}", clear::CurrentLine, clear::AfterCursor, "\r"),
        };

        Some(teardown)
    }
}

#[derive(Debug, Clone)]
pub struct Layout<W: io::Write + Send + Unpin + 'static> {
    size: (usize, usize),
    offset: usize,
    mode: Mode,
    writer: W,

    prompt: Prompt,
}

impl<W: io::Write + Send + Unpin + 'static> Layout<W> {
    pub async fn new(config: &Config, writer: W) -> Result<Self> {
        let size = config.screen.size;
        let offset = 0;
        let mode = if config.screen.full {
            Mode::Full
        } else {
            let (_, height) = size;
            Mode::Inline(height)
        };

        let prompt = Prompt::new(config);

        let mut layout = Self {
            size,
            offset,
            mode,
            writer,
            prompt,
        };

        if let Some(setup) = layout.mode.setup() {
            layout.write(&setup).await?;
        }

        Ok(layout)
    }

    pub async fn write<D: std::fmt::Display>(&mut self, display: &D) -> Result<()> {
        let rendered = format!("{}", display,);
        self.writer.write_all(rendered.as_bytes()).await?;
        self.writer.flush().await?;

        Ok(())
    }

    pub async fn render(&mut self, state: &State) -> Result<()> {
        let d = self.draw(state)?;

        self.write(&d).await?;

        Ok(())
    }

    pub fn draw(&mut self, state: &State) -> Result<String> {
        let mut display = String::new();

        match state.last_update() {
            StateUpdate::Query => {
                let prompt = self.draw_prompt(&state)?;
                write!(&mut display, "{}", prompt)?;
            }
            _ => {
                let list = self.draw_list(&state)?;
                let prompt = self.draw_prompt(&state)?;
                write!(&mut display, "{}{}", list, prompt)?;
            }
        }

        Ok(display)
    }

    fn draw_prompt(&mut self, state: &State) -> Result<String> {
        self.prompt.render(state)?;
        let prompt = format!("{}\r{}", clear::CurrentLine, self.prompt);

        Ok(prompt)
    }

    fn draw_list(&mut self, state: &State) -> Result<String> {
        let mut display = String::new();

        let counter = format!(
            "{}  {}/{}",
            clear::CurrentLine,
            state.matches().len(),
            state.pool_len()
        );

        let invert = format!("{}", style::Invert);
        let no_invert = format!("{}", style::NoInvert);

        let (width, _) = self.size;
        let line_len = width - 2;
        let (offset, lines) = self.scroll(&state);
        let mut list: Vec<String> = state
            .matches()
            .iter()
            .cloned()
            .enumerate()
            .skip(offset)
            .take(lines)
            .map(|(idx, c)| (idx, c.text))
            .map(|(index, candidate)| {
                let (truncated, _) = candidate.unicode_truncate(line_len);
                if index == state.selection_idx() {
                    format!(
                        "{}{}> {}{}",
                        clear::CurrentLine,
                        invert,
                        truncated,
                        no_invert
                    )
                } else {
                    format!("{}  {}", clear::CurrentLine, truncated)
                }
            })
            .collect();

        // The counter is another element of the list
        list.insert(0, counter);

        write!(
            &mut display,
            "{}\r{}{}{}",
            cursor::Down(1),
            list.join("\n"),
            clear::AfterCursor,
            // We always need to reprint the prompt after
            // going up to set the cursor in the last
            // position
            cursor::Up(list.len() as u16),
        )?;

        Ok(display)
    }

    fn scroll(&mut self, state: &State) -> (usize, usize) {
        let (_, height) = self.size;
        let lines_len = height - 2;

        let selection = state.selection_idx();

        let top_position = self.offset;
        let last_position = (lines_len + self.offset) - 1;

        if selection > last_position {
            self.offset += selection - last_position;
        } else if selection < top_position {
            self.offset -= top_position - selection;
        }

        (self.offset, lines_len)
    }
}

impl<W: io::Write + Send + Unpin + 'static> Drop for Layout<W> {
    fn drop(&mut self) {
        task::block_on(async {
            if let Some(teardown) = self.mode.teardown() {
                self.write(&teardown)
                    .await
                    .expect("Error writing to output");
            }
        });
    }
}
<commit_msg>Basic Meter UI component<commit_after>use crate::common::Result;
use crate::config::Config;
use crate::state::{State, StateUpdate};
use async_std::io;
use async_std::prelude::*;
use async_std::task;
use std::fmt::{self, Write};
use termion::{clear, cursor, style};
use unicode_truncate::UnicodeTruncateStr;

const ALTERNATE_SCREEN: &'static str = csi!("?1049h");
const MAIN_SCREEN: &'static str = csi!("?1049l");

trait Component {
    fn render(&mut self, state: &State) -> Result<()>;
}

#[derive(Debug, Clone, Default)]
struct Prompt {
    symbol: String,
    query: String,
}

// TODO: From Config
impl Prompt {
    fn new(_config: &Config) -> Self {
        let symbol = "$".into();
        let query = "".into();

        Self { symbol, query }
    }
}

impl Component for Prompt {
    fn render(&mut self, state: &State) -> Result<()> {
        self.query = state.query();

        Ok(())
    }
}

impl fmt::Display for Prompt {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} {}", self.symbol, self.query)
    }
}

#[derive(Debug, Clone, Default)]
struct Meter {
    current: usize,
    total: usize,
}

// TODO: From Config
impl Meter {
    fn new(_config: &Config) -> Self {
        let current = 0;
        let total = 0;

        Self { current, total }
    }
}

impl Component for Meter {
    fn render(&mut self, state: &State) -> Result<()> {
        self.current = state.matches().len();
        self.total = state.pool_len();

        Ok(())
    }
}

impl fmt::Display for Meter {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "  {}/{}", self.current, self.total)
    }
}

#[derive(Debug, Clone)]
enum Mode {
    Full,
    Inline(usize),
}

impl Mode {
    pub fn setup(&self) -> Option<String> {
        let setup = match self {
            Self::Full => format!("{}{}", ALTERNATE_SCREEN, cursor::Goto(1, 1)),
            Self::Inline(height) => {
                let room = std::iter::repeat("\n")
                    .take(*height)
                    .collect::<Vec<&str>>()
                    .join("");

                let up = *height as u16;

                format!("{}{}\r", room, cursor::Up(up))
            }
        };

        Some(setup)
    }

    pub fn teardown(&self) -> Option<String> {
        let teardown = match self {
            Self::Full => MAIN_SCREEN.to_string(),
            Self::Inline(_) => format!("{}{}{}", clear::CurrentLine, clear::AfterCursor, "\r"),
        };

        Some(teardown)
    }
}

#[derive(Debug, Clone)]
pub struct Layout<W: io::Write + Send + Unpin + 'static> {
    size: (usize, usize),
    offset: usize,
    mode: Mode,
    writer: W,

    prompt: Prompt,
    meter: Meter,
}

impl<W: io::Write + Send + Unpin + 'static> Layout<W> {
    pub async fn new(config: &Config, writer: W) -> Result<Self> {
        let size = config.screen.size;
        let offset = 0;
        let mode = if config.screen.full {
            Mode::Full
        } else {
            let (_, height) = size;
            Mode::Inline(height)
        };

        let prompt = Prompt::new(config);
        let meter = Meter::new(config);

        let mut layout = Self {
            size,
            offset,
            mode,
            writer,
            prompt,
            meter,
        };

        if let Some(setup) = layout.mode.setup() {
            layout.write(&setup).await?;
        }

        Ok(layout)
    }

    pub async fn write<D: std::fmt::Display>(&mut self, display: &D) -> Result<()> {
        let rendered = format!("{}", display,);
        self.writer.write_all(rendered.as_bytes()).await?;
        self.writer.flush().await?;

        Ok(())
    }

    pub async fn render(&mut self, state: &State) -> Result<()> {
        let d = self.draw(state)?;

        self.write(&d).await?;

        Ok(())
    }

    pub fn draw(&mut self, state: &State) -> Result<String> {
        let mut display = String::new();

        match state.last_update() {
            StateUpdate::Query => {
                let prompt = self.draw_prompt(&state)?;
                write!(&mut display, "{}", prompt)?;
            }
            _ => {
                let list = self.draw_list(&state)?;
                let prompt = self.draw_prompt(&state)?;
                write!(&mut display, "{}{}", list, prompt)?;
            }
        }

        Ok(display)
    }

    fn draw_prompt(&mut self, state: &State) -> Result<String> {
        self.prompt.render(state)?;
        let prompt = format!("{}\r{}", clear::CurrentLine, self.prompt);

        Ok(prompt)
    }

    fn draw_list(&mut self, state: &State) -> Result<String> {
        let mut display = String::new();

        self.meter.render(state)?;
        let counter = format!(
            "{}  {}",
            clear::CurrentLine,
            self.meter
        );

        let invert = format!("{}", style::Invert);
        let no_invert = format!("{}", style::NoInvert);

        let (width, _) = self.size;
        let line_len = width - 2;
        let (offset, lines) = self.scroll(&state);
        let mut list: Vec<String> = state
            .matches()
            .iter()
            .cloned()
            .enumerate()
            .skip(offset)
            .take(lines)
            .map(|(idx, c)| (idx, c.text))
            .map(|(index, candidate)| {
                let (truncated, _) = candidate.unicode_truncate(line_len);
                if index == state.selection_idx() {
                    format!(
                        "{}{}> {}{}",
                        clear::CurrentLine,
                        invert,
                        truncated,
                        no_invert
                    )
                } else {
                    format!("{}  {}", clear::CurrentLine, truncated)
                }
            })
            .collect();

        // The counter is another element of the list
        list.insert(0, counter);

        write!(
            &mut display,
            "{}\r{}{}{}",
            cursor::Down(1),
            list.join("\n"),
            clear::AfterCursor,
            // We always need to reprint the prompt after
            // going up to set the cursor in the last
            // position
            cursor::Up(list.len() as u16),
        )?;

        Ok(display)
    }

    fn scroll(&mut self, state: &State) -> (usize, usize) {
        let (_, height) = self.size;
        let lines_len = height - 2;

        let selection = state.selection_idx();

        let top_position = self.offset;
        let last_position = (lines_len + self.offset) - 1;

        if selection > last_position {
            self.offset += selection - last_position;
        } else if selection < top_position {
            self.offset -= top_position - selection;
        }

        (self.offset, lines_len)
    }
}

impl<W: io::Write + Send + Unpin + 'static> Drop for Layout<W> {
    fn drop(&mut self) {
        task::block_on(async {
            if let Some(teardown) = self.mode.teardown() {
                self.write(&teardown)
                    .await
                    .expect("Error writing to output");
            }
        });
    }
}
<|endoftext|>