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

use command::BuilderArgs;
use keyboard::Key;

pub enum Trie {
    Leaf(CommandInfo),
    Node(HashMap<Key, Trie>)
}

impl Trie {
    fn new() -> Trie {
        Trie::Node(HashMap::new())
    }
    fn lookup_key(&self, key: Key) -> Option<&Trie> {
        match *self {
            Trie::Leaf(_) => None,
            Trie::Node(ref map) => map.get(&key)
        }
    }
    fn lookup_keys(&self, keys: &[Key]) -> Option<&Trie> {
        let mut current = self;

        for key in keys.iter() {
            if let Some(node) = current.lookup_key(*key) {
                match *node {
                    Trie::Leaf(_) => return Some(&(*node)),
                    Trie::Node(_) => current = &(*node)
                }
            } else {
                return None
            }
        }

        Some(&(*current))
    }
    fn bind_key(&mut self, key: Key, value: CommandInfo) {
        match *self {
            Trie::Leaf(_) => {
                *self = Trie::new();
                self.bind_key(key, value);
            }
            Trie::Node(ref mut map) => {
                map.insert(key, Trie::Leaf(value));
            }
        }
    }
    fn bind_keys(&mut self, keys: &[Key], value: CommandInfo) {
        if keys.len() == 1 {
            self.bind_key(keys[0], value);
        } else if keys.len() > 1 {
            match *self {
                Trie::Leaf(_) => {
                    *self = Trie::new();
                    self.bind_keys(keys, value);
                }
                Trie::Node(ref mut map) => {
                    let key = keys[0];
                    let keys = &keys[1..];
                    match map.entry(key) {
                        Entry::Vacant(v) => {
                            let mut node = Trie::new();
                            node.bind_keys(keys, value);
                            v.insert(node);
                        },
                        Entry::Occupied(mut o) =>
                            o.get_mut().bind_keys(keys, value)
                    }
                }
            }
        }
    }
}

pub enum KeyMapState {
    Match(CommandInfo),     // found a match
    Continue,     // needs another key to disambiguate
    None          // no match
}

/// Map sequences of `Key`s to values
pub struct KeyMap {
    root: Trie,
    state: KeyMapState,
    path: Vec<Key>
}

impl KeyMap {
    pub fn new() -> KeyMap {
        KeyMap {
            root: Trie::new(),
            state: KeyMapState::None,
            path: Vec::new()
        }
    }

    /// Eat one keypress, return the new state
    pub fn check_key(&mut self, key: Key) -> KeyMapState {
        self.path.push(key);
        self.state = match self.root.lookup_keys(&*self.path) {
            Some(n) => {
                match n {
                    &Trie::Leaf(ref value) => KeyMapState::Match(value.clone()),
                    &Trie::Node(_) => KeyMapState::Continue
                }
            }
            _ => { self.path.clear(); KeyMapState::None }
        };
        let (new_state, ret_val) = match self.state {
            KeyMapState::Match(ref value) => {
                // self.state = KeyMapState::None;
                self.path.clear();
                (Some(KeyMapState::None), KeyMapState::Match(value.clone()))
            },
            KeyMapState::Continue => (None, KeyMapState::Continue),
            KeyMapState::None => (None, KeyMapState::None),
        };

        if let Some(st) = new_state {
            self.state = st;
        }

        ret_val
    }

    /// Insert or overwrite a key-sequence binding
    pub fn bind_keys(&mut self, keys: &[Key], value: CommandInfo) {
        self.root.bind_keys(&*keys, value);
    }

    /// Insert or overwrite a key binding
    pub fn bind_key(&mut self, key: Key, value: CommandInfo) {
        self.root.bind_key(key, value);
    }

    // /// Insert or overwrite a key binding or key-sequence binding
    // pub fn bind(&mut self, binding: KeyBinding) {
    //     if binding.keys.len() == 1 {
    //         self.bind_key(binding.keys[0], binding.command_info);
    //     } else {
    //         self.bind_keys(&binding.keys.clone(), binding.command_info);
    //     }
    // }
}

#[derive(Clone)]
pub struct KeyBinding {
    pub keys: Vec<Key>,
    pub command_info: CommandInfo,
}

#[derive(Clone)]
pub struct CommandInfo {
    pub command_name: String,
    pub args: Option<BuilderArgs>,
}
<commit_msg>Remove unnecessary Clone from KeyBinding<commit_after>use std::collections::HashMap;
use std::collections::hash_map::Entry;

use command::BuilderArgs;
use keyboard::Key;

pub enum Trie {
    Leaf(CommandInfo),
    Node(HashMap<Key, Trie>)
}

impl Trie {
    fn new() -> Trie {
        Trie::Node(HashMap::new())
    }
    fn lookup_key(&self, key: Key) -> Option<&Trie> {
        match *self {
            Trie::Leaf(_) => None,
            Trie::Node(ref map) => map.get(&key)
        }
    }
    fn lookup_keys(&self, keys: &[Key]) -> Option<&Trie> {
        let mut current = self;

        for key in keys.iter() {
            if let Some(node) = current.lookup_key(*key) {
                match *node {
                    Trie::Leaf(_) => return Some(&(*node)),
                    Trie::Node(_) => current = &(*node)
                }
            } else {
                return None
            }
        }

        Some(&(*current))
    }
    fn bind_key(&mut self, key: Key, value: CommandInfo) {
        match *self {
            Trie::Leaf(_) => {
                *self = Trie::new();
                self.bind_key(key, value);
            }
            Trie::Node(ref mut map) => {
                map.insert(key, Trie::Leaf(value));
            }
        }
    }
    fn bind_keys(&mut self, keys: &[Key], value: CommandInfo) {
        if keys.len() == 1 {
            self.bind_key(keys[0], value);
        } else if keys.len() > 1 {
            match *self {
                Trie::Leaf(_) => {
                    *self = Trie::new();
                    self.bind_keys(keys, value);
                }
                Trie::Node(ref mut map) => {
                    let key = keys[0];
                    let keys = &keys[1..];
                    match map.entry(key) {
                        Entry::Vacant(v) => {
                            let mut node = Trie::new();
                            node.bind_keys(keys, value);
                            v.insert(node);
                        },
                        Entry::Occupied(mut o) =>
                            o.get_mut().bind_keys(keys, value)
                    }
                }
            }
        }
    }
}

pub enum KeyMapState {
    Match(CommandInfo),     // found a match
    Continue,     // needs another key to disambiguate
    None          // no match
}

/// Map sequences of `Key`s to values
pub struct KeyMap {
    root: Trie,
    state: KeyMapState,
    path: Vec<Key>
}

impl KeyMap {
    pub fn new() -> KeyMap {
        KeyMap {
            root: Trie::new(),
            state: KeyMapState::None,
            path: Vec::new()
        }
    }

    /// Eat one keypress, return the new state
    pub fn check_key(&mut self, key: Key) -> KeyMapState {
        self.path.push(key);
        self.state = match self.root.lookup_keys(&*self.path) {
            Some(n) => {
                match n {
                    &Trie::Leaf(ref value) => KeyMapState::Match(value.clone()),
                    &Trie::Node(_) => KeyMapState::Continue
                }
            }
            _ => { self.path.clear(); KeyMapState::None }
        };
        let (new_state, ret_val) = match self.state {
            KeyMapState::Match(ref value) => {
                // self.state = KeyMapState::None;
                self.path.clear();
                (Some(KeyMapState::None), KeyMapState::Match(value.clone()))
            },
            KeyMapState::Continue => (None, KeyMapState::Continue),
            KeyMapState::None => (None, KeyMapState::None),
        };

        if let Some(st) = new_state {
            self.state = st;
        }

        ret_val
    }

    /// Insert or overwrite a key-sequence binding
    pub fn bind_keys(&mut self, keys: &[Key], value: CommandInfo) {
        self.root.bind_keys(&*keys, value);
    }

    /// Insert or overwrite a key binding
    pub fn bind_key(&mut self, key: Key, value: CommandInfo) {
        self.root.bind_key(key, value);
    }

    // /// Insert or overwrite a key binding or key-sequence binding
    // pub fn bind(&mut self, binding: KeyBinding) {
    //     if binding.keys.len() == 1 {
    //         self.bind_key(binding.keys[0], binding.command_info);
    //     } else {
    //         self.bind_keys(&binding.keys.clone(), binding.command_info);
    //     }
    // }
}

pub struct KeyBinding {
    pub keys: Vec<Key>,
    pub command_info: CommandInfo,
}

#[derive(Clone)]
pub struct CommandInfo {
    pub command_name: String,
    pub args: Option<BuilderArgs>,
}
<|endoftext|>


<commit_before>// This code is heavily inspired by hoedown.

//
// Performance observations:
//
// Note that buf.head() == Some(&ch) is much faster than buf[0] == ch.
//

extern crate extra;
use extra::test::BenchHarness;

static SP: u8 = ' ' as u8;
static NL: u8 = '\n' as u8;
static CR: u8 = '\r' as u8;
static TAB: u8 = '\t' as u8;
static STAR: u8 = '*' as u8;
static DASH: u8 = '-' as u8;
static UNDERSCORE: u8 = '_' as u8;

/// Return Some(`rem`) if the line is a horizontal rule, with `rem` being the
/// buf after the hrule. Otherwise return None.
fn is_hrule<'a>(buf: &'a[u8]) -> Option<&'a[u8]> {
    let mut buf = buf;

    // Skip up to three leading spaces.
    //
    // We don't need to care about tabs here as in this position they are
    // equivalent to 4 spaces, which means we would not parse this as a
    // hrule.
    if buf.head() == Some(&SP) { buf = buf.tail(); }
    if buf.head() == Some(&SP) { buf = buf.tail(); }
    if buf.head() == Some(&SP) { buf = buf.tail(); }

    let item = match buf.head() {
        Some(&c) if c == STAR ||
                    c == DASH ||
                    c == UNDERSCORE => c,
        _                           => return None
    };

    // The count of '*', '-' or '_'
    let mut cnt: uint = 0;

    // Counts the consumed spaces (and the final NL)
    let mut spc: uint = 0;

    for &ch in buf.iter() {
        if      ch == item { cnt += 1; }
        else if ch == NL   { spc += 1; break; }
        else if ch == SP   { spc += 1; }
        else               { return None; }
    }

    if cnt >= 3 {
        Some(buf.slice_from(cnt + spc))
    } else {
        None
    }
}

#[test]
fn test_is_hrule() {
    // examples as given on the markdown homepage
    assert!(is_hrule(bytes!("* * *\n")).is_some());
    assert!(is_hrule(bytes!("***\n")).is_some());
    assert!(is_hrule(bytes!("*****\n")).is_some());
    assert!(is_hrule(bytes!("- - -\n")).is_some());
    assert!(is_hrule(bytes!("---------------------------------------\n")).is_some());

    // up to three spaces ignored
    assert!(is_hrule(bytes!(" ***\n")).is_some());
    assert!(is_hrule(bytes!("  ***\n")).is_some());
    assert!(is_hrule(bytes!("   ***\n")).is_some());

    // but not four, or a tab which is equivalent to four spaces
    assert!(is_hrule(bytes!("    ***\n")).is_none());
    assert!(is_hrule(bytes!("\t***\n")).is_none());

    // need at least three
    assert!(is_hrule(bytes!("*\n")).is_none());
    assert!(is_hrule(bytes!("**\n")).is_none());
    assert!(is_hrule(bytes!("* *\n")).is_none());
    assert!(is_hrule(bytes!("   * *\n")).is_none());

    // Also works without newline at the end
    assert!(is_hrule(bytes!("* * *")).is_some());

    // And underscores also supported
    assert!(is_hrule(bytes!("___")).is_some());
    assert!(is_hrule(bytes!("______________")).is_some());
    assert!(is_hrule(bytes!(" ______________")).is_some());

    // Test if the remaining buf actually works.
    let s = bytes!("   * * *\nremaining");
    let res = is_hrule(s);
    assert!(res.is_some());
    assert_eq!(res.unwrap(), bytes!("remaining"));
}

#[bench]
fn bench_is_hrule(b: &mut BenchHarness) {
    let s = bytes!("   * * * * * * * * * * * * * * * *\n");
    b.iter(|| is_hrule(s));
}

/// Return Some(`rem`) if the line is an empty line, with `rem` being the buf
/// after the empty line. Otherwise return None.
fn is_empty<'a>(buf: &'a[u8]) -> Option<&'a[u8]> {
    let mut cnt: uint = 0;

    for &ch in buf.iter() {
        if      ch == NL  { cnt += 1; break; }
        else if ch == CR  { cnt += 1; }
        else if ch == SP  { cnt += 1; }
        else if ch == TAB { cnt += 1; }
        else              { return None; }
    }

    if cnt > 0 {
        Some(buf.slice_from(cnt))
    } else {
        None
    }
}

#[test]
fn test_is_empty() {
    assert!(is_empty(bytes!("\n")).is_some());
    assert!(is_empty(bytes!("    \n")).is_some());
    assert!(is_empty(bytes!("  \t  \n")).is_some());
    assert!(is_empty(bytes!("  \t  \r\n")).is_some());
    assert!(is_empty(bytes!("  \t  \nabc")).is_some());
    assert!(is_empty(bytes!("  \t  ")).is_some());

    assert!(is_empty(bytes!("a")).is_none());
    assert!(is_empty(bytes!(" a")).is_none());
    assert!(is_empty(bytes!(" a\n")).is_none());
    assert!(is_empty(bytes!(" \ta\n")).is_none());

    // Test if the remaining buf actually works.
    let s = bytes!("   \t\r\nremaining");
    let res = is_empty(s);
    assert!(res.is_some());
    assert_eq!(res.unwrap(), bytes!("remaining"));
}
<commit_msg>Factor out space skipping<commit_after>// This code is heavily inspired by hoedown.

//
// Performance observations:
//
// Note that buf.head() == Some(&ch) is much faster than buf[0] == ch.
//

#[cfg(test)] extern crate extra;
#[cfg(test)] use extra::test::BenchHarness;

static SP: u8 = ' ' as u8;
static NL: u8 = '\n' as u8;
static CR: u8 = '\r' as u8;
static TAB: u8 = '\t' as u8;
static STAR: u8 = '*' as u8;
static DASH: u8 = '-' as u8;
static UNDERSCORE: u8 = '_' as u8;

//
// Skip up to three leading spaces.
//
// Up to three leading spaces are allowed for many elements.
//
// We don't need to care about a TAB here as in this position it is equivalent
// to 4 spaces, which means that when we find a TAB here we would not parse the
// corresponding element.
//
fn skip_initial_three_spaces<'a>(buf: &'a[u8])-> &'a[u8] {
    let mut buf = buf;
    if buf.head() == Some(&SP) { buf = buf.tail(); }
    if buf.head() == Some(&SP) { buf = buf.tail(); }
    if buf.head() == Some(&SP) { buf = buf.tail(); }
    return buf;
}

//
// Return Some(`rem`) if the line is a horizontal rule, with `rem` being the
// buf after the hrule. Otherwise return None.
//
fn is_hrule<'a>(buf: &'a[u8]) -> Option<&'a[u8]> {
    let buf = skip_initial_three_spaces(buf);

    let item = match buf.head() {
        Some(&c) if c == STAR ||
                    c == DASH ||
                    c == UNDERSCORE => c,
        _                           => return None
    };

    // The count of '*', '-' or '_'
    let mut cnt: uint = 0;

    // Counts the consumed spaces (and the final NL)
    let mut spc: uint = 0;

    for &ch in buf.iter() {
        if      ch == item { cnt += 1; }
        else if ch == NL   { spc += 1; break; }
        else if ch == SP   { spc += 1; }
        else               { return None; }
    }

    if cnt >= 3 {
        Some(buf.slice_from(cnt + spc))
    } else {
        None
    }
}

#[test]
fn test_is_hrule() {
    // examples as given on the markdown homepage
    assert!(is_hrule(bytes!("* * *\n")).is_some());
    assert!(is_hrule(bytes!("***\n")).is_some());
    assert!(is_hrule(bytes!("*****\n")).is_some());
    assert!(is_hrule(bytes!("- - -\n")).is_some());
    assert!(is_hrule(bytes!("---------------------------------------\n")).is_some());

    // up to three spaces ignored
    assert!(is_hrule(bytes!(" ***\n")).is_some());
    assert!(is_hrule(bytes!("  ***\n")).is_some());
    assert!(is_hrule(bytes!("   ***\n")).is_some());

    // but not four, or a tab which is equivalent to four spaces
    assert!(is_hrule(bytes!("    ***\n")).is_none());
    assert!(is_hrule(bytes!("\t***\n")).is_none());

    // need at least three
    assert!(is_hrule(bytes!("*\n")).is_none());
    assert!(is_hrule(bytes!("**\n")).is_none());
    assert!(is_hrule(bytes!("* *\n")).is_none());
    assert!(is_hrule(bytes!("   * *\n")).is_none());

    // Also works without newline at the end
    assert!(is_hrule(bytes!("* * *")).is_some());

    // And underscores also supported
    assert!(is_hrule(bytes!("___")).is_some());
    assert!(is_hrule(bytes!("______________")).is_some());
    assert!(is_hrule(bytes!(" ______________")).is_some());

    // Test if the remaining buf actually works.
    let s = bytes!("   * * *\nremaining");
    let res = is_hrule(s);
    assert!(res.is_some());
    assert_eq!(res.unwrap(), bytes!("remaining"));
}

#[bench]
fn bench_is_hrule(b: &mut BenchHarness) {
    let s = bytes!("   * * * * * * * * * * * * * * * *\n");
    b.iter(|| is_hrule(s));
}

//
// Return Some(`rem`) if the line is an empty line, with `rem` being the buf
// after the empty line. Otherwise return None.
//
fn is_empty<'a>(buf: &'a[u8]) -> Option<&'a[u8]> {
    let mut cnt: uint = 0;

    for &ch in buf.iter() {
        if      ch == NL  { cnt += 1; break; }
        else if ch == CR  { cnt += 1; }
        else if ch == SP  { cnt += 1; }
        else if ch == TAB { cnt += 1; }
        else              { return None; }
    }

    if cnt > 0 {
        Some(buf.slice_from(cnt))
    } else {
        None
    }
}

#[test]
fn test_is_empty() {
    assert!(is_empty(bytes!("\n")).is_some());
    assert!(is_empty(bytes!("    \n")).is_some());
    assert!(is_empty(bytes!("  \t  \n")).is_some());
    assert!(is_empty(bytes!("  \t  \r\n")).is_some());
    assert!(is_empty(bytes!("  \t  \nabc")).is_some());
    assert!(is_empty(bytes!("  \t  ")).is_some());

    assert!(is_empty(bytes!("a")).is_none());
    assert!(is_empty(bytes!(" a")).is_none());
    assert!(is_empty(bytes!(" a\n")).is_none());
    assert!(is_empty(bytes!(" \ta\n")).is_none());

    // Test if the remaining buf actually works.
    let s = bytes!("   \t\r\nremaining");
    let res = is_empty(s);
    assert!(res.is_some());
    assert_eq!(res.unwrap(), bytes!("remaining"));
}
<|endoftext|>


<commit_before>extern crate std;
extern crate hyper;
extern crate serde_json;

use std::string::String;
use std::io::Read;
use self::serde_json::Value;

#[derive(Debug)]
pub struct GithubError;

impl From<hyper::error::Error> for GithubError {
    fn from(_: hyper::error::Error) -> Self {
        GithubError
    }
}

impl From<serde_json::error::Error> for GithubError {
    fn from(_: serde_json::error::Error) -> Self {
        GithubError
    }
}

impl From<std::io::Error> for GithubError {
    fn from(_: std::io::Error) -> Self {
        GithubError
    }
}

pub fn get_display_text(user: &str, repo: &str, issue: &str)
    -> Result<String, GithubError> {

    let url = format!("https://api.github.com/repos/{}/{}/issues/{}",
                      user, repo, issue);
    let client = hyper::client::Client::new();
    let mut resp = try!(client
        .get(&url)
        .header(hyper::header::UserAgent("ids1024".to_owned()))
        .send());

    let mut body = String::new();
    try!(resp.read_to_string(&mut body));
    let data: Value = try!(serde_json::from_str(&body));
    let obj = try!(data.as_object().ok_or(GithubError));

    let title = try!(try!(obj.get("title").ok_or(GithubError))
                     .as_string().ok_or(GithubError));
    let state = try!(try!(obj.get("state").ok_or(GithubError))
                     .as_string().ok_or(GithubError));
    let url = try!(try!(obj.get("html_url").ok_or(GithubError))
                        .as_string().ok_or(GithubError));
    let issuetype =
        if obj.get("pull_request").is_some() {
            "pull request"
        } else {
            "issue"
        };

    Ok(format!("[{}] [{}] {}\n{}", issuetype, state, title, url))
}
<commit_msg>Use match instead of if/else<commit_after>extern crate std;
extern crate hyper;
extern crate serde_json;

use std::string::String;
use std::io::Read;
use self::serde_json::Value;

#[derive(Debug)]
pub struct GithubError;

impl From<hyper::error::Error> for GithubError {
    fn from(_: hyper::error::Error) -> Self {
        GithubError
    }
}

impl From<serde_json::error::Error> for GithubError {
    fn from(_: serde_json::error::Error) -> Self {
        GithubError
    }
}

impl From<std::io::Error> for GithubError {
    fn from(_: std::io::Error) -> Self {
        GithubError
    }
}

pub fn get_display_text(user: &str, repo: &str, issue: &str)
    -> Result<String, GithubError> {

    let url = format!("https://api.github.com/repos/{}/{}/issues/{}",
                      user, repo, issue);
    let client = hyper::client::Client::new();
    let mut resp = try!(client
        .get(&url)
        .header(hyper::header::UserAgent("ids1024".to_owned()))
        .send());

    let mut body = String::new();
    try!(resp.read_to_string(&mut body));
    let data: Value = try!(serde_json::from_str(&body));
    let obj = try!(data.as_object().ok_or(GithubError));

    let title = try!(try!(obj.get("title").ok_or(GithubError))
                     .as_string().ok_or(GithubError));
    let state = try!(try!(obj.get("state").ok_or(GithubError))
                     .as_string().ok_or(GithubError));
    let url = try!(try!(obj.get("html_url").ok_or(GithubError))
                        .as_string().ok_or(GithubError));
    let issuetype = match obj.get("pull_request") {
        Some(..) => "pull request",
        None => "issue",
    };

    Ok(format!("[{}] [{}] {}\n{}", issuetype, state, title, url))
}
<|endoftext|>


<commit_before>use cf = core_foundation;
use cf::array::CFArrayRef;
use cf::base::{
    AbstractCFType,
    AbstractCFTypeRef,
    CFAllocatorRef,
    CFIndex,
    CFGetTypeID,
    CFRange,
    CFRelease,
    CFTypeRef,
    CFTypeID,
    kCFAllocatorDefault,
};
use cf::dictionary::CFDictionaryRef;
use cf::number::CFNumberRef;
use cf::set::CFSetRef;
use cf::string::{
    CFString,
    CFStringRef,
    CFStringGetTypeID,
};

use cg = core_graphics;
use cg::base::CGFloat;

use libc::c_void;

/*
* CTFontTraits.h
*/
// actually, these are extern enums
pub type CTFontFormat = u32;
pub const kCTFontFormatUnrecognized: CTFontFormat = 0;
pub const kCTFontFormatOpenTypePostScript: CTFontFormat = 1;
pub const kCTFontFormatOpenTypeTrueType: CTFontFormat = 2;
pub const kCTFontFormatTrueType: CTFontFormat = 3;
pub const kCTFontFormatPostScript: CTFontFormat = 4;
pub const kCTFontFormatBitmap: CTFontFormat = 5;

pub const kCTFontClassMaskShift: u32 = 28;

pub type CTFontSymbolicTraits = u32;
pub const kCTFontItalicTrait: CTFontSymbolicTraits = (1 << 0);
pub const kCTFontBoldTrait: CTFontSymbolicTraits = (1 << 1);
pub const kCTFontExpandedTrait: CTFontSymbolicTraits = (1 << 5);
pub const kCTFontCondensedTrait: CTFontSymbolicTraits = (1 << 6);
pub const kCTFontMonoSpaceTrait: CTFontSymbolicTraits = (1 << 10);
pub const kCTFontVerticalTrait: CTFontSymbolicTraits = (1 << 11);
pub const kCTFontUIOptimizedTrait: CTFontSymbolicTraits = (1 << 12);
pub const kCTFontClassMaskTrait: CTFontSymbolicTraits = (15 << kCTFontClassMaskShift);

pub type CTFontStylisticClass = u32;
pub const kCTFontUnknownClass: CTFontStylisticClass = (0 << kCTFontClassMaskShift);
pub const kCTFontOldStyleSerifsClass: CTFontStylisticClass = (1 << kCTFontClassMaskShift);
pub const kCTFontTransitionalSerifsClass: CTFontStylisticClass = (2 << kCTFontClassMaskShift);
pub const kCTFontModernSerifsClass: CTFontStylisticClass = (3 << kCTFontClassMaskShift);
pub const kCTFontClarendonSerifsClass: CTFontStylisticClass = (4 << kCTFontClassMaskShift);
pub const kCTFontSlabSerifsClass: CTFontStylisticClass = (5 << kCTFontClassMaskShift);
pub const kCTFontFreeformSerifsClass: CTFontStylisticClass = (7 << kCTFontClassMaskShift);
pub const kCTFontSansSerifClass: CTFontStylisticClass = (8 << kCTFontClassMaskShift);
pub const kCTFontOrnamentalsClass: CTFontStylisticClass = (9 << kCTFontClassMaskShift);
pub const kCTFontScriptsClass: CTFontStylisticClass = (10 << kCTFontClassMaskShift);
pub const kCTFontSymbolicClass: CTFontStylisticClass = (12 << kCTFontClassMaskShift);

/*
* CTFontDescriptor.h
*/
pub type CTFontOrientation = u32;
pub const kCTFontDefaultOrientation: CTFontOrientation = 0;
pub const kCTFontHorizontalOrientation: CTFontOrientation = 1;
pub const kCTFontVerticalOrientation: CTFontOrientation = 2;

pub type CTFontPriority = u32;
pub const kCTFontPrioritySystem: CTFontPriority = 10000;
pub const kCTFontPriorityNetwork: CTFontPriority = 20000;
pub const kCTFontPriorityComputer: CTFontPriority = 30000;
pub const kCTFontPriorityUser: CTFontPriority = 40000;
pub const kCTFontPriorityDynamic: CTFontPriority = 50000;
pub const kCTFontPriorityProcess: CTFontPriority = 60000;

struct __CTFontDescriptor { private: () }
pub type CTFontDescriptorRef = *__CTFontDescriptor;

impl CTFontDescriptorRef : AbstractCFTypeRef {
    pure fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }
}

struct CTFontDescriptor {
    obj: CTFontDescriptorRef,

    drop {
        unsafe {
            CFRelease(cast::transmute(self.obj))
        }
    }
}

pub impl CTFontDescriptor : AbstractCFType<CTFontDescriptorRef> {
    pure fn get_ref() -> CTFontDescriptorRef { self.obj }

    static fn wrap(obj: CTFontDescriptorRef) -> CTFontDescriptor {
        CTFontDescriptor { obj: obj }
    }

    static fn unwrap(wrapper: CTFontDescriptor) -> CTFontDescriptorRef {
        wrapper.obj
    }
}

pub impl CTFontDescriptor {
    fn family_name() -> ~str {
        let value = CTFontDescriptorCopyAttribute(self.obj, kCTFontDisplayNameAttribute);
        // family name should never be null.
        assert value.is_not_null();
        assert CFGetTypeID(value) == CFStringGetTypeID();

        let name : CFString = cf::base::wrap(value as CFStringRef);
        return name.to_str();
    }
}

extern {
    /*
     * CTFontTraits.h
     */

    // font trait constants
    const kCTFontSymbolicTrait: CFStringRef;
    const kCTFontWeightTrait: CFStringRef;
    const kCTFontWidthTrait: CFStringRef;
    const kCTFontSlantTrait: CFStringRef;

    /*
     * CTFontDescriptor.h
     */

    // font attribute constants
    const kCTFontURLAttribute: CFStringRef;
    const kCTFontNameAttribute: CFStringRef;
    const kCTFontDisplayNameAttribute: CFStringRef;
    const kCTFontFamilyNameAttribute: CFStringRef;
    const kCTFontStyleNameAttribute: CFStringRef;
    const kCTFontTraitsAttribute: CFStringRef;
    const kCTFontVariationAttribute: CFStringRef;
    const kCTFontSizeAttribute: CFStringRef;
    const kCTFontMatrixAttribute: CFStringRef;
    const kCTFontCascadeListAttribute: CFStringRef;
    const kCTFontCharacterSetAttribute: CFStringRef;
    const kCTFontLanguagesAttribute: CFStringRef;
    const kCTFontBaselineAdjustAttribute: CFStringRef;
    const kCTFontMacintoshEncodingsAttribute: CFStringRef;
    const kCTFontFeaturesAttribute: CFStringRef;
    const kCTFontFeatureSettingsAttribute: CFStringRef;
    const kCTFontFixedAdvanceAttribute: CFStringRef;
    const kCTFontOrientationAttribute: CFStringRef;
    const kCTFontFormatAttribute: CFStringRef;
    const kCTFontRegistrationScopeAttribute: CFStringRef;
    const kCTFontPriorityAttribute: CFStringRef;
    const kCTFontEnabledAttribute: CFStringRef;

    fn CTFontDescriptorCopyAttribute(descriptor: CTFontDescriptorRef, attribute: CFStringRef) -> CFTypeRef;
    fn CTFontDescriptorCopyAttributes(descriptor: CTFontDescriptorRef) -> CFDictionaryRef;
    fn CTFontDescriptorCopyLocalizedAttribute(descriptor: CTFontDescriptorRef, attribute: CFStringRef, language: *CFStringRef) -> CFTypeRef;
    fn CTFontDescriptorCreateCopyWithAttributes(original: CTFontDescriptorRef, attributes: CFDictionaryRef) -> CTFontDescriptorRef;
    fn CTFontDescriptorCreateCopyWithFeature(original: CTFontDescriptorRef, featureTypeIdentifier: CFNumberRef, featureSelectorIdentifier: CFNumberRef) -> CTFontDescriptorRef;
    fn CTFontDescriptorCreateCopyWithVariation(original: CTFontDescriptorRef, variationIdentifier: CFNumberRef, variationValue: CGFloat) -> CTFontDescriptorRef;
    fn CTFontDescriptorCreateMatchingFontDescriptor(descriptor: CTFontDescriptorRef, mandatoryAttributes: CFSetRef) -> CTFontDescriptorRef;
    fn CTFontDescriptorCreateMatchingFontDescriptors(descriptor: CTFontDescriptorRef, mandatoryAttributes: CFSetRef) -> CTFontDescriptorRef;
    fn CTFontDescriptorCreateWithAttributes(attributes: CFDictionaryRef) -> CTFontDescriptorRef;
    fn CTFontDescriptorCreateWithNameAndSize(name: CFStringRef, size: CGFloat) -> CTFontDescriptorRef;
    fn CTFontDescriptorGetTypeID() -> CFTypeID;
}<commit_msg>Add font_path(), and debug_descriptor()<commit_after>use cf = core_foundation;
use cf::array::CFArrayRef;
use cf::base::{
    AbstractCFType,
    AbstractCFTypeRef,
    CFAllocatorRef,
    CFIndex,
    CFGetTypeID,
    CFRange,
    CFRelease,
    CFTypeID,
    CFTypeOps,
    CFTypeRef,
    kCFAllocatorDefault,
};
use cf::dictionary::CFDictionaryRef;
use cf::number::CFNumberRef;
use cf::set::CFSetRef;
use cf::string::{
    CFString,
    CFStringRef,
    CFStringGetTypeID,
};
use cf::url::{
    CFURL,
    CFURLRef,
    CFURLGetTypeID,
};

use cg = core_graphics;
use cg::base::CGFloat;

use libc::c_void;

/*
* CTFontTraits.h
*/
// actually, these are extern enums
pub type CTFontFormat = u32;
pub const kCTFontFormatUnrecognized: CTFontFormat = 0;
pub const kCTFontFormatOpenTypePostScript: CTFontFormat = 1;
pub const kCTFontFormatOpenTypeTrueType: CTFontFormat = 2;
pub const kCTFontFormatTrueType: CTFontFormat = 3;
pub const kCTFontFormatPostScript: CTFontFormat = 4;
pub const kCTFontFormatBitmap: CTFontFormat = 5;

pub const kCTFontClassMaskShift: u32 = 28;

pub type CTFontSymbolicTraits = u32;
pub const kCTFontItalicTrait: CTFontSymbolicTraits = (1 << 0);
pub const kCTFontBoldTrait: CTFontSymbolicTraits = (1 << 1);
pub const kCTFontExpandedTrait: CTFontSymbolicTraits = (1 << 5);
pub const kCTFontCondensedTrait: CTFontSymbolicTraits = (1 << 6);
pub const kCTFontMonoSpaceTrait: CTFontSymbolicTraits = (1 << 10);
pub const kCTFontVerticalTrait: CTFontSymbolicTraits = (1 << 11);
pub const kCTFontUIOptimizedTrait: CTFontSymbolicTraits = (1 << 12);
pub const kCTFontClassMaskTrait: CTFontSymbolicTraits = (15 << kCTFontClassMaskShift);

pub type CTFontStylisticClass = u32;
pub const kCTFontUnknownClass: CTFontStylisticClass = (0 << kCTFontClassMaskShift);
pub const kCTFontOldStyleSerifsClass: CTFontStylisticClass = (1 << kCTFontClassMaskShift);
pub const kCTFontTransitionalSerifsClass: CTFontStylisticClass = (2 << kCTFontClassMaskShift);
pub const kCTFontModernSerifsClass: CTFontStylisticClass = (3 << kCTFontClassMaskShift);
pub const kCTFontClarendonSerifsClass: CTFontStylisticClass = (4 << kCTFontClassMaskShift);
pub const kCTFontSlabSerifsClass: CTFontStylisticClass = (5 << kCTFontClassMaskShift);
pub const kCTFontFreeformSerifsClass: CTFontStylisticClass = (7 << kCTFontClassMaskShift);
pub const kCTFontSansSerifClass: CTFontStylisticClass = (8 << kCTFontClassMaskShift);
pub const kCTFontOrnamentalsClass: CTFontStylisticClass = (9 << kCTFontClassMaskShift);
pub const kCTFontScriptsClass: CTFontStylisticClass = (10 << kCTFontClassMaskShift);
pub const kCTFontSymbolicClass: CTFontStylisticClass = (12 << kCTFontClassMaskShift);

/*
* CTFontDescriptor.h
*/
pub type CTFontOrientation = u32;
pub const kCTFontDefaultOrientation: CTFontOrientation = 0;
pub const kCTFontHorizontalOrientation: CTFontOrientation = 1;
pub const kCTFontVerticalOrientation: CTFontOrientation = 2;

pub type CTFontPriority = u32;
pub const kCTFontPrioritySystem: CTFontPriority = 10000;
pub const kCTFontPriorityNetwork: CTFontPriority = 20000;
pub const kCTFontPriorityComputer: CTFontPriority = 30000;
pub const kCTFontPriorityUser: CTFontPriority = 40000;
pub const kCTFontPriorityDynamic: CTFontPriority = 50000;
pub const kCTFontPriorityProcess: CTFontPriority = 60000;

struct __CTFontDescriptor { private: () }
pub type CTFontDescriptorRef = *__CTFontDescriptor;

impl CTFontDescriptorRef : AbstractCFTypeRef {
    pure fn as_type_ref(&self) -> CFTypeRef { *self as CFTypeRef }
}

struct CTFontDescriptor {
    obj: CTFontDescriptorRef,

    drop {
        unsafe {
            CFRelease(cast::transmute(self.obj))
        }
    }
}

pub impl CTFontDescriptor : AbstractCFType<CTFontDescriptorRef> {
    pure fn get_ref() -> CTFontDescriptorRef { self.obj }

    static fn wrap(obj: CTFontDescriptorRef) -> CTFontDescriptor {
        CTFontDescriptor { obj: obj }
    }

    static fn unwrap(wrapper: CTFontDescriptor) -> CTFontDescriptorRef {
        wrapper.obj
    }
}

pub impl CTFontDescriptor {
    fn family_name() -> ~str {
        let value = CTFontDescriptorCopyAttribute(self.obj, kCTFontDisplayNameAttribute);
        // family name should never be null.
        assert value.is_not_null();
        assert CFGetTypeID(value) == CFStringGetTypeID();

        let name : CFString = cf::base::wrap(value as CFStringRef);
        return name.to_str();
    }

    fn font_path() -> ~str {
        let value = CTFontDescriptorCopyAttribute(self.obj, kCTFontURLAttribute);
        assert value.is_not_null();
        assert CFGetTypeID(value) == CFURLGetTypeID();

        let cfurl : CFURL = cf::base::wrap(value as CFURLRef);
        return cfurl.to_str();
    }
}

pub fn debug_descriptor(desc: &CTFontDescriptor) {
    io::println(fmt!("family: %s", desc.family_name()));
    io::println(fmt!("path: %s", desc.font_path()));
    desc.show();
}

extern {
    /*
     * CTFontTraits.h
     */

    // font trait constants
    const kCTFontSymbolicTrait: CFStringRef;
    const kCTFontWeightTrait: CFStringRef;
    const kCTFontWidthTrait: CFStringRef;
    const kCTFontSlantTrait: CFStringRef;

    /*
     * CTFontDescriptor.h
     */

    // font attribute constants
    const kCTFontURLAttribute: CFStringRef;
    const kCTFontNameAttribute: CFStringRef;
    const kCTFontDisplayNameAttribute: CFStringRef;
    const kCTFontFamilyNameAttribute: CFStringRef;
    const kCTFontStyleNameAttribute: CFStringRef;
    const kCTFontTraitsAttribute: CFStringRef;
    const kCTFontVariationAttribute: CFStringRef;
    const kCTFontSizeAttribute: CFStringRef;
    const kCTFontMatrixAttribute: CFStringRef;
    const kCTFontCascadeListAttribute: CFStringRef;
    const kCTFontCharacterSetAttribute: CFStringRef;
    const kCTFontLanguagesAttribute: CFStringRef;
    const kCTFontBaselineAdjustAttribute: CFStringRef;
    const kCTFontMacintoshEncodingsAttribute: CFStringRef;
    const kCTFontFeaturesAttribute: CFStringRef;
    const kCTFontFeatureSettingsAttribute: CFStringRef;
    const kCTFontFixedAdvanceAttribute: CFStringRef;
    const kCTFontOrientationAttribute: CFStringRef;
    const kCTFontFormatAttribute: CFStringRef;
    const kCTFontRegistrationScopeAttribute: CFStringRef;
    const kCTFontPriorityAttribute: CFStringRef;
    const kCTFontEnabledAttribute: CFStringRef;

    fn CTFontDescriptorCopyAttribute(descriptor: CTFontDescriptorRef, attribute: CFStringRef) -> CFTypeRef;
    fn CTFontDescriptorCopyAttributes(descriptor: CTFontDescriptorRef) -> CFDictionaryRef;
    fn CTFontDescriptorCopyLocalizedAttribute(descriptor: CTFontDescriptorRef, attribute: CFStringRef, language: *CFStringRef) -> CFTypeRef;
    fn CTFontDescriptorCreateCopyWithAttributes(original: CTFontDescriptorRef, attributes: CFDictionaryRef) -> CTFontDescriptorRef;
    fn CTFontDescriptorCreateCopyWithFeature(original: CTFontDescriptorRef, featureTypeIdentifier: CFNumberRef, featureSelectorIdentifier: CFNumberRef) -> CTFontDescriptorRef;
    fn CTFontDescriptorCreateCopyWithVariation(original: CTFontDescriptorRef, variationIdentifier: CFNumberRef, variationValue: CGFloat) -> CTFontDescriptorRef;
    fn CTFontDescriptorCreateMatchingFontDescriptor(descriptor: CTFontDescriptorRef, mandatoryAttributes: CFSetRef) -> CTFontDescriptorRef;
    fn CTFontDescriptorCreateMatchingFontDescriptors(descriptor: CTFontDescriptorRef, mandatoryAttributes: CFSetRef) -> CTFontDescriptorRef;
    fn CTFontDescriptorCreateWithAttributes(attributes: CFDictionaryRef) -> CTFontDescriptorRef;
    fn CTFontDescriptorCreateWithNameAndSize(name: CFStringRef, size: CGFloat) -> CTFontDescriptorRef;
    fn CTFontDescriptorGetTypeID() -> CFTypeID;
}<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

//!
//! This module exposes two types of sockets useful for tests:
//! - ReadOnlyTestSocket: a socket that can be read from in different ways.
//! - ReadWriteTestSocket: a similar wrapper but around MemorySocket to retrieve handshake messages being sent as well.
//!

use futures::{
    io::{AsyncRead, AsyncWrite},
    ready,
    task::{Context, Poll},
};
use memsocket::MemorySocket;
use std::{io, pin::Pin};

//
// ReadOnlyTestSocket
// ==================
//

#[derive(Debug)]
pub struct ReadOnlyTestSocket<'a> {
    /// the content
    content: &'a [u8],
    /// the socket will read byte-by-byte
    fragmented: bool,
    /// continue to read 0s once content has been fully read
    trailing: bool,
}

impl<'a> ReadOnlyTestSocket<'a> {
    pub fn new(content: &'a [u8]) -> Self {
        Self {
            content,
            fragmented: false,
            trailing: false,
        }
    }

    /// reads will have to be done byte by byte
    pub fn set_fragmented_read(&mut self) {
        self.fragmented = true;
    }

    /// reads will never return pending, but 0s
    pub fn set_trailing(&mut self) {
        self.trailing = true;
    }
}

/// Does nothing, but looks to the caller as if write worked
impl<'a> AsyncWrite for ReadOnlyTestSocket<'a> {
    fn poll_write(
        self: Pin<&mut Self>,
        _context: &mut Context,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        Poll::Ready(Ok(buf.len()))
    }

    fn poll_flush(self: Pin<&mut Self>, _context: &mut Context) -> Poll<io::Result<()>> {
        Poll::Ready(Ok(()))
    }

    /// Attempt to close the channel. Cannot Fail.
    fn poll_close(self: Pin<&mut Self>, _context: &mut Context) -> Poll<io::Result<()>> {
        Poll::Ready(Ok(()))
    }
}

/// Read based on the mode set
impl<'a> AsyncRead for ReadOnlyTestSocket<'a> {
    fn poll_read(
        mut self: Pin<&mut Self>,
        mut _context: &mut Context,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        // nothing left to read
        if self.content.is_empty() {
            if self.trailing {
                // [0, 0, 0, 0, ...]
                for val in buf.iter_mut() {
                    *val = 0;
                }
                return Poll::Ready(Ok(buf.len()));
            } else {
                // EOF
                return Poll::Ready(Ok(0));
            }
        }

        // if something left return what's asked
        if self.fragmented {
            // read only one byte
            let (read, content) = self.content.split_at(1);
            buf[0] = read[0];

            // update internal state
            self.content = content;

            // return 1 byte
            Poll::Ready(Ok(1))
        } else {
            // read as much as we can
            let to_read = std::cmp::min(buf.len(), self.content.len());
            buf[..to_read].copy_from_slice(&self.content[..to_read]);

            // update internal state
            self.content = &self.content[to_read..self.content.len()];

            // return length read
            Poll::Ready(Ok(to_read))
        }
    }
}

//
// ReadOnlyTestSocket but with a static lifetime (useful to really replace a socket)
//

#[derive(Debug)]
pub struct ReadOnlyTestSocketVec {
    /// the content
    content: Vec<u8>,
    /// the socket will read byte-by-byte
    fragmented: bool,
    /// continue to read 0s once content has been fully read
    trailing: bool,
}

impl ReadOnlyTestSocketVec {
    pub fn new(content: Vec<u8>) -> Self {
        Self {
            content,
            fragmented: false,
            trailing: false,
        }
    }

    /// reads will have to be done byte by byte
    #[allow(dead_code)]
    pub fn set_fragmented_read(&mut self) {
        self.fragmented = true;
    }

    /// reads will never return pending, but 0s
    #[allow(dead_code)]
    pub fn set_trailing(&mut self) {
        self.trailing = true;
    }
}

/// Does nothing, but looks to the caller as if write worked
impl AsyncWrite for ReadOnlyTestSocketVec {
    fn poll_write(
        self: Pin<&mut Self>,
        _context: &mut Context,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        Poll::Ready(Ok(buf.len()))
    }

    fn poll_flush(self: Pin<&mut Self>, _context: &mut Context) -> Poll<io::Result<()>> {
        Poll::Ready(Ok(()))
    }

    /// Attempt to close the channel. Cannot Fail.
    fn poll_close(self: Pin<&mut Self>, _context: &mut Context) -> Poll<io::Result<()>> {
        Poll::Ready(Ok(()))
    }
}

/// Read based on the mode set
impl AsyncRead for ReadOnlyTestSocketVec {
    fn poll_read(
        mut self: Pin<&mut Self>,
        mut _context: &mut Context,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        // nothing left to read
        if self.content.is_empty() {
            if self.trailing {
                // [0, 0, 0, 0, ...]
                for val in buf.iter_mut() {
                    *val = 0;
                }
                return Poll::Ready(Ok(buf.len()));
            } else {
                // EOF
                return Poll::Ready(Ok(0));
            }
        }

        // if something left return what's asked
        if self.fragmented {
            // read only one byte
            buf[0] = self.content[0];

            // update internal state
            self.content = self.content.split_off(1);

            // return 1 byte
            Poll::Ready(Ok(1))
        } else {
            // read as much as we can
            let to_read = std::cmp::min(buf.len(), self.content.len());
            buf[..to_read].copy_from_slice(&self.content[..to_read]);

            // update internal state
            self.content = self.content.split_off(to_read);

            // return length read
            Poll::Ready(Ok(to_read))
        }
    }
}

//
// ReadWriteTestSocket
// ==================
//

#[derive(Debug)]
pub struct ReadWriteTestSocket<'a> {
    /// an in-memory socket
    inner: MemorySocket,
    /// useful to save what was written on the socket
    written: Option<&'a mut Vec<u8>>,
    /// fragment reads byte by byte
    fragmented: bool,
}

impl<'a> ReadWriteTestSocket<'a> {
    fn new(memory_socket: MemorySocket) -> Self {
        Self {
            inner: memory_socket,
            written: None,
            fragmented: false,
        }
    }

    /// the vec passed as argument will expand to store any writes on the socket
    pub fn save_writing(&mut self, buf: &'a mut Vec<u8>) {
        self.written = Some(buf);
    }

    /// reads will have to be done byte by byte
    #[allow(dead_code)]
    pub fn set_fragmented_read(&mut self) {
        self.fragmented = true;
    }

    /// Creates a new pair of sockets
    pub fn new_pair() -> (Self, Self) {
        let (dialer_socket, listener_socket) = MemorySocket::new_pair();
        (
            ReadWriteTestSocket::new(dialer_socket),
            ReadWriteTestSocket::new(listener_socket),
        )
    }
}

impl<'a> AsyncWrite for ReadWriteTestSocket<'a> {
    fn poll_write(
        mut self: Pin<&mut Self>,
        context: &mut Context,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        let bytes_written = ready!(Pin::new(&mut self.inner).poll_write(context, buf))?;

        if let Some(v) = self.written.as_mut() {
            v.extend_from_slice(&buf[..bytes_written])
        }
        Poll::Ready(Ok(bytes_written))
    }

    fn poll_flush(mut self: Pin<&mut Self>, context: &mut Context) -> Poll<io::Result<()>> {
        Pin::new(&mut self.inner).poll_flush(context)
    }

    /// Attempt to close the channel. Cannot Fail.
    fn poll_close(mut self: Pin<&mut Self>, context: &mut Context) -> Poll<io::Result<()>> {
        Pin::new(&mut self.inner).poll_close(context)
    }
}

impl<'a> AsyncRead for ReadWriteTestSocket<'a> {
    fn poll_read(
        mut self: Pin<&mut Self>,
        context: &mut Context,
        buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        // read from inner sockets
        if self.fragmented {
            // fragmented: read only one byte
            let mut buf_byte = [0u8];
            let poll_res = Pin::new(&mut self.inner).poll_read(context, &mut buf_byte);
            if poll_res.is_ready() {
                buf[0] = buf_byte[0];
            }
            poll_res
        } else {
            // read normally
            Pin::new(&mut self.inner).poll_read(context, buf)
        }
    }
}

//
// Tests
// =====
//

#[cfg(test)]
mod tests {
    use super::*;
    use futures::{
        executor::block_on,
        io::{AsyncReadExt, AsyncWriteExt},
    };

    #[test]
    fn test_normal_reads() {
        let a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
        let mut socket = ReadOnlyTestSocket::new(&a);

        block_on(async {
            let mut buf = [0u8; 10];
            socket.read_exact(&mut buf).await.unwrap();
            assert!(buf == a);
        });
    }

    #[test]
    fn test_fragmented_reads() {
        let a = [1, 2, 3, 4, 5];
        let mut socket = ReadOnlyTestSocket::new(&a);
        socket.set_fragmented_read();

        block_on(async {
            let mut buf = [9u8; 10];
            for i in 1..=5 {
                let read = socket.read(&mut buf).await.unwrap();
                assert!(read == 1);
                assert!(buf[0] == i);
            }
        });
    }

    #[test]
    fn test_trailing_reads() {
        let a = [1, 2, 3, 4, 5];
        let mut socket = ReadOnlyTestSocket::new(&a);
        socket.set_trailing();

        block_on(async {
            let mut buf = [0u8; 10];
            socket.read_exact(&mut buf).await.unwrap();
            assert!(buf[..5] == a);
            assert!(buf[5..] == [0u8, 0, 0, 0, 0]);
        });
    }

    #[test]
    fn test_fragmented_exposed_socket() {
        block_on(async {
            let (mut dialer, mut listener) = ReadWriteTestSocket::new_pair();
            let mut init_msg = Vec::new();
            let mut resp_msg = Vec::new();

            // save writes
            dialer.save_writing(&mut init_msg);
            listener.save_writing(&mut resp_msg);

            // fragment reads
            dialer.set_fragmented_read();
            listener.set_fragmented_read();

            let first_message = [1u8, 2, 3, 4, 5];
            let second_message = [6u8, 7, 8, 9, 10];

            // dialer sends first message
            let written = dialer.write(&first_message).await.unwrap();
            assert_eq!(written, first_message.len());

            // listener reads byte-by-byte
            let mut buf = [0u8; 5];
            for i in 1..=5 {
                let read = listener.read(&mut buf).await.unwrap();
                assert!(read == 1);
                assert!(buf[0] == i);
            }

            // listener responds with second message
            let written = listener.write(&second_message).await.unwrap();
            assert_eq!(written, second_message.len());

            // dialer reads byte-by-byte
            for i in 6..=10 {
                let read = dialer.read(&mut buf).await.unwrap();
                assert!(read == 1);
                assert!(buf[0] == i);
            }

            // did we record the writes correctly?
            assert!(init_msg.as_slice() == first_message);
            assert!(resp_msg.as_slice() == second_message);
        });
    }
}
<commit_msg>[network] Add fragmented write support to fake sockets<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

//!
//! This module exposes two types of sockets useful for tests:
//! - ReadOnlyTestSocket: a socket that can be read from in different ways.
//! - ReadWriteTestSocket: a similar wrapper but around MemorySocket to retrieve handshake messages being sent as well.
//!

use futures::{
    io::{AsyncRead, AsyncWrite},
    ready,
    task::{Context, Poll},
};
use memsocket::MemorySocket;
use std::{io, pin::Pin};

//
// ReadOnlyTestSocket
// ==================
//

#[derive(Debug)]
pub struct ReadOnlyTestSocket<'a> {
    /// the content
    content: &'a [u8],
    /// fragment reads byte-by-byte
    fragmented_read: bool,
    /// continue to read 0s once content has been fully read
    trailing: bool,
}

impl<'a> ReadOnlyTestSocket<'a> {
    pub fn new(content: &'a [u8]) -> Self {
        Self {
            content,
            fragmented_read: false,
            trailing: false,
        }
    }

    /// reads will be done byte-by-byte
    pub fn set_fragmented_read(&mut self) {
        self.fragmented_read = true;
    }

    /// reads will never return pending, but 0s
    pub fn set_trailing(&mut self) {
        self.trailing = true;
    }
}

/// Does nothing, but looks to the caller as if write worked
impl<'a> AsyncWrite for ReadOnlyTestSocket<'a> {
    fn poll_write(
        self: Pin<&mut Self>,
        _context: &mut Context,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        Poll::Ready(Ok(buf.len()))
    }

    fn poll_flush(self: Pin<&mut Self>, _context: &mut Context) -> Poll<io::Result<()>> {
        Poll::Ready(Ok(()))
    }

    /// Attempt to close the channel. Cannot Fail.
    fn poll_close(self: Pin<&mut Self>, _context: &mut Context) -> Poll<io::Result<()>> {
        Poll::Ready(Ok(()))
    }
}

/// Read based on the mode set
impl<'a> AsyncRead for ReadOnlyTestSocket<'a> {
    fn poll_read(
        mut self: Pin<&mut Self>,
        mut _context: &mut Context,
        mut buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        // read/recv on an empty buffer is underspecified
        assert!(!buf.is_empty());

        if self.fragmented_read {
            buf = &mut buf[..1];
        }

        // nothing left to read
        if self.content.is_empty() {
            if self.trailing {
                // [0, 0, 0, 0, ...]
                for val in buf.iter_mut() {
                    *val = 0;
                }
                return Poll::Ready(Ok(buf.len()));
            } else {
                // EOF
                return Poll::Ready(Ok(0));
            }
        }

        // read as much as we can
        let to_read = std::cmp::min(buf.len(), self.content.len());
        buf[..to_read].copy_from_slice(&self.content[..to_read]);

        // update internal buffer
        self.content = &self.content[to_read..self.content.len()];

        Poll::Ready(Ok(to_read))
    }
}

//
// ReadOnlyTestSocket but with a static lifetime (useful to really replace a socket)
//

#[derive(Debug)]
pub struct ReadOnlyTestSocketVec {
    /// the content
    content: Vec<u8>,
    /// fragment reads byte-by-byte
    fragmented_read: bool,
    /// continue to read 0s once content has been fully read
    trailing: bool,
}

impl ReadOnlyTestSocketVec {
    pub fn new(content: Vec<u8>) -> Self {
        Self {
            content,
            fragmented_read: false,
            trailing: false,
        }
    }

    /// reads will be done byte-by-byte
    #[allow(dead_code)]
    pub fn set_fragmented_read(&mut self) {
        self.fragmented_read = true;
    }

    /// reads will never return pending, but 0s
    pub fn set_trailing(&mut self) {
        self.trailing = true;
    }
}

/// Does nothing, but looks to the caller as if write worked
impl AsyncWrite for ReadOnlyTestSocketVec {
    fn poll_write(
        self: Pin<&mut Self>,
        _context: &mut Context,
        buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        Poll::Ready(Ok(buf.len()))
    }

    fn poll_flush(self: Pin<&mut Self>, _context: &mut Context) -> Poll<io::Result<()>> {
        Poll::Ready(Ok(()))
    }

    /// Attempt to close the channel. Cannot Fail.
    fn poll_close(self: Pin<&mut Self>, _context: &mut Context) -> Poll<io::Result<()>> {
        Poll::Ready(Ok(()))
    }
}

/// Read based on the mode set
impl AsyncRead for ReadOnlyTestSocketVec {
    fn poll_read(
        mut self: Pin<&mut Self>,
        mut _context: &mut Context,
        mut buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        // read/recv on an empty buffer is underspecified
        assert!(!buf.is_empty());

        if self.fragmented_read {
            buf = &mut buf[..1];
        }

        // nothing left to read
        if self.content.is_empty() {
            if self.trailing {
                // [0, 0, 0, 0, ...]
                for val in buf.iter_mut() {
                    *val = 0;
                }
                return Poll::Ready(Ok(buf.len()));
            } else {
                // EOF
                return Poll::Ready(Ok(0));
            }
        }

        // read as much as we can
        let to_read = std::cmp::min(buf.len(), self.content.len());
        buf[..to_read].copy_from_slice(&self.content[..to_read]);

        // update internal buffer
        self.content = self.content.split_off(to_read);

        Poll::Ready(Ok(to_read))
    }
}

//
// ReadWriteTestSocket
// ==================
//

#[derive(Debug)]
pub struct ReadWriteTestSocket<'a> {
    /// an in-memory socket
    inner: MemorySocket,
    /// useful to save what was written on the socket
    written: Option<&'a mut Vec<u8>>,
    /// fragment reads byte-by-byte
    fragmented_read: bool,
    /// fragment writes byte-by-byte
    fragmented_write: bool,
}

impl<'a> ReadWriteTestSocket<'a> {
    fn new(memory_socket: MemorySocket) -> Self {
        Self {
            inner: memory_socket,
            written: None,
            fragmented_read: false,
            fragmented_write: false,
        }
    }

    /// the vec passed as argument will expand to store any writes on the socket
    pub fn save_writing(&mut self, buf: &'a mut Vec<u8>) {
        self.written = Some(buf);
    }

    /// reads will be done byte-by-byte
    pub fn set_fragmented_read(&mut self) {
        self.fragmented_read = true;
    }

    /// writes will be done byte-by-byte
    pub fn set_fragmented_write(&mut self) {
        self.fragmented_write = true;
    }

    /// Creates a new pair of sockets
    pub fn new_pair() -> (Self, Self) {
        let (dialer_socket, listener_socket) = MemorySocket::new_pair();
        (
            ReadWriteTestSocket::new(dialer_socket),
            ReadWriteTestSocket::new(listener_socket),
        )
    }
}

impl<'a> AsyncWrite for ReadWriteTestSocket<'a> {
    fn poll_write(
        mut self: Pin<&mut Self>,
        context: &mut Context,
        mut buf: &[u8],
    ) -> Poll<io::Result<usize>> {
        if self.fragmented_write {
            buf = &buf[..1];
        }

        // write buf
        let bytes_written = ready!(Pin::new(&mut self.inner).poll_write(context, buf))?;

        // record write if needed
        if let Some(v) = self.written.as_mut() {
            v.extend_from_slice(&buf[..bytes_written])
        }

        Poll::Ready(Ok(bytes_written))
    }

    fn poll_flush(mut self: Pin<&mut Self>, context: &mut Context) -> Poll<io::Result<()>> {
        Pin::new(&mut self.inner).poll_flush(context)
    }

    /// Attempt to close the channel. Cannot Fail.
    fn poll_close(mut self: Pin<&mut Self>, context: &mut Context) -> Poll<io::Result<()>> {
        Pin::new(&mut self.inner).poll_close(context)
    }
}

impl<'a> AsyncRead for ReadWriteTestSocket<'a> {
    fn poll_read(
        mut self: Pin<&mut Self>,
        context: &mut Context,
        mut buf: &mut [u8],
    ) -> Poll<io::Result<usize>> {
        // read/recv on an empty buffer is underspecified
        assert!(!buf.is_empty());

        if self.fragmented_read {
            buf = &mut buf[..1];
        }

        Pin::new(&mut self.inner).poll_read(context, buf)
    }
}

//
// Tests
// =====
//

#[cfg(test)]
mod tests {
    use super::*;
    use futures::{
        executor::block_on,
        future,
        io::{AsyncReadExt, AsyncWriteExt},
    };

    #[test]
    fn test_normal_reads() {
        let a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
        let mut socket = ReadOnlyTestSocket::new(&a);

        block_on(async {
            let mut buf = [0u8; 10];
            socket.read_exact(&mut buf).await.unwrap();
            assert!(buf == a);
        });
    }

    #[test]
    fn test_fragmented_reads() {
        let a = [1, 2, 3, 4, 5];
        let mut socket = ReadOnlyTestSocket::new(&a);
        socket.set_fragmented_read();

        block_on(async {
            let mut buf = [9u8; 10];
            for i in 1..=5 {
                let read = socket.read(&mut buf).await.unwrap();
                assert!(read == 1);
                assert!(buf[0] == i);
            }
        });
    }

    #[test]
    fn test_fragmented_writes() {
        let (mut tx, mut rx) = ReadWriteTestSocket::new_pair();
        let mut tx_writes = Vec::new();
        tx.set_fragmented_write();
        tx.save_writing(&mut tx_writes);

        let msg = b"12345";
        let f_write = async {
            for i in 0..msg.len() {
                let write = tx.write(&msg[i..]).await.unwrap();
                assert_eq!(write, 1);
                // satisfy borrow checker...
                let tx_writes = tx.written.as_ref().unwrap();
                assert_eq!(&tx_writes[..], &msg[..i + 1]);
            }
            tx.close().await.unwrap();
        };

        let f_read = async {
            let mut read_buf = Vec::new();
            let read = rx.read_to_end(&mut read_buf).await.unwrap();
            assert_eq!(read, msg.len());
            assert_eq!(&read_buf[..], &msg[..]);
        };

        block_on(future::join(f_write, f_read));
    }

    #[test]
    fn test_trailing_reads() {
        let a = [1, 2, 3, 4, 5];
        let mut socket = ReadOnlyTestSocket::new(&a);
        socket.set_trailing();

        block_on(async {
            let mut buf = [0u8; 10];
            socket.read_exact(&mut buf).await.unwrap();
            assert!(buf[..5] == a);
            assert!(buf[5..] == [0u8, 0, 0, 0, 0]);
        });
    }

    #[test]
    fn test_fragmented_exposed_socket() {
        block_on(async {
            let (mut dialer, mut listener) = ReadWriteTestSocket::new_pair();
            let mut init_msg = Vec::new();
            let mut resp_msg = Vec::new();

            // save writes
            dialer.save_writing(&mut init_msg);
            listener.save_writing(&mut resp_msg);

            // fragment reads
            dialer.set_fragmented_read();
            listener.set_fragmented_read();

            let first_message = [1u8, 2, 3, 4, 5];
            let second_message = [6u8, 7, 8, 9, 10];

            // dialer sends first message
            let written = dialer.write(&first_message).await.unwrap();
            assert_eq!(written, first_message.len());

            // listener reads byte-by-byte
            let mut buf = [0u8; 5];
            for i in 1..=5 {
                let read = listener.read(&mut buf).await.unwrap();
                assert!(read == 1);
                assert!(buf[0] == i);
            }

            // listener responds with second message
            let written = listener.write(&second_message).await.unwrap();
            assert_eq!(written, second_message.len());

            // dialer reads byte-by-byte
            for i in 6..=10 {
                let read = dialer.read(&mut buf).await.unwrap();
                assert!(read == 1);
                assert!(buf[0] == i);
            }

            // did we record the writes correctly?
            assert!(init_msg.as_slice() == first_message);
            assert!(resp_msg.as_slice() == second_message);
        });
    }
}
<|endoftext|>


<commit_before>macro_rules! ast_struct {
    (
        [$($attrs_pub:tt)*]
        struct $name:ident #full $($rest:tt)*
    ) => {
        #[cfg(feature = "full")]
        $($attrs_pub)* struct $name $($rest)*

        #[cfg(not(feature = "full"))]
        $($attrs_pub)* struct $name {
            _noconstruct: ::std::marker::PhantomData<::proc_macro2::Span>,
        }

        #[cfg(all(not(feature = "full"), feature = "printing"))]
        impl ::quote::ToTokens for $name {
            fn to_tokens(&self, _: &mut ::proc_macro2::TokenStream) {
                unreachable!()
            }
        }
    };

    (
        [$($attrs_pub:tt)*]
        struct $name:ident $($rest:tt)*
    ) => {
        $($attrs_pub)* struct $name $($rest)*
    };

    ($($t:tt)*) => {
        strip_attrs_pub!(ast_struct!($($t)*));
    };
}

macro_rules! ast_enum {
    // Drop the `#no_visit` attribute, if present.
    (
        [$($attrs_pub:tt)*]
        enum $name:ident #no_visit $($rest:tt)*
    ) => (
        ast_enum!([$($attrs_pub)*] enum $name $($rest)*);
    );

    (
        [$($attrs_pub:tt)*]
        enum $name:ident $($rest:tt)*
    ) => (
        $($attrs_pub)* enum $name $($rest)*
    );

    ($($t:tt)*) => {
        strip_attrs_pub!(ast_enum!($($t)*));
    };
}

macro_rules! ast_enum_of_structs {
    (
        $(#[$enum_attr:meta])*
        $pub:ident $enum:ident $name:ident $body:tt
        $($remaining:tt)*
    ) => {
        ast_enum!($(#[$enum_attr])* $pub $enum $name $body);
        ast_enum_of_structs_impl!($pub $enum $name $body $($remaining)*);
    };
}

macro_rules! ast_enum_of_structs_impl {
    (
        $pub:ident $enum:ident $name:ident {
            $(
                $(#[cfg $cfg_attr:tt])*
                $(#[doc $($doc_attr:tt)*])*
                $variant:ident $( ($($member:ident)::+) )*,
            )*
        }

        $($remaining:tt)*
    ) => {
        check_keyword_matches!(pub $pub);
        check_keyword_matches!(enum $enum);

        $($(
            ast_enum_from_struct!($name::$variant, $($member)::+);
        )*)*

        #[cfg(feature = "printing")]
        generate_to_tokens! {
            $($remaining)*
            ()
            tokens
            $name {
                $(
                    $(#[cfg $cfg_attr])*
                    $(#[doc $($doc_attr)*])*
                    $variant $($($member)::+)*,
                )*
            }
        }
    };
}

macro_rules! ast_enum_from_struct {
    // No From<TokenStream> for verbatim variants.
    ($name:ident::Verbatim, $member:ident) => {};

    ($name:ident::$variant:ident, $member:ident) => {
        impl From<$member> for $name {
            fn from(e: $member) -> $name {
                $name::$variant(e)
            }
        }
    };
}

#[cfg(feature = "printing")]
macro_rules! generate_to_tokens {
    (do_not_generate_to_tokens $($foo:tt)*) => ();

    (
        ($($arms:tt)*) $tokens:ident $name:ident {
            $(#[cfg $cfg_attr:tt])*
            $(#[doc $($doc_attr:tt)*])*
            $variant:ident,
            $($next:tt)*
        }
    ) => {
        generate_to_tokens!(
            ($($arms)* $(#[cfg $cfg_attr])* $name::$variant => {})
            $tokens $name { $($next)* }
        );
    };

    (
        ($($arms:tt)*) $tokens:ident $name:ident {
            $(#[cfg $cfg_attr:tt])*
            $(#[doc $($doc_attr:tt)*])*
            $variant:ident $member:ident,
            $($next:tt)*
        }
    ) => {
        generate_to_tokens!(
            ($($arms)* $(#[cfg $cfg_attr])* $name::$variant(_e) => _e.to_tokens($tokens),)
            $tokens $name { $($next)* }
        );
    };

    (($($arms:tt)*) $tokens:ident $name:ident {}) => {
        #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
        impl ::quote::ToTokens for $name {
            fn to_tokens(&self, $tokens: &mut ::proc_macro2::TokenStream) {
                match self {
                    $($arms)*
                }
            }
        }
    };
}

macro_rules! strip_attrs_pub {
    ($mac:ident!($(#[$m:meta])* $pub:ident $($t:tt)*)) => {
        check_keyword_matches!(pub $pub);

        $mac!([$(#[$m])* $pub] $($t)*);
    };
}

macro_rules! check_keyword_matches {
    (enum enum) => {};
    (pub pub) => {};
}
<commit_msg>Fix unused macro rule in no-default-features mode<commit_after>#[allow(unknown_lints)]
#[cfg_attr(not(any(feature = "full", feature = "derive")), allow(unused_macro_rules))]
macro_rules! ast_struct {
    (
        [$($attrs_pub:tt)*]
        struct $name:ident #full $($rest:tt)*
    ) => {
        #[cfg(feature = "full")]
        $($attrs_pub)* struct $name $($rest)*

        #[cfg(not(feature = "full"))]
        $($attrs_pub)* struct $name {
            _noconstruct: ::std::marker::PhantomData<::proc_macro2::Span>,
        }

        #[cfg(all(not(feature = "full"), feature = "printing"))]
        impl ::quote::ToTokens for $name {
            fn to_tokens(&self, _: &mut ::proc_macro2::TokenStream) {
                unreachable!()
            }
        }
    };

    (
        [$($attrs_pub:tt)*]
        struct $name:ident $($rest:tt)*
    ) => {
        $($attrs_pub)* struct $name $($rest)*
    };

    ($($t:tt)*) => {
        strip_attrs_pub!(ast_struct!($($t)*));
    };
}

macro_rules! ast_enum {
    // Drop the `#no_visit` attribute, if present.
    (
        [$($attrs_pub:tt)*]
        enum $name:ident #no_visit $($rest:tt)*
    ) => (
        ast_enum!([$($attrs_pub)*] enum $name $($rest)*);
    );

    (
        [$($attrs_pub:tt)*]
        enum $name:ident $($rest:tt)*
    ) => (
        $($attrs_pub)* enum $name $($rest)*
    );

    ($($t:tt)*) => {
        strip_attrs_pub!(ast_enum!($($t)*));
    };
}

macro_rules! ast_enum_of_structs {
    (
        $(#[$enum_attr:meta])*
        $pub:ident $enum:ident $name:ident $body:tt
        $($remaining:tt)*
    ) => {
        ast_enum!($(#[$enum_attr])* $pub $enum $name $body);
        ast_enum_of_structs_impl!($pub $enum $name $body $($remaining)*);
    };
}

macro_rules! ast_enum_of_structs_impl {
    (
        $pub:ident $enum:ident $name:ident {
            $(
                $(#[cfg $cfg_attr:tt])*
                $(#[doc $($doc_attr:tt)*])*
                $variant:ident $( ($($member:ident)::+) )*,
            )*
        }

        $($remaining:tt)*
    ) => {
        check_keyword_matches!(pub $pub);
        check_keyword_matches!(enum $enum);

        $($(
            ast_enum_from_struct!($name::$variant, $($member)::+);
        )*)*

        #[cfg(feature = "printing")]
        generate_to_tokens! {
            $($remaining)*
            ()
            tokens
            $name {
                $(
                    $(#[cfg $cfg_attr])*
                    $(#[doc $($doc_attr)*])*
                    $variant $($($member)::+)*,
                )*
            }
        }
    };
}

macro_rules! ast_enum_from_struct {
    // No From<TokenStream> for verbatim variants.
    ($name:ident::Verbatim, $member:ident) => {};

    ($name:ident::$variant:ident, $member:ident) => {
        impl From<$member> for $name {
            fn from(e: $member) -> $name {
                $name::$variant(e)
            }
        }
    };
}

#[cfg(feature = "printing")]
macro_rules! generate_to_tokens {
    (do_not_generate_to_tokens $($foo:tt)*) => ();

    (
        ($($arms:tt)*) $tokens:ident $name:ident {
            $(#[cfg $cfg_attr:tt])*
            $(#[doc $($doc_attr:tt)*])*
            $variant:ident,
            $($next:tt)*
        }
    ) => {
        generate_to_tokens!(
            ($($arms)* $(#[cfg $cfg_attr])* $name::$variant => {})
            $tokens $name { $($next)* }
        );
    };

    (
        ($($arms:tt)*) $tokens:ident $name:ident {
            $(#[cfg $cfg_attr:tt])*
            $(#[doc $($doc_attr:tt)*])*
            $variant:ident $member:ident,
            $($next:tt)*
        }
    ) => {
        generate_to_tokens!(
            ($($arms)* $(#[cfg $cfg_attr])* $name::$variant(_e) => _e.to_tokens($tokens),)
            $tokens $name { $($next)* }
        );
    };

    (($($arms:tt)*) $tokens:ident $name:ident {}) => {
        #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
        impl ::quote::ToTokens for $name {
            fn to_tokens(&self, $tokens: &mut ::proc_macro2::TokenStream) {
                match self {
                    $($arms)*
                }
            }
        }
    };
}

macro_rules! strip_attrs_pub {
    ($mac:ident!($(#[$m:meta])* $pub:ident $($t:tt)*)) => {
        check_keyword_matches!(pub $pub);

        $mac!([$(#[$m])* $pub] $($t)*);
    };
}

macro_rules! check_keyword_matches {
    (enum enum) => {};
    (pub pub) => {};
}
<|endoftext|>


<commit_before>/// Gets the offset of a field. Used by container_of!
#[macro_export]
macro_rules! offset_of(
    ($ty:ty, $field:ident) => {
        &(*(0 as *const $ty)).$field as *const _ as usize
    }
);

/// Gets the parent struct from a pointer.
/// VERY unsafe. The parent struct _must_ be repr(C), and the
/// type passed to this macro _must_ match the type of the parent.
#[macro_export]
macro_rules! container_of (
    ($ptr: expr, $container: ty, $field: ident) => {
        ($ptr as *mut u8).offset(-(offset_of!($container, $field) as isize)) as *mut $container
    }
);

/// Convert a literal string to a C string.
/// Note: Does not check for internal nulls, nor does it do any conversions on
/// the grapheme clustors. Just passes the bytes as is.
/// So probably only works on ASCII.
#[macro_export]
macro_rules! c_str {
    ($s:expr) => {
        concat!($s, "\0").as_ptr() as *const i8
    }
}

#[macro_export]
/// Logs a message using wlroots' logging capability.
macro_rules! wlr_log {
    ($verb: expr, $($msg:tt)*) => {{
        use $crate::wlroots_sys::_wlr_log;
        use $crate::wlroots_sys::log_importance_t::*;
        use ::std::ffi::CString;
        unsafe {
            let fmt = CString::new(format!($($msg)*))
                .expect("Could not convert log message to C string");
            let raw = fmt.into_raw();
            _wlr_log($verb, c_str!("[%s:%lu] %s"),
                    c_str!(file!()), line!(), raw);
            // Deallocate string
            CString::from_raw(raw);
        }
    }}
}

/// Defines a new struct that contains a variable number of listeners that
/// will trigger unsafe user-defined callbacks.
///
/// The structure that is defined is repr(C), has one `data` field with the
/// given user type, and a field for each `$listener`.
///
/// Each `$listener` has a getter method that lets you get the pointer to the
/// listener. This method is unsafe, since it returns a raw pointer.
/// To use it correctly, you need to ensure that the data it refers to never
/// moves (e.g keep it in a box). The primary purpose of this method is to pass
/// the listener pointer to other methods to register it for a Wayland event.
/// **A listener can only be registered to one event at a time**.
///
/// Finally, it also takes in a body for each `$listener` that is called
/// every time the event that is later hooked up to it is fired.
/// This method is inherently unsafe, because the user data hasn't been cast
/// from the void pointer yet. It is the user's job to write this safely.
/// To highlight this fact, the body of the function must be prefixed with
/// `unsafe`.
///
/// # Example
/// ```
/// // Handles input addition and removal.
/// pub trait InputManagerHandler {
///     // Callback triggered when an input device is added.
///     fn input_added(&mut self, Device);
/// }
/// wayland_listener!(
///     // The name of the structure that will be defined.
///     InputManager,
///     // The type that's stored in the `data` field.
///     // Note that we use a Box here to achieve dynamic dispatch,
///     // it's not required for this type to be in a box.
///     Box<InputManagerHandler>,
///     [
///         // Adds a new listener called `add_listener`.
///         add_listener =>
///         // Adds an unsafe function called `add_notify` that is triggered
///         // whenever add_listener is activated from a Wayland event.
///         add_notify: |input_manager: &mut Box<InputManagerHandler>,
///                      data: *mut libc::c_void,| unsafe {
/// // Call the method defined above, wrapping it in a safe
/// interface.
/// // It is your job to ensure that the code in here doesn't
/// trigger UB!
/// input_manager.input_added(Device::from_ptr(data as *mut
/// wlr_input_device))
///         };
///     ]
/// );
/// ```
///
/// # Unsafety
/// Note that the purpose of this macro is to make it easy to generate unsafe
/// boiler plate for using listeners with Rust data.
///
/// However, there are a few things this macro doesn't protect against.
///
/// First and foremost, the data cannot move. The listeners assume that the
/// structure will never move, so in order to defend against this the generated
/// `new` method returns a Box version. **Do not move out of the box**.
///
/// Second, this macro doesn't protect against the stored data being unsized.
/// Passing a pointer of unsized data to C is UB, don't do it.
#[macro_export]
macro_rules! wayland_listener {
    ($struct_name: ident, $data: ty, $([
        $($listener: ident => $listener_func: ident :
          |$($func_arg:ident: $func_type:ty,)*| unsafe $body: block;)*])+) => {
        #[repr(C)]
        pub struct $struct_name {
            data: $data,
            $($($listener: $crate::wlroots_sys::wl_listener),*)*
        }

        impl $struct_name {
            pub fn new(data: $data) -> Box<$struct_name> {
                use $crate::wayland_sys::server::WAYLAND_SERVER_HANDLE;
                Box::new($struct_name {
                    data,
                    $($($listener: unsafe {
                        // NOTE Rationale for zeroed memory:
                        // * Need to pass a pointer to wl_list_init
                        // * The list is initialized by Wayland, which doesn't "drop"
                        // * The listener is written to without dropping any of the data
                        let mut listener: $crate::wlroots_sys::wl_listener = ::std::mem::zeroed();
                        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                      wl_list_init,
                                      &mut listener.link as *mut _ as _);
                        ::std::ptr::write(&mut listener.notify, Some($struct_name::$listener_func));
                        listener
                    }),*)*
                })
            }

            $($(pub unsafe extern "C" fn $listener(&mut self)
                                                   -> *mut $crate::wlroots_sys::wl_listener {
                &mut self.$listener as *mut _
            })*)*

            $($(pub unsafe extern "C" fn $listener_func(listener:
                                                        *mut $crate::wlroots_sys::wl_listener,
                                                        data: *mut libc::c_void) {
                let manager: &mut $struct_name = &mut (*container_of!(listener,
                                                                      $struct_name,
                                                                      $listener));
                (|$($func_arg: $func_type,)*| { $body })(manager, data);
            })*)*
        }
    }
}
<commit_msg>Added doc for verbs used in wlr_log!<commit_after>/// Gets the offset of a field. Used by container_of!
#[macro_export]
macro_rules! offset_of(
    ($ty:ty, $field:ident) => {
        &(*(0 as *const $ty)).$field as *const _ as usize
    }
);

/// Gets the parent struct from a pointer.
/// VERY unsafe. The parent struct _must_ be repr(C), and the
/// type passed to this macro _must_ match the type of the parent.
#[macro_export]
macro_rules! container_of (
    ($ptr: expr, $container: ty, $field: ident) => {
        ($ptr as *mut u8).offset(-(offset_of!($container, $field) as isize)) as *mut $container
    }
);

/// Convert a literal string to a C string.
/// Note: Does not check for internal nulls, nor does it do any conversions on
/// the grapheme clustors. Just passes the bytes as is.
/// So probably only works on ASCII.
#[macro_export]
macro_rules! c_str {
    ($s:expr) => {
        concat!($s, "\0").as_ptr() as *const i8
    }
}

#[macro_export]
/// Logs a message using wlroots' logging capability.
///
/// Possible values for `verb`:
///
/// * L_SILENT
/// * L_INFO
/// * L_DEBUG
/// * L_ERROR
macro_rules! wlr_log {
    ($verb: expr, $($msg:tt)*) => {{
        use $crate::wlroots_sys::_wlr_log;
        use $crate::wlroots_sys::log_importance_t::*;
        use ::std::ffi::CString;
        unsafe {
            let fmt = CString::new(format!($($msg)*))
                .expect("Could not convert log message to C string");
            let raw = fmt.into_raw();
            _wlr_log($verb, c_str!("[%s:%lu] %s"),
                    c_str!(file!()), line!(), raw);
            // Deallocate string
            CString::from_raw(raw);
        }
    }}
}

/// Defines a new struct that contains a variable number of listeners that
/// will trigger unsafe user-defined callbacks.
///
/// The structure that is defined is repr(C), has one `data` field with the
/// given user type, and a field for each `$listener`.
///
/// Each `$listener` has a getter method that lets you get the pointer to the
/// listener. This method is unsafe, since it returns a raw pointer.
/// To use it correctly, you need to ensure that the data it refers to never
/// moves (e.g keep it in a box). The primary purpose of this method is to pass
/// the listener pointer to other methods to register it for a Wayland event.
/// **A listener can only be registered to one event at a time**.
///
/// Finally, it also takes in a body for each `$listener` that is called
/// every time the event that is later hooked up to it is fired.
/// This method is inherently unsafe, because the user data hasn't been cast
/// from the void pointer yet. It is the user's job to write this safely.
/// To highlight this fact, the body of the function must be prefixed with
/// `unsafe`.
///
/// # Example
/// ```
/// // Handles input addition and removal.
/// pub trait InputManagerHandler {
///     // Callback triggered when an input device is added.
///     fn input_added(&mut self, Device);
/// }
/// wayland_listener!(
///     // The name of the structure that will be defined.
///     InputManager,
///     // The type that's stored in the `data` field.
///     // Note that we use a Box here to achieve dynamic dispatch,
///     // it's not required for this type to be in a box.
///     Box<InputManagerHandler>,
///     [
///         // Adds a new listener called `add_listener`.
///         add_listener =>
///         // Adds an unsafe function called `add_notify` that is triggered
///         // whenever add_listener is activated from a Wayland event.
///         add_notify: |input_manager: &mut Box<InputManagerHandler>,
///                      data: *mut libc::c_void,| unsafe {
/// // Call the method defined above, wrapping it in a safe
/// interface.
/// // It is your job to ensure that the code in here doesn't
/// trigger UB!
/// input_manager.input_added(Device::from_ptr(data as *mut
/// wlr_input_device))
///         };
///     ]
/// );
/// ```
///
/// # Unsafety
/// Note that the purpose of this macro is to make it easy to generate unsafe
/// boiler plate for using listeners with Rust data.
///
/// However, there are a few things this macro doesn't protect against.
///
/// First and foremost, the data cannot move. The listeners assume that the
/// structure will never move, so in order to defend against this the generated
/// `new` method returns a Box version. **Do not move out of the box**.
///
/// Second, this macro doesn't protect against the stored data being unsized.
/// Passing a pointer of unsized data to C is UB, don't do it.
#[macro_export]
macro_rules! wayland_listener {
    ($struct_name: ident, $data: ty, $([
        $($listener: ident => $listener_func: ident :
          |$($func_arg:ident: $func_type:ty,)*| unsafe $body: block;)*])+) => {
        #[repr(C)]
        pub struct $struct_name {
            data: $data,
            $($($listener: $crate::wlroots_sys::wl_listener),*)*
        }

        impl $struct_name {
            pub fn new(data: $data) -> Box<$struct_name> {
                use $crate::wayland_sys::server::WAYLAND_SERVER_HANDLE;
                Box::new($struct_name {
                    data,
                    $($($listener: unsafe {
                        // NOTE Rationale for zeroed memory:
                        // * Need to pass a pointer to wl_list_init
                        // * The list is initialized by Wayland, which doesn't "drop"
                        // * The listener is written to without dropping any of the data
                        let mut listener: $crate::wlroots_sys::wl_listener = ::std::mem::zeroed();
                        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                                      wl_list_init,
                                      &mut listener.link as *mut _ as _);
                        ::std::ptr::write(&mut listener.notify, Some($struct_name::$listener_func));
                        listener
                    }),*)*
                })
            }

            $($(pub unsafe extern "C" fn $listener(&mut self)
                                                   -> *mut $crate::wlroots_sys::wl_listener {
                &mut self.$listener as *mut _
            })*)*

            $($(pub unsafe extern "C" fn $listener_func(listener:
                                                        *mut $crate::wlroots_sys::wl_listener,
                                                        data: *mut libc::c_void) {
                let manager: &mut $struct_name = &mut (*container_of!(listener,
                                                                      $struct_name,
                                                                      $listener));
                (|$($func_arg: $func_type,)*| { $body })(manager, data);
            })*)*
        }
    }
}
<|endoftext|>


<commit_before>extern crate llvm_sys;

use std::ptr;
use self::llvm_sys::core::*;
use self::llvm_sys::*;
use llvm::codegen::{Context, c_str_ptr};

// Generate LLVM IR for functions built into the language
pub unsafe fn generate_builtins(context: &mut Context) {
    generate_types(context);
    generate_print(context);

    // Generate a `main` function for the script to be housed
    let int32 = LLVMInt32TypeInContext(context.get_context());
    let fn_type = LLVMFunctionType(int32, ptr::null_mut(), 0, 0);
    let main = LLVMAddFunction(context.get_module(), c_str_ptr("main"), fn_type);
    let bb = LLVMAppendBasicBlockInContext(context.get_context(), main, c_str_ptr("entry"));

    // Goes to the end of the block
    LLVMPositionBuilderAtEnd(context.get_builder(), bb);

    // Adds a return statement
    LLVMBuildRet(context.get_builder(), LLVMConstInt(int32, 1, 1));

    // Reposition to the start of the block
    LLVMPositionBuilder(context.get_builder(), bb, LLVMGetFirstInstruction(bb));
}

unsafe fn generate_print(context: &mut Context) {
    // Types
    let void = LLVMVoidTypeInContext(context.get_context());
    let string_type_fields = vec![LLVMInt32TypeInContext(context.get_context()),
                  LLVMPointerType(LLVMInt8TypeInContext(context.get_context()), 0)];
    let int32_type = LLVMInt32TypeInContext(context.get_context());
    let string_type = LLVMStructTypeInContext(context.get_context(), string_type_fields.as_ptr() as *mut _, 2, 0);

    let args = vec![string_type];

    // 2nd arg is param types (*mut LLVMTypeRef) and 3rd is param count. 4 is variable # of args t/f?
    let fn_type = LLVMFunctionType(void, args.as_ptr() as *mut _, 1, 0);
    let print_fn = LLVMAddFunction(context.get_module(), c_str_ptr("print"), fn_type);

    // Name the param
    let param = LLVMGetFirstParam(print_fn);
    LLVMSetValueName(param, c_str_ptr("str"));

    // Create basic blocks to generate code in
    let start_block = LLVMAppendBasicBlockInContext(context.get_context(), print_fn, c_str_ptr("start"));
    let loop_block = LLVMAppendBasicBlockInContext(context.get_context(), print_fn, c_str_ptr("loop"));
    let end_block = LLVMAppendBasicBlockInContext(context.get_context(), print_fn, c_str_ptr("end"));

    // Start
    LLVMPositionBuilderAtEnd(context.get_builder(), start_block);

    let zero = LLVMConstInt(int32_type, 0, 0);
    let op = LLVMIntPredicate::LLVMIntEQ;
    let iter = LLVMBuildAlloca(context.get_builder(), int32_type, c_str_ptr("iter"));
    LLVMBuildStore(context.get_builder(), zero, iter);
    let len = LLVMBuildExtractValue(context.get_builder(), param, 0, c_str_ptr("len"));
    let str_ptr = LLVMBuildExtractValue(context.get_builder(), param, 1, c_str_ptr("strptr"));
    let cmp = LLVMBuildICmp(context.get_builder(), op, len, zero, c_str_ptr("cmp"));

    // Branch to end if string len is 0
    LLVMBuildCondBr(context.get_builder(), cmp, end_block, loop_block);

    // Loop
    LLVMPositionBuilderAtEnd(context.get_builder(), loop_block);
    // Do more stuff here
    let ptr_offset = LLVMBuildAdd(context.get_builder(), str_ptr, iter, c_str_ptr("offset"));

    LLVMBuildBr(context.get_builder(), end_block);

    // End
    LLVMPositionBuilderAtEnd(context.get_builder(), end_block);
    LLVMBuildRetVoid(context.get_builder());
}

unsafe fn generate_types(context: &mut Context) {
    // Define a string structure that looks like:
    // string {
    //     len: i32,
    //     array: i8*
    // }

    let string_type_fields = vec![LLVMInt32TypeInContext(context.get_context()),
                  LLVMPointerType(LLVMInt8TypeInContext(context.get_context()), 0)];

//    let struct_type = LLVMStructType(string_type_fields.as_ptr() as *mut _, 2, 0);
//    let const_str_var = LLVMAddGlobal(context.get_module(), struct_type, c_str_ptr("struct.String"));

    let string_struct_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), c_str_ptr("string"));
    LLVMStructSetBody(string_struct_type, string_type_fields.as_ptr() as *mut _, 2, 0);
//    let string_struct = LLVMStructType(struct_type, 2, 0);
}
<commit_msg>Continued working on print IR.<commit_after>extern crate llvm_sys;

use std::ptr;
use self::llvm_sys::core::*;
use self::llvm_sys::*;
use llvm::codegen::{Context, c_str_ptr};

// Generate LLVM IR for functions built into the language
pub unsafe fn generate_builtins(context: &mut Context) {
    generate_types(context);
    generate_print(context);

    // Generate a `main` function for the script to be housed
    let int32 = LLVMInt32TypeInContext(context.get_context());
    let fn_type = LLVMFunctionType(int32, ptr::null_mut(), 0, 0);
    let main = LLVMAddFunction(context.get_module(), c_str_ptr("main"), fn_type);
    let bb = LLVMAppendBasicBlockInContext(context.get_context(), main, c_str_ptr("entry"));

    // Goes to the end of the block
    LLVMPositionBuilderAtEnd(context.get_builder(), bb);

    // Adds a return statement
    LLVMBuildRet(context.get_builder(), LLVMConstInt(int32, 1, 1));

    // Reposition to the start of the block
    LLVMPositionBuilder(context.get_builder(), bb, LLVMGetFirstInstruction(bb));
}

unsafe fn generate_print(context: &mut Context) {
    // Types
    let void = LLVMVoidTypeInContext(context.get_context());
    let string_type_fields = vec![LLVMInt32TypeInContext(context.get_context()),
                  LLVMPointerType(LLVMInt8TypeInContext(context.get_context()), 0)];
    let int32_type = LLVMInt32TypeInContext(context.get_context());
    let string_type = LLVMStructTypeInContext(context.get_context(), string_type_fields.as_ptr() as *mut _, 2, 0);

    let args = vec![string_type];

    // 2nd arg is param types (*mut LLVMTypeRef) and 3rd is param count. 4 is variable # of args t/f?
    let fn_type = LLVMFunctionType(void, args.as_ptr() as *mut _, 1, 0);
    let print_fn = LLVMAddFunction(context.get_module(), c_str_ptr("print"), fn_type);

    // Name the param
    let param = LLVMGetFirstParam(print_fn);
    LLVMSetValueName(param, c_str_ptr("str"));

    // Create basic blocks to generate code in
    let start_block = LLVMAppendBasicBlockInContext(context.get_context(), print_fn, c_str_ptr("start"));
    let loop_block = LLVMAppendBasicBlockInContext(context.get_context(), print_fn, c_str_ptr("loop"));
    let end_block = LLVMAppendBasicBlockInContext(context.get_context(), print_fn, c_str_ptr("end"));

    // Start
    LLVMPositionBuilderAtEnd(context.get_builder(), start_block);

    let zero = LLVMConstInt(int32_type, 0, 0);
    let op = LLVMIntPredicate::LLVMIntEQ;
    let offset_ptr = LLVMBuildAlloca(context.get_builder(), int32_type, c_str_ptr("offsetptr"));
    LLVMBuildStore(context.get_builder(), zero, offset_ptr);
    let len = LLVMBuildExtractValue(context.get_builder(), param, 0, c_str_ptr("len"));
    let str_ptr = LLVMBuildExtractValue(context.get_builder(), param, 1, c_str_ptr("strptr"));
    let cmp = LLVMBuildICmp(context.get_builder(), op, len, zero, c_str_ptr("cmp"));

    // Branch to end if string len is 0
    LLVMBuildCondBr(context.get_builder(), cmp, end_block, loop_block);

    // Loop
    LLVMPositionBuilderAtEnd(context.get_builder(), loop_block);

    let offset_val = LLVMBuildLoad(context.get_builder(), offset_ptr, c_str_ptr("offsetsval"));
    let ptr_iter = LLVMBuildAdd(context.get_builder(), str_ptr, offset_val, c_str_ptr("iter"));
    let mut putchar_fn = LLVMGetNamedFunction(context.get_module(), c_str_ptr("putchar"));
    if putchar_fn.is_null() {
        let fn_type2 = LLVMFunctionType(int32_type, vec![int32_type].as_ptr() as *mut _, 1, 0);
        putchar_fn = LLVMAddFunction(context.get_module(), c_str_ptr("putchar"), fn_type2);
    }

    // Print char at ptr_iter here
    LLVMBuildCall(context.get_builder(), putchar_fn, vec![ptr_iter].as_ptr() as *mut _, 1, c_str_ptr(""));

    // TODO: Increment offset_val? (move its init out of the loop?)

    // TODO: If equal to len, branch to end else branch to loop

    LLVMBuildBr(context.get_builder(), end_block);

    // End
    LLVMPositionBuilderAtEnd(context.get_builder(), end_block);
    LLVMBuildRetVoid(context.get_builder());
}

unsafe fn generate_types(context: &mut Context) {
    // Define a string structure that looks like:
    // string {
    //     len: i32,
    //     array: i8*
    // }

    let string_type_fields = vec![LLVMInt32TypeInContext(context.get_context()),
                  LLVMPointerType(LLVMInt8TypeInContext(context.get_context()), 0)];

//    let struct_type = LLVMStructType(string_type_fields.as_ptr() as *mut _, 2, 0);
//    let const_str_var = LLVMAddGlobal(context.get_module(), struct_type, c_str_ptr("struct.String"));

    let string_struct_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), c_str_ptr("string"));
    LLVMStructSetBody(string_struct_type, string_type_fields.as_ptr() as *mut _, 2, 0);
//    let string_struct = LLVMStructType(struct_type, 2, 0);
}
<|endoftext|>