<commit_before>use std::mem;

/// A platform profile.
///
/// A profile is a matrix that captures the evolution of a parameter over a time
/// interval with respect to a number of processing elements.
pub struct Profile {
    /// The number of processing elements.
    pub units: usize,
    /// The number of time steps.
    pub steps: usize,
    /// The beginning of the time interval.
    pub time: f64,
    /// The time step (sampling interval).
    pub time_step: f64,
    /// The actual data.
    pub data: Vec<f64>,
}

impl Profile {
    /// Create a profile.
    pub fn new(units: usize, time_step: f64) -> Profile {
        Profile { units: units, steps: 0, time: 0.0, time_step: time_step, data: vec![] }
    }

    /// Create a copy but with the data zeroed out.
    pub fn clone_zero(&self) -> Profile {
        Profile {
            units: self.units,
            steps: self.steps,
            time: self.time,
            time_step: self.time_step,
            data: vec![0.0; self.units * self.steps],
        }
    }

    /// Add data to a particular processing element starting from a particular
    /// time moment.
    pub fn push(&mut self, unit: usize, time: f64, time_step: f64, dynamic: &[f64], statik: f64) {
        debug_assert!(unit < self.units);
        debug_assert!(time >= self.time);

        let (t1, t2) = (self.time, time);
        let (d1, d2) = (self.time_step, time_step);

        let s2 = dynamic.len();
        let s1 = ((t2 - t1 + (s2 as f64) * d2) / d1).ceil() as usize;

        if s1 > self.steps {
            self.data.extend(vec![statik; (s1 - self.steps) * self.units]);
            self.steps = s1;
        }

        let mut j1 = ((t2 - t1) / d1) as usize;
        let mut j2 = 0;

        macro_rules! add(
            ($weight:expr) => (self.data[j1 * self.units + unit] += $weight * dynamic[j2]);
        );

        while j1 < s1 && j2 < s2 {
            let l1 = t1 + (j1 as f64) * d1;
            let l2 = t2 + (j2 as f64) * d2;

            let r1 = l1 + d1;
            let r2 = l2 + d2;

            if l1 < l2 {
                if r2 < r1 {
                    add!(1.0);
                    j2 += 1;
                } else {
                    add!((r1 - l2) / d2);
                    j1 += 1;
                }
            } else {
                if r1 < r2 {
                    add!(d1 / d2);
                    j1 += 1;
                } else {
                    add!((r2 - l1) / d2);
                    j2 += 1;
                }
            }
        }
    }

    /// Advance time and return the accumulated data.
    pub fn pull(&mut self, time: f64) -> Self {
        debug_assert!(time >= self.time);
        let steps = ((time - self.time) / self.time_step).floor() as usize;
        debug_assert!(self.steps >= steps);

        let mut profile = Profile {
            units: self.units,
            steps: self.steps - steps,
            time: (time / self.time_step).floor() * self.time_step,
            time_step: self.time_step,
            data: self.data[(steps * self.units)..].to_vec(),
        };

        mem::swap(self, &mut profile);

        profile.steps = steps;
        profile.data.truncate(steps * self.units);

        profile
    }
}

impl Into<Vec<f64>> for Profile {
    #[inline]
    fn into(self) -> Vec<f64> {
        self.data
    }
}

deref! { Profile::data => [f64] }
deref! { mut Profile::data => [f64] }

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

    #[test]
    fn push_padding() {
        let mut profile = Profile::new(2, 0.5);

        profile.push(0, 4.0, 1.0, &[], 42.0);
        assert_eq!(profile.steps, 8);
        assert_eq!(&profile.data, &vec![42.0; 2 * 8]);

        profile.push(0, 2.5, 1.0, &[], 0.0);
        assert_eq!(profile.steps, 8);
        assert_eq!(&profile.data, &vec![42.0; 2 * 8]);

        profile.push(0, 6.5, 1.0, &[], 42.0);
        assert_eq!(profile.steps, 13);
        assert_eq!(&profile.data, &vec![42.0; 2 * 13]);

        profile.push(0, 6.55, 1.0, &[], 42.0);
        assert_eq!(profile.steps, 14);
        assert_eq!(&profile.data, &vec![42.0; 2 * 14]);
    }

    #[test]
    fn push_synchronous() {
        let mut profile = Profile::new(2, 1.0);

        profile.push(0, 1.0, 1.0, &[1.0, 2.0], 0.0);
        assert_eq!(profile.steps, 3);
        assert_eq!(&profile.data, &vec![
           0.0, 0.0,
           1.0, 0.0,
           2.0, 0.0,
        ]);

        profile.push(0, 1.0, 1.0, &[1.0, 2.0, 3.0], 0.0);
        assert_eq!(profile.steps, 4);
        assert_eq!(&profile.data, &vec![
           0.0, 0.0,
           2.0, 0.0,
           4.0, 0.0,
           3.0, 0.0,
        ]);
    }

    #[test]
    fn push_asynchronous() {
        let mut profile = Profile::new(2, 1.0);

        profile.push(1, 1.5, 1.0, &[1.0, 2.0, 3.0], 0.0);
        assert_eq!(profile.steps, 5);
        assert_eq!(&profile.data, &vec![
           0.0, 0.0,
           0.0, 0.5,
           0.0, 1.5,
           0.0, 2.5,
           0.0, 1.5,
        ]);

        profile.push(0, 0.5, 0.25, &[1.0, 2.0, 3.0, 1.0, 3.0], 0.0);
        assert_eq!(profile.steps, 5);
        assert_eq!(&profile.data, &vec![
           3.0, 0.0,
           7.0, 0.5,
           0.0, 1.5,
           0.0, 2.5,
           0.0, 1.5,
        ]);

        profile.push(0, 1.25, 1.0, &[1.0, 2.0, 3.0, 0.0, 4.0], 0.0);
        assert_eq!(profile.steps, 7);
        assert_eq!(&profile.data, &vec![
           3.00, 0.0,
           7.75, 0.5,
           1.75, 1.5,
           2.75, 2.5,
           0.75, 1.5,
           3.00, 0.0,
           1.00, 0.0,
        ]);
    }

    #[test]
    fn pull() {
        let mut profile = Profile::new(2, 1.0);
        profile.push(0, 0.0, 1.0, &vec![42.0; 42], 0.0);
        assert_eq!(profile.time, 0.0);
        assert_eq!(profile.steps, 42);

        assert_eq!(profile.pull(0.0).data, vec![]);
        assert_eq!(profile.time, 0.0);
        assert_eq!(profile.steps, 42);

        assert_eq!(profile.pull(0.75).data, vec![]);
        assert_eq!(profile.time, 0.0);
        assert_eq!(profile.steps, 42);

        assert_eq!(profile.pull(1.0).data, vec![42.0, 0.0]);
        assert_eq!(profile.time, 1.0);
        assert_eq!(profile.steps, 41);

        assert_eq!(profile.pull(1.5).data, vec![]);
        assert_eq!(profile.time, 1.0);
        assert_eq!(profile.steps, 41);

        assert_eq!(profile.pull(3.5).data, vec![42.0, 0.0, 42.0, 0.0]);
        assert_eq!(profile.time, 3.0);
        assert_eq!(profile.steps, 39);
    }
}
<commit_msg>Rename a couple of variables<commit_after>use std::mem;

/// A platform profile.
///
/// A profile is a matrix that captures the evolution of a parameter over a time
/// interval with respect to a number of processing elements.
pub struct Profile {
    /// The number of processing elements.
    pub units: usize,
    /// The number of time steps.
    pub steps: usize,
    /// The beginning of the time interval.
    pub time: f64,
    /// The time step (sampling interval).
    pub time_step: f64,
    /// The actual data.
    pub data: Vec<f64>,
}

impl Profile {
    /// Create a profile.
    pub fn new(units: usize, time_step: f64) -> Profile {
        Profile { units: units, steps: 0, time: 0.0, time_step: time_step, data: vec![] }
    }

    /// Create a copy but with the data zeroed out.
    pub fn clone_zero(&self) -> Profile {
        Profile {
            units: self.units,
            steps: self.steps,
            time: self.time,
            time_step: self.time_step,
            data: vec![0.0; self.units * self.steps],
        }
    }

    /// Add data to a particular processing element starting from a particular
    /// time moment.
    pub fn push(&mut self, unit: usize, time: f64, time_step: f64, data: &[f64], fill: f64) {
        debug_assert!(unit < self.units);
        debug_assert!(time >= self.time);

        let (t1, t2) = (self.time, time);
        let (d1, d2) = (self.time_step, time_step);

        let s2 = data.len();
        let s1 = ((t2 - t1 + (s2 as f64) * d2) / d1).ceil() as usize;

        if s1 > self.steps {
            self.data.extend(vec![fill; (s1 - self.steps) * self.units]);
            self.steps = s1;
        }

        let mut j1 = ((t2 - t1) / d1) as usize;
        let mut j2 = 0;

        macro_rules! add(
            ($weight:expr) => (self.data[j1 * self.units + unit] += $weight * data[j2]);
        );

        while j1 < s1 && j2 < s2 {
            let l1 = t1 + (j1 as f64) * d1;
            let l2 = t2 + (j2 as f64) * d2;

            let r1 = l1 + d1;
            let r2 = l2 + d2;

            if l1 < l2 {
                if r2 < r1 {
                    add!(1.0);
                    j2 += 1;
                } else {
                    add!((r1 - l2) / d2);
                    j1 += 1;
                }
            } else {
                if r1 < r2 {
                    add!(d1 / d2);
                    j1 += 1;
                } else {
                    add!((r2 - l1) / d2);
                    j2 += 1;
                }
            }
        }
    }

    /// Advance time and return the accumulated data.
    pub fn pull(&mut self, time: f64) -> Self {
        debug_assert!(time >= self.time);
        let steps = ((time - self.time) / self.time_step).floor() as usize;
        debug_assert!(self.steps >= steps);

        let mut profile = Profile {
            units: self.units,
            steps: self.steps - steps,
            time: (time / self.time_step).floor() * self.time_step,
            time_step: self.time_step,
            data: self.data[(steps * self.units)..].to_vec(),
        };

        mem::swap(self, &mut profile);

        profile.steps = steps;
        profile.data.truncate(steps * self.units);

        profile
    }
}

impl Into<Vec<f64>> for Profile {
    #[inline]
    fn into(self) -> Vec<f64> {
        self.data
    }
}

deref! { Profile::data => [f64] }
deref! { mut Profile::data => [f64] }

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

    #[test]
    fn push_padding() {
        let mut profile = Profile::new(2, 0.5);

        profile.push(0, 4.0, 1.0, &[], 42.0);
        assert_eq!(profile.steps, 8);
        assert_eq!(&profile.data, &vec![42.0; 2 * 8]);

        profile.push(0, 2.5, 1.0, &[], 0.0);
        assert_eq!(profile.steps, 8);
        assert_eq!(&profile.data, &vec![42.0; 2 * 8]);

        profile.push(0, 6.5, 1.0, &[], 42.0);
        assert_eq!(profile.steps, 13);
        assert_eq!(&profile.data, &vec![42.0; 2 * 13]);

        profile.push(0, 6.55, 1.0, &[], 42.0);
        assert_eq!(profile.steps, 14);
        assert_eq!(&profile.data, &vec![42.0; 2 * 14]);
    }

    #[test]
    fn push_synchronous() {
        let mut profile = Profile::new(2, 1.0);

        profile.push(0, 1.0, 1.0, &[1.0, 2.0], 0.0);
        assert_eq!(profile.steps, 3);
        assert_eq!(&profile.data, &vec![
           0.0, 0.0,
           1.0, 0.0,
           2.0, 0.0,
        ]);

        profile.push(0, 1.0, 1.0, &[1.0, 2.0, 3.0], 0.0);
        assert_eq!(profile.steps, 4);
        assert_eq!(&profile.data, &vec![
           0.0, 0.0,
           2.0, 0.0,
           4.0, 0.0,
           3.0, 0.0,
        ]);
    }

    #[test]
    fn push_asynchronous() {
        let mut profile = Profile::new(2, 1.0);

        profile.push(1, 1.5, 1.0, &[1.0, 2.0, 3.0], 0.0);
        assert_eq!(profile.steps, 5);
        assert_eq!(&profile.data, &vec![
           0.0, 0.0,
           0.0, 0.5,
           0.0, 1.5,
           0.0, 2.5,
           0.0, 1.5,
        ]);

        profile.push(0, 0.5, 0.25, &[1.0, 2.0, 3.0, 1.0, 3.0], 0.0);
        assert_eq!(profile.steps, 5);
        assert_eq!(&profile.data, &vec![
           3.0, 0.0,
           7.0, 0.5,
           0.0, 1.5,
           0.0, 2.5,
           0.0, 1.5,
        ]);

        profile.push(0, 1.25, 1.0, &[1.0, 2.0, 3.0, 0.0, 4.0], 0.0);
        assert_eq!(profile.steps, 7);
        assert_eq!(&profile.data, &vec![
           3.00, 0.0,
           7.75, 0.5,
           1.75, 1.5,
           2.75, 2.5,
           0.75, 1.5,
           3.00, 0.0,
           1.00, 0.0,
        ]);
    }

    #[test]
    fn pull() {
        let mut profile = Profile::new(2, 1.0);
        profile.push(0, 0.0, 1.0, &vec![42.0; 42], 0.0);
        assert_eq!(profile.time, 0.0);
        assert_eq!(profile.steps, 42);

        assert_eq!(profile.pull(0.0).data, vec![]);
        assert_eq!(profile.time, 0.0);
        assert_eq!(profile.steps, 42);

        assert_eq!(profile.pull(0.75).data, vec![]);
        assert_eq!(profile.time, 0.0);
        assert_eq!(profile.steps, 42);

        assert_eq!(profile.pull(1.0).data, vec![42.0, 0.0]);
        assert_eq!(profile.time, 1.0);
        assert_eq!(profile.steps, 41);

        assert_eq!(profile.pull(1.5).data, vec![]);
        assert_eq!(profile.time, 1.0);
        assert_eq!(profile.steps, 41);

        assert_eq!(profile.pull(3.5).data, vec![42.0, 0.0, 42.0, 0.0]);
        assert_eq!(profile.time, 3.0);
        assert_eq!(profile.steps, 39);
    }
}
<|endoftext|>


<commit_before>//! Global initialization and retrieval of command line arguments.
//!
//! On some platforms these are stored during runtime startup,
//! and on some they are retrieved from the system on demand.

#![allow(dead_code)] // runtime init functions not used during testing

use crate::ffi::OsString;
use crate::marker::PhantomData;
use crate::vec;

/// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }

/// One-time global cleanup.
pub unsafe fn cleanup() { imp::cleanup() }

/// Returns the command line arguments
pub fn args() -> Args {
    imp::args()
}

pub struct Args {
    iter: vec::IntoIter<OsString>,
    _dont_send_or_sync_me: PhantomData<*mut ()>,
}

impl Args {
    pub fn inner_debug(&self) -> &[OsString] {
        self.iter.as_slice()
    }
}

impl Iterator for Args {
    type Item = OsString;
    fn next(&mut self) -> Option<OsString> { self.iter.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

impl ExactSizeIterator for Args {
    fn len(&self) -> usize { self.iter.len() }
}

impl DoubleEndedIterator for Args {
    fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
}

#[cfg(any(target_os = "linux",
          target_os = "android",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "netbsd",
          target_os = "openbsd",
          target_os = "solaris",
          target_os = "emscripten",
          target_os = "haiku",
          target_os = "l4re",
          target_os = "fuchsia",
          target_os = "redox"))]
mod imp {
    use crate::os::unix::prelude::*;
    use crate::ptr;
    use crate::ffi::{CStr, OsString};
    use crate::marker::PhantomData;
    use super::Args;

    use crate::sys_common::mutex::Mutex;

    static mut ARGC: isize = 0;
    static mut ARGV: *const *const u8 = ptr::null();
    // We never call `ENV_LOCK.init()`, so it is UB to attempt to
    // acquire this mutex reentrantly!
    static LOCK: Mutex = Mutex::new();

    unsafe fn really_init(argc: isize, argv: *const *const u8) {
        let _guard = LOCK.lock();
        ARGC = argc;
        ARGV = argv;
    }

    #[inline(always)]
    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
        #[cfg(not(all(target_os = "linux", target_env = "gnu")))]
        really_init(_argc, _argv);
    }

    /// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension.
    /// This allows `std::env::args` to work even in a `cdylib`, as it does on macOS and Windows.
    #[cfg(all(target_os = "linux", target_env = "gnu"))]
    #[used]
    #[link_section = ".init_array.00099"]
    static ARGV_INIT_ARRAY: extern "C" fn(
        crate::os::raw::c_int,
        *const *const u8,
        *const *const u8,
    ) = {
        extern "C" fn init_wrapper(
            argc: crate::os::raw::c_int,
            argv: *const *const u8,
            _envp: *const *const u8,
        ) {
            unsafe {
                really_init(argc as isize, argv);
            }
        }
        init_wrapper
    };

    pub unsafe fn cleanup() {
        let _guard = LOCK.lock();
        ARGC = 0;
        ARGV = ptr::null();
    }

    pub fn args() -> Args {
        Args {
            iter: clone().into_iter(),
            _dont_send_or_sync_me: PhantomData
        }
    }

    fn clone() -> Vec<OsString> {
        unsafe {
            let _guard = LOCK.lock();
            (0..ARGC).map(|i| {
                let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char);
                OsStringExt::from_vec(cstr.to_bytes().to_vec())
            }).collect()
        }
    }
}

#[cfg(any(target_os = "macos",
          target_os = "ios"))]
mod imp {
    use crate::ffi::CStr;
    use crate::marker::PhantomData;
    use super::Args;

    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
    }

    pub fn cleanup() {
    }

    #[cfg(target_os = "macos")]
    pub fn args() -> Args {
        use crate::os::unix::prelude::*;
        extern {
            // These functions are in crt_externs.h.
            fn _NSGetArgc() -> *mut libc::c_int;
            fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
        }

        let vec = unsafe {
            let (argc, argv) = (*_NSGetArgc() as isize,
                                *_NSGetArgv() as *const *const libc::c_char);
            (0.. argc as isize).map(|i| {
                let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
                OsStringExt::from_vec(bytes)
            }).collect::<Vec<_>>()
        };
        Args {
            iter: vec.into_iter(),
            _dont_send_or_sync_me: PhantomData,
        }
    }

    // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
    // and use underscores in their names - they're most probably
    // are considered private and therefore should be avoided
    // Here is another way to get arguments using Objective C
    // runtime
    //
    // In general it looks like:
    // res = Vec::new()
    // let args = [[NSProcessInfo processInfo] arguments]
    // for i in (0..[args count])
    //      res.push([args objectAtIndex:i])
    // res
    #[cfg(target_os = "ios")]
    pub fn args() -> Args {
        use crate::ffi::OsString;
        use crate::mem;
        use crate::str;

        extern {
            fn sel_registerName(name: *const libc::c_uchar) -> Sel;
            fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
        }

        #[cfg(target_arch="aarch64")]
        extern {
            fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
            #[link_name="objc_msgSend"]
            fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
        }

        #[cfg(not(target_arch="aarch64"))]
        extern {
            fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
            #[link_name="objc_msgSend"]
            fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
        }

        type Sel = *const libc::c_void;
        type NsId = *const libc::c_void;

        let mut res = Vec::new();

        unsafe {
            let process_info_sel = sel_registerName("processInfo\0".as_ptr());
            let arguments_sel = sel_registerName("arguments\0".as_ptr());
            let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
            let count_sel = sel_registerName("count\0".as_ptr());
            let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());

            let klass = objc_getClass("NSProcessInfo\0".as_ptr());
            let info = objc_msgSend(klass, process_info_sel);
            let args = objc_msgSend(info, arguments_sel);

            let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
            for i in 0..cnt {
                let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong);
                let utf_c_str: *const libc::c_char =
                    mem::transmute(objc_msgSend(tmp, utf8_sel));
                let bytes = CStr::from_ptr(utf_c_str).to_bytes();
                res.push(OsString::from(str::from_utf8(bytes).unwrap()))
            }
        }

        Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }
    }
}
<commit_msg>Auto merge of #66873 - RalfJung:miri-args, r=dtolnay<commit_after>//! Global initialization and retrieval of command line arguments.
//!
//! On some platforms these are stored during runtime startup,
//! and on some they are retrieved from the system on demand.

#![allow(dead_code)] // runtime init functions not used during testing

use crate::ffi::OsString;
use crate::marker::PhantomData;
use crate::vec;

/// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }

/// One-time global cleanup.
pub unsafe fn cleanup() { imp::cleanup() }

/// Returns the command line arguments
pub fn args() -> Args {
    imp::args()
}

pub struct Args {
    iter: vec::IntoIter<OsString>,
    _dont_send_or_sync_me: PhantomData<*mut ()>,
}

impl Args {
    pub fn inner_debug(&self) -> &[OsString] {
        self.iter.as_slice()
    }
}

impl Iterator for Args {
    type Item = OsString;
    fn next(&mut self) -> Option<OsString> { self.iter.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

impl ExactSizeIterator for Args {
    fn len(&self) -> usize { self.iter.len() }
}

impl DoubleEndedIterator for Args {
    fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
}

#[cfg(any(target_os = "linux",
          target_os = "android",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "netbsd",
          target_os = "openbsd",
          target_os = "solaris",
          target_os = "emscripten",
          target_os = "haiku",
          target_os = "l4re",
          target_os = "fuchsia",
          target_os = "redox"))]
mod imp {
    use crate::os::unix::prelude::*;
    use crate::ptr;
    use crate::ffi::{CStr, OsString};
    use crate::marker::PhantomData;
    use super::Args;

    use crate::sys_common::mutex::Mutex;

    static mut ARGC: isize = 0;
    static mut ARGV: *const *const u8 = ptr::null();
    // We never call `ENV_LOCK.init()`, so it is UB to attempt to
    // acquire this mutex reentrantly!
    static LOCK: Mutex = Mutex::new();

    unsafe fn really_init(argc: isize, argv: *const *const u8) {
        let _guard = LOCK.lock();
        ARGC = argc;
        ARGV = argv;
    }

    #[inline(always)]
    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
        // On Linux-GNU, we rely on `ARGV_INIT_ARRAY` below to initialize
        // `ARGC` and `ARGV`. But in Miri that does not actually happen so we
        // still initialize here.
        #[cfg(any(
            miri,
            not(all(target_os = "linux", target_env = "gnu"))
        ))]
        really_init(_argc, _argv);
    }

    /// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension.
    /// This allows `std::env::args` to work even in a `cdylib`, as it does on macOS and Windows.
    #[cfg(all(target_os = "linux", target_env = "gnu"))]
    #[used]
    #[link_section = ".init_array.00099"]
    static ARGV_INIT_ARRAY: extern "C" fn(
        crate::os::raw::c_int,
        *const *const u8,
        *const *const u8,
    ) = {
        extern "C" fn init_wrapper(
            argc: crate::os::raw::c_int,
            argv: *const *const u8,
            _envp: *const *const u8,
        ) {
            unsafe {
                really_init(argc as isize, argv);
            }
        }
        init_wrapper
    };

    pub unsafe fn cleanup() {
        let _guard = LOCK.lock();
        ARGC = 0;
        ARGV = ptr::null();
    }

    pub fn args() -> Args {
        Args {
            iter: clone().into_iter(),
            _dont_send_or_sync_me: PhantomData
        }
    }

    fn clone() -> Vec<OsString> {
        unsafe {
            let _guard = LOCK.lock();
            (0..ARGC).map(|i| {
                let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char);
                OsStringExt::from_vec(cstr.to_bytes().to_vec())
            }).collect()
        }
    }
}

#[cfg(any(target_os = "macos",
          target_os = "ios"))]
mod imp {
    use crate::ffi::CStr;
    use crate::marker::PhantomData;
    use super::Args;

    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
    }

    pub fn cleanup() {
    }

    #[cfg(target_os = "macos")]
    pub fn args() -> Args {
        use crate::os::unix::prelude::*;
        extern {
            // These functions are in crt_externs.h.
            fn _NSGetArgc() -> *mut libc::c_int;
            fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
        }

        let vec = unsafe {
            let (argc, argv) = (*_NSGetArgc() as isize,
                                *_NSGetArgv() as *const *const libc::c_char);
            (0.. argc as isize).map(|i| {
                let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
                OsStringExt::from_vec(bytes)
            }).collect::<Vec<_>>()
        };
        Args {
            iter: vec.into_iter(),
            _dont_send_or_sync_me: PhantomData,
        }
    }

    // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
    // and use underscores in their names - they're most probably
    // are considered private and therefore should be avoided
    // Here is another way to get arguments using Objective C
    // runtime
    //
    // In general it looks like:
    // res = Vec::new()
    // let args = [[NSProcessInfo processInfo] arguments]
    // for i in (0..[args count])
    //      res.push([args objectAtIndex:i])
    // res
    #[cfg(target_os = "ios")]
    pub fn args() -> Args {
        use crate::ffi::OsString;
        use crate::mem;
        use crate::str;

        extern {
            fn sel_registerName(name: *const libc::c_uchar) -> Sel;
            fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
        }

        #[cfg(target_arch="aarch64")]
        extern {
            fn objc_msgSend(obj: NsId, sel: Sel) -> NsId;
            #[link_name="objc_msgSend"]
            fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId;
        }

        #[cfg(not(target_arch="aarch64"))]
        extern {
            fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
            #[link_name="objc_msgSend"]
            fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId;
        }

        type Sel = *const libc::c_void;
        type NsId = *const libc::c_void;

        let mut res = Vec::new();

        unsafe {
            let process_info_sel = sel_registerName("processInfo\0".as_ptr());
            let arguments_sel = sel_registerName("arguments\0".as_ptr());
            let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
            let count_sel = sel_registerName("count\0".as_ptr());
            let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());

            let klass = objc_getClass("NSProcessInfo\0".as_ptr());
            let info = objc_msgSend(klass, process_info_sel);
            let args = objc_msgSend(info, arguments_sel);

            let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
            for i in 0..cnt {
                let tmp = objc_msgSend_ul(args, object_at_sel, i as libc::c_ulong);
                let utf_c_str: *const libc::c_char =
                    mem::transmute(objc_msgSend(tmp, utf8_sel));
                let bytes = CStr::from_ptr(utf_c_str).to_bytes();
                res.push(OsString::from(str::from_utf8(bytes).unwrap()))
            }
        }

        Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData }
    }
}
<|endoftext|>


<commit_before>extern crate gl;
extern crate glfw;

use gl::types::*;
use glfw::{Context, OpenGlProfileHint, WindowHint, WindowMode};

fn main() {
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(WindowHint::ContextVersion(3, 2));
    glfw.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core));
    glfw.window_hint(WindowHint::OpenGlForwardCompat(true));
    glfw.window_hint(WindowHint::Resizable(false));

    let (mut window, events) = glfw.create_window(800, 600, "OpenGL", WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    // Listen for keyboard events on this window.
    window.set_key_polling(true);

    // Make this window's OpenGL context the current context. This must be done before calling
    // `gl::load_with`.
    window.make_current();

    // Load OpenGL function pointers.
    gl::load_with(|symbol| window.get_proc_address(symbol));

    static VERTICES: [GLfloat; 6] = [
         0.0,  0.5,
         0.5, -0.5,
        -0.5, -0.5,
    ];

    let mut vbo = 0;

    unsafe {
        gl::GenBuffers(1, &mut vbo);
        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(gl::ARRAY_BUFFER,
                       (VERTICES.len() * std::mem::size_of::<GLfloat>()) as GLsizeiptr,
                       &VERTICES as *const _ as *const GLvoid,
                       gl::STATIC_DRAW);
    }

    const VERTEX_SHADER_SOURCE: &'static str = "
        #version 150

        in vec2 position;

        void main() {
            gl_Position = vec4(position, 0.0, 1.0);
        }
    ";

    const FRAGMENT_SHADER_SOURCE: &'static str = "
        #version 150

        out vec4 out_color;

        void main() {
            out_color = vec4(1.0, 1.0, 1.0, 1.0);
        }
    ";

    fn compile_shader(shader_type: GLenum, source: &str) -> Result<GLuint, String> {
        let shader;
        unsafe {
            shader = gl::CreateShader(shader_type);
            let source_ptr = source.as_bytes().as_ptr() as *const GLchar;
            let source_len = source.len() as GLint;
            gl::ShaderSource(shader, 1, &source_ptr, &source_len);
            gl::CompileShader(shader);

            let mut status = gl::FALSE as GLint;
            gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

            if status == gl::TRUE as GLint {
                Ok(shader)
            } else {
                let mut len = 0;
                gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
                if len == 0 { return Err(String::new()) }

                let mut buf = Vec::with_capacity(len as usize);
                buf.set_len(len as usize - 1); // Subtract 1 to ignore the trailing null.
                gl::GetShaderInfoLog(shader, len, std::ptr::null_mut(),
                                     buf.as_mut_ptr() as *mut GLchar);

                Err(String::from_utf8_lossy(&buf).into_owned())
            }
        }
    }

    let vertex_shader = compile_shader(gl::VERTEX_SHADER, VERTEX_SHADER_SOURCE).unwrap();
    let fragment_shader = compile_shader(gl::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE).unwrap();

    while !window.should_close() {
        glfw.poll_events();

        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&mut window, event);
        }

        window.swap_buffers();
    }
}

fn handle_window_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
    use glfw::{Action, Key, WindowEvent};

    match event {
        WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
            window.set_should_close(true);
        },
        _ => {},
    }
}
<commit_msg>Move compile_shader out of main.<commit_after>extern crate gl;
extern crate glfw;

use gl::types::*;
use glfw::{Context, OpenGlProfileHint, WindowHint, WindowMode};

fn compile_shader(shader_type: GLenum, source: &str) -> Result<GLuint, String> {
    let shader;
    unsafe {
        shader = gl::CreateShader(shader_type);
        let source_ptr = source.as_bytes().as_ptr() as *const GLchar;
        let source_len = source.len() as GLint;
        gl::ShaderSource(shader, 1, &source_ptr, &source_len);
        gl::CompileShader(shader);

        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        if status == gl::TRUE as GLint {
            Ok(shader)
        } else {
            let mut log_len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut log_len);
            if log_len == 0 { return Err(String::new()) }

            let mut buf = Vec::with_capacity(log_len as usize);
            buf.set_len(log_len as usize - 1); // Subtract 1 to ignore the trailing null.
            gl::GetShaderInfoLog(shader, log_len, std::ptr::null_mut(),
                                 buf.as_mut_ptr() as *mut GLchar);

            Err(String::from_utf8_lossy(&buf).into_owned())
        }
    }
}

fn main() {
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(WindowHint::ContextVersion(3, 2));
    glfw.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core));
    glfw.window_hint(WindowHint::OpenGlForwardCompat(true));
    glfw.window_hint(WindowHint::Resizable(false));

    let (mut window, events) = glfw.create_window(800, 600, "OpenGL", WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    // Listen for keyboard events on this window.
    window.set_key_polling(true);

    // Make this window's OpenGL context the current context. This must be done before calling
    // `gl::load_with`.
    window.make_current();

    // Load OpenGL function pointers.
    gl::load_with(|symbol| window.get_proc_address(symbol));

    static VERTICES: [GLfloat; 6] = [
         0.0,  0.5,
         0.5, -0.5,
        -0.5, -0.5,
    ];

    let mut vbo = 0;

    unsafe {
        gl::GenBuffers(1, &mut vbo);
        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(gl::ARRAY_BUFFER,
                       (VERTICES.len() * std::mem::size_of::<GLfloat>()) as GLsizeiptr,
                       &VERTICES as *const _ as *const GLvoid,
                       gl::STATIC_DRAW);
    }

    const VERTEX_SHADER_SOURCE: &'static str = "
        #version 150

        in vec2 position;

        void main() {
            gl_Position = vec4(position, 0.0, 1.0);
        }
    ";

    const FRAGMENT_SHADER_SOURCE: &'static str = "
        #version 150

        out vec4 out_color;

        void main() {
            out_color = vec4(1.0, 1.0, 1.0, 1.0);
        }
    ";

    let vertex_shader = compile_shader(gl::VERTEX_SHADER, VERTEX_SHADER_SOURCE).unwrap();
    let fragment_shader = compile_shader(gl::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE).unwrap();

    while !window.should_close() {
        glfw.poll_events();

        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&mut window, event);
        }

        window.swap_buffers();
    }
}

fn handle_window_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
    use glfw::{Action, Key, WindowEvent};

    match event {
        WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
            window.set_should_close(true);
        },
        _ => {},
    }
}
<|endoftext|>


<commit_before>use gl::types::*;
use std::f32::consts::PI;
use std::ops::{Add, Index, IndexMut, Mul, Sub};

pub const TAU: GLfloat = 2.0 * PI;

macro_rules! define_vec {
    ($name:ident, $size:expr) => (
        #[derive(Copy, Clone, Debug, PartialEq)]
        pub struct $name(pub [GLfloat; $size]);

        impl $name {
            pub fn zero() -> Self {
                $name([0.0; $size])
            }

            /// Calculate the square of the length (or norm) of the vector. Slightly faster than
            /// `length`.
            pub fn length_squared(&self) -> GLfloat {
                let mut sum = 0.0;

                for i in 0..$size {
                    sum += self[i] * self[i];
                }

                sum
            }

            /// Calculate the the length (or norm) of the vector.
            pub fn length(&self) -> GLfloat {
                self.length_squared().sqrt()
            }

            /// Normalize the vector so that it has the same orientation but a length of 1.
            pub fn normalize(&mut self) {
                let length = self.length();

                for i in 0..$size {
                    self[i] /= length;
                }
            }
        }

        impl Index<usize> for $name {
            type Output = GLfloat;

            fn index(&self, i: usize) -> &GLfloat {
                &self.0[i]
            }
        }

        impl IndexMut<usize> for $name {
            fn index_mut(&mut self, i: usize) -> &mut GLfloat {
                &mut self.0[i]
            }
        }

        impl Add for $name {
            type Output = Self;

            fn add(self, other: Self) -> Self {
                let mut result = $name::zero();

                for i in 0..$size {
                    result[i] = self[i] + other[i];
                }

                result
            }
        }

        impl Sub for $name {
            type Output = Self;

            fn sub(self, other: Self) -> Self {
                let mut result = $name::zero();

                for i in 0..$size {
                    result[i] = self[i] - other[i];
                }

                result
            }
        }
    );
}

define_vec!(Vec3, 3);
define_vec!(Vec4, 4);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Mat4(pub [[GLfloat; 4]; 4]);

impl Mat4 {
    /// The zero matrix.
    pub fn zero() -> Self {
        Mat4([
            [0.0, 0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0, 0.0],
        ])
    }

    /// The identity matrix.
    pub fn identity() -> Self {
        Mat4([
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 1.0, 0.0, 0.0],
            [0.0, 0.0, 1.0, 0.0],
            [0.0, 0.0, 0.0, 1.0],
        ])
    }

    /// Build a matrix representing a scaling by the given factors.
    pub fn scale(x: GLfloat, y: GLfloat, z: GLfloat) -> Self {
        Mat4([
            [x,   0.0, 0.0, 0.0],
            [0.0, y,   0.0, 0.0],
            [0.0, 0.0, z,   0.0],
            [0.0, 0.0, 0.0, 1.0],
        ])
    }

    /// Build a matrix representing a translation.
    pub fn translate(x: GLfloat, y: GLfloat, z: GLfloat) -> Self {
        Mat4([
            [1.0, 0.0, 0.0, x  ],
            [0.0, 1.0, 0.0, y  ],
            [0.0, 0.0, 1.0, z  ],
            [0.0, 0.0, 0.0, 1.0],
        ])
    }

    /// Build a matrix representing a rotation around the X-axis by the given angle (in radians).
    pub fn rotate_x(angle: GLfloat) -> Self {
        let cos = angle.cos();
        let sin = angle.sin();

        Mat4([
            [1.0, 0.0,  0.0, 0.0],
            [0.0, cos, -sin, 0.0],
            [0.0, sin,  cos, 0.0],
            [0.0, 0.0,  0.0, 1.0],
        ])
    }

    /// Build a matrix representing a rotation around the Y-axis by the given angle (in radians).
    pub fn rotate_y(angle: GLfloat) -> Self {
        let cos = angle.cos();
        let sin = angle.sin();

        Mat4([
            [ cos, 0.0, sin, 0.0],
            [ 0.0, 1.0, 0.0, 0.0],
            [-sin, 0.0, cos, 0.0],
            [ 0.0, 0.0, 0.0, 1.0],
        ])
    }

    /// Build a matrix representing a rotation around the Z-axis by the given angle (in radians).
    pub fn rotate_z(angle: GLfloat) -> Self {
        let cos = angle.cos();
        let sin = angle.sin();

        Mat4([
            [cos, -sin, 0.0, 0.0],
            [sin,  cos, 0.0, 0.0],
            [0.0,  0.0, 1.0, 0.0],
            [0.0,  0.0, 0.0, 1.0],
        ])
    }
}

impl Index<usize> for Mat4 {
    type Output = [GLfloat; 4];

    fn index(&self, i: usize) -> &[GLfloat; 4] {
        &self.0[i]
    }
}

impl IndexMut<usize> for Mat4 {
    fn index_mut(&mut self, i: usize) -> &mut [GLfloat; 4] {
        &mut self.0[i]
    }
}

impl Mul<Mat4> for Mat4 {
    type Output = Mat4;

    fn mul(self, other: Mat4) -> Mat4 {
        let mut result = Mat4::zero();

        for i in 0..4 {
            for j in 0..4 {
                for k in 0..4 {
                    result[i][j] += self[i][k] * other[k][j];
                }
            }
        }

        result
    }
}

impl Mul<Vec4> for Mat4 {
    type Output = Vec4;

    fn mul(self, vec: Vec4) -> Vec4 {
        let mut result = Vec4::zero();

        for i in 0..4 {
            for j in 0..4 {
                result[i] += self[i][j] * vec[j];
            }
        }

        result
    }
}

#[test]
fn test_math() {
    let scale = Mat4::scale(2.0, 2.0, 2.0);
    let trans = Mat4::translate(1.0, 2.0, 3.0);
    let combined = trans * scale;

    let original = Vec4([3.0, 3.0, 3.0, 1.0]);
    let expected = Vec4([7.0, 8.0, 9.0, 1.0]);

    assert_eq!(expected, combined * original);
}
<commit_msg>Implement vector dot product.<commit_after>use gl::types::*;
use std::f32::consts::PI;
use std::ops::{Add, Index, IndexMut, Mul, Sub};

pub const TAU: GLfloat = 2.0 * PI;

macro_rules! define_vec {
    ($name:ident, $size:expr) => (
        #[derive(Copy, Clone, Debug, PartialEq)]
        pub struct $name(pub [GLfloat; $size]);

        impl $name {
            pub fn zero() -> Self {
                $name([0.0; $size])
            }

            /// Calculate the square of the length (or norm) of the vector. Slightly faster than
            /// `length`.
            pub fn length_squared(self) -> GLfloat {
                self.dot(self)
            }

            /// Calculate the the length (or norm) of the vector.
            pub fn length(self) -> GLfloat {
                self.length_squared().sqrt()
            }

            /// Normalize the vector so that it has the same orientation but a length of 1.
            pub fn normalize(&mut self) {
                let length = self.length();

                for i in 0..$size {
                    self[i] /= length;
                }
            }

            /// Calculate the vector dot product.
            pub fn dot(self, other: Self) -> GLfloat {
                let mut result = 0.0;

                for i in 0..$size {
                    result += self[i] * other[i];
                }

                result
            }
        }

        impl Index<usize> for $name {
            type Output = GLfloat;

            fn index(&self, i: usize) -> &GLfloat {
                &self.0[i]
            }
        }

        impl IndexMut<usize> for $name {
            fn index_mut(&mut self, i: usize) -> &mut GLfloat {
                &mut self.0[i]
            }
        }

        impl Add for $name {
            type Output = Self;

            fn add(self, other: Self) -> Self {
                let mut result = $name::zero();

                for i in 0..$size {
                    result[i] = self[i] + other[i];
                }

                result
            }
        }

        impl Sub for $name {
            type Output = Self;

            fn sub(self, other: Self) -> Self {
                let mut result = $name::zero();

                for i in 0..$size {
                    result[i] = self[i] - other[i];
                }

                result
            }
        }
    );
}

define_vec!(Vec3, 3);
define_vec!(Vec4, 4);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Mat4(pub [[GLfloat; 4]; 4]);

impl Mat4 {
    /// The zero matrix.
    pub fn zero() -> Self {
        Mat4([
            [0.0, 0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0, 0.0],
        ])
    }

    /// The identity matrix.
    pub fn identity() -> Self {
        Mat4([
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 1.0, 0.0, 0.0],
            [0.0, 0.0, 1.0, 0.0],
            [0.0, 0.0, 0.0, 1.0],
        ])
    }

    /// Build a matrix representing a scaling by the given factors.
    pub fn scale(x: GLfloat, y: GLfloat, z: GLfloat) -> Self {
        Mat4([
            [x,   0.0, 0.0, 0.0],
            [0.0, y,   0.0, 0.0],
            [0.0, 0.0, z,   0.0],
            [0.0, 0.0, 0.0, 1.0],
        ])
    }

    /// Build a matrix representing a translation.
    pub fn translate(x: GLfloat, y: GLfloat, z: GLfloat) -> Self {
        Mat4([
            [1.0, 0.0, 0.0, x  ],
            [0.0, 1.0, 0.0, y  ],
            [0.0, 0.0, 1.0, z  ],
            [0.0, 0.0, 0.0, 1.0],
        ])
    }

    /// Build a matrix representing a rotation around the X-axis by the given angle (in radians).
    pub fn rotate_x(angle: GLfloat) -> Self {
        let cos = angle.cos();
        let sin = angle.sin();

        Mat4([
            [1.0, 0.0,  0.0, 0.0],
            [0.0, cos, -sin, 0.0],
            [0.0, sin,  cos, 0.0],
            [0.0, 0.0,  0.0, 1.0],
        ])
    }

    /// Build a matrix representing a rotation around the Y-axis by the given angle (in radians).
    pub fn rotate_y(angle: GLfloat) -> Self {
        let cos = angle.cos();
        let sin = angle.sin();

        Mat4([
            [ cos, 0.0, sin, 0.0],
            [ 0.0, 1.0, 0.0, 0.0],
            [-sin, 0.0, cos, 0.0],
            [ 0.0, 0.0, 0.0, 1.0],
        ])
    }

    /// Build a matrix representing a rotation around the Z-axis by the given angle (in radians).
    pub fn rotate_z(angle: GLfloat) -> Self {
        let cos = angle.cos();
        let sin = angle.sin();

        Mat4([
            [cos, -sin, 0.0, 0.0],
            [sin,  cos, 0.0, 0.0],
            [0.0,  0.0, 1.0, 0.0],
            [0.0,  0.0, 0.0, 1.0],
        ])
    }
}

impl Index<usize> for Mat4 {
    type Output = [GLfloat; 4];

    fn index(&self, i: usize) -> &[GLfloat; 4] {
        &self.0[i]
    }
}

impl IndexMut<usize> for Mat4 {
    fn index_mut(&mut self, i: usize) -> &mut [GLfloat; 4] {
        &mut self.0[i]
    }
}

impl Mul<Mat4> for Mat4 {
    type Output = Mat4;

    fn mul(self, other: Mat4) -> Mat4 {
        let mut result = Mat4::zero();

        for i in 0..4 {
            for j in 0..4 {
                for k in 0..4 {
                    result[i][j] += self[i][k] * other[k][j];
                }
            }
        }

        result
    }
}

impl Mul<Vec4> for Mat4 {
    type Output = Vec4;

    fn mul(self, vec: Vec4) -> Vec4 {
        let mut result = Vec4::zero();

        for i in 0..4 {
            for j in 0..4 {
                result[i] += self[i][j] * vec[j];
            }
        }

        result
    }
}

#[test]
fn test_math() {
    let scale = Mat4::scale(2.0, 2.0, 2.0);
    let trans = Mat4::translate(1.0, 2.0, 3.0);
    let combined = trans * scale;

    let original = Vec4([3.0, 3.0, 3.0, 1.0]);
    let expected = Vec4([7.0, 8.0, 9.0, 1.0]);

    assert_eq!(expected, combined * original);
}
<|endoftext|>


<commit_before>extern crate llvm_tools;
extern crate target_build_utils;
extern crate walkdir;

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
#[cfg(feature = "mem")]
use std::process;
use std::process::Command;
use target_build_utils::TargetInfo;
use walkdir::{DirEntry, WalkDir};

fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) {
	let target = TargetInfo::new().expect("Could not get target info");
	let profile = env::var("PROFILE").expect("PROFILE was not set");
	let mut cmd = Command::new("cargo");

	if target.target_arch() == "x86_64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("x86_64-unknown-hermit-kernel");
	} else if target.target_arch() == "aarch64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("aarch64-unknown-hermit");
	} else {
		panic!("Try to build for an unsupported platform");
	}

	if let Some(target_dir) = target_dir_opt {
		cmd.arg("--target-dir").arg(target_dir);
	}
	let target_dir = match target_dir_opt {
		Some(target_dir) => target_dir.to_path_buf(),
		None => src_dir.join("target"),
	};

	if profile == "release" {
		cmd.arg("--release");
	}

	// disable all default features
	cmd.arg("--no-default-features");

	// do we have to enable PCI support?
	#[cfg(feature = "pci")]
	{
		cmd.arg("--features");
		cmd.arg("pci");
	}

	// do we have to enable acpi support?
	#[cfg(feature = "acpi")]
	{
		cmd.arg("--features");
		cmd.arg("acpi");
	}

	// do we have to enable FSGSBASE support?
	#[cfg(feature = "fsgs_base")]
	{
		cmd.arg("--features");
		cmd.arg("fsgs_base");
	}

	// do we support multi-processor systems?
	#[cfg(feature = "smp")]
	{
		cmd.arg("--features");
		cmd.arg("smp");
	}

	// do we have to enable VGA support
	#[cfg(feature = "vga")]
	{
		cmd.arg("--features");
		cmd.arg("vga");
	}

	#[cfg(feature = "instrument")]
	{
		cmd.env("RUSTFLAGS", "-Z instrument-mcount");
		// if instrument is not set, ensure that instrument is not in environment variables!
		cmd.env(
			"RUSTFLAGS",
			env::var("RUSTFLAGS")
				.unwrap_or_else(|_| "".into())
				.replace("-Z instrument-mcount", ""),
		);
	}

	let output = cmd.output().expect("Unable to build kernel");
	let stdout = std::string::String::from_utf8(output.stdout);
	let stderr = std::string::String::from_utf8(output.stderr);

	println!("Build libhermit-rs output-status: {}", output.status);
	println!("Build libhermit-rs output-stdout: {}", stdout.unwrap());
	println!("Build libhermit-rs output-stderr: {}", stderr.unwrap());
	assert!(output.status.success());

	let lib_location = if target.target_arch() == "x86_64" {
		target_dir
			.join("x86_64-unknown-hermit-kernel")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else if target.target_arch() == "aarch64" {
		target_dir
			.join("aarch64-unknown-hermit")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else {
		panic!("Try to build for an unsupported platform");
	};
	println!("Lib location: {}", lib_location.display());

	#[cfg(feature = "mem")]
	{
		// Kernel and user space has its own versions of memcpy, memset, etc,
		// Consequently, we rename the functions in the libos to avoid collisions.
		// In addition, it provides us the offer to create a optimized version of memcpy
		// in user space.

		// get access to llvm tools shipped in the llvm-tools-preview rustup component
		let llvm_tools = match llvm_tools::LlvmTools::new() {
			Ok(tools) => tools,
			Err(llvm_tools::Error::NotFound) => {
				eprintln!("Error: llvm-tools not found");
				eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?");
				eprintln!("  Install it through: `rustup component add llvm-tools-preview`");
				process::exit(1);
			}
			Err(err) => {
				eprintln!("Failed to retrieve llvm-tools component: {:?}", err);
				process::exit(1);
			}
		};

		let lib = lib_location.join("libhermit.a");

		let symbols: [&str; 5] = ["memcpy", "memmove", "memset", "memcmp", "bcmp"];
		for symbol in symbols.iter() {
			// determine llvm_objcopy
			let llvm_objcopy = llvm_tools
				.tool(&llvm_tools::exe("llvm-objcopy"))
				.expect("llvm_objcopy not found in llvm-tools");

			// rename symbols
			let mut cmd = Command::new(llvm_objcopy);
			cmd.arg("--redefine-sym")
				.arg(String::from(*symbol) + &String::from("=kernel") + &String::from(*symbol))
				.arg(lib.display().to_string());

			println!("cmd {:?}", cmd);
			let output = cmd.output().expect("Unable to rename symbols");
			let stdout = std::string::String::from_utf8(output.stdout);
			let stderr = std::string::String::from_utf8(output.stderr);
			println!("Rename symbols output-status: {}", output.status);
			println!("Rename symbols output-stdout: {}", stdout.unwrap());
			println!("Rename symbols output-stderr: {}", stderr.unwrap());
		}
	}

	println!("cargo:rustc-link-search=native={}", lib_location.display());
	println!("cargo:rustc-link-lib=static=hermit");

	//HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time
	// Doesn't actually rebuild atm - see: https://github.com/rust-lang/cargo/issues/8306
	println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER");
}

#[cfg(all(not(feature = "rustc-dep-of-std"), not(feature = "with_submodule")))]
fn build() {
	#[cfg(windows)]
	let out_dir = env::temp_dir();
	#[cfg(not(windows))]
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let src_dir = out_dir.join("rusty-hermit");

	let _output = Command::new("cargo")
		.current_dir(out_dir)
		.arg("download")
		.arg("--output")
		.arg(src_dir.clone().into_os_string())
		.arg("--extract")
		.arg("rusty-hermit")
		.output()
		.expect("Unable to download rusty-hermit. Please install `cargo-download`.");

	build_hermit(src_dir.as_ref(), None);
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn build() {
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let target_dir = out_dir.clone().join("target");
	let src_dir = env::current_dir()
		.unwrap()
		.parent()
		.unwrap()
		.join("libhermit-rs");

	build_hermit(src_dir.as_ref(), Some(target_dir.as_ref()));
	configure_cargo_rerun_if_changed(src_dir.as_ref());
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn configure_cargo_rerun_if_changed(src_dir: &Path) {
	fn is_not_ignored(entry: &DirEntry) -> bool {
		// Ignore .git .vscode and target directories, but not .cargo or .github
		if entry.depth() == 1
			&& entry.path().is_dir()
			&& (entry.path().ends_with("target")
				|| entry.path().ends_with(".git")
				|| entry.path().ends_with(".vscode"))
		{
			return false;
		}
		true
	}

	WalkDir::new(src_dir)
		.into_iter()
		.filter_entry(|e| is_not_ignored(e))
		.filter_map(|v| v.ok())
		.filter_map(|v| v.path().canonicalize().ok())
		.for_each(|x| println!("cargo:rerun-if-changed={}", x.display()));
}

#[cfg(not(feature = "rustc-dep-of-std"))]
fn create_constants() {
	let out_dir = env::var("OUT_DIR").expect("No out dir");
	let dest_path = Path::new(&out_dir).join("constants.rs");
	let mut f = File::create(&dest_path).expect("Could not create file");

	let ip = option_env!("HERMIT_IP");
	let ip = ip.map_or("10.0.5.3", |v| v);

	let gateway = option_env!("HERMIT_GATEWAY");
	let gateway = gateway.map_or("10.0.5.1", |v| v);

	let mask = option_env!("HERMIT_MASK");
	let mask = mask.map_or("255.255.255.0", |v| v);

	writeln!(&mut f, "const HERMIT_IP: &str = \"{}\";", ip).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_IP");

	writeln!(&mut f, "const HERMIT_GATEWAY: &str = \"{}\";", gateway)
		.expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_GATEWAY");

	writeln!(&mut f, "const HERMIT_MASK: &str = \"{}\";", mask).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_MASK");
}

fn main() {
	#[cfg(not(feature = "rustc-dep-of-std"))]
	create_constants();
	#[cfg(not(feature = "rustc-dep-of-std"))]
	build();
}
<commit_msg>rename target to build libos<commit_after>extern crate llvm_tools;
extern crate target_build_utils;
extern crate walkdir;

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
#[cfg(feature = "mem")]
use std::process;
use std::process::Command;
use target_build_utils::TargetInfo;
use walkdir::{DirEntry, WalkDir};

fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) {
	let target = TargetInfo::new().expect("Could not get target info");
	let profile = env::var("PROFILE").expect("PROFILE was not set");
	let mut cmd = Command::new("cargo");

	if target.target_arch() == "x86_64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("x86_64-unknown-none-hermitkernel");
	} else if target.target_arch() == "aarch64" {
		cmd.current_dir(src_dir)
			.arg("build")
			.arg("-Z")
			.arg("build-std=core,alloc")
			.arg("--target")
			.arg("aarch64-unknown-hermit");
	} else {
		panic!("Try to build for an unsupported platform");
	}

	if let Some(target_dir) = target_dir_opt {
		cmd.arg("--target-dir").arg(target_dir);
	}
	let target_dir = match target_dir_opt {
		Some(target_dir) => target_dir.to_path_buf(),
		None => src_dir.join("target"),
	};

	if profile == "release" {
		cmd.arg("--release");
	}

	// disable all default features
	cmd.arg("--no-default-features");

	// do we have to enable PCI support?
	#[cfg(feature = "pci")]
	{
		cmd.arg("--features");
		cmd.arg("pci");
	}

	// do we have to enable acpi support?
	#[cfg(feature = "acpi")]
	{
		cmd.arg("--features");
		cmd.arg("acpi");
	}

	// do we have to enable FSGSBASE support?
	#[cfg(feature = "fsgs_base")]
	{
		cmd.arg("--features");
		cmd.arg("fsgs_base");
	}

	// do we support multi-processor systems?
	#[cfg(feature = "smp")]
	{
		cmd.arg("--features");
		cmd.arg("smp");
	}

	// do we have to enable VGA support
	#[cfg(feature = "vga")]
	{
		cmd.arg("--features");
		cmd.arg("vga");
	}

	#[cfg(feature = "instrument")]
	{
		cmd.env("RUSTFLAGS", "-Z instrument-mcount");
		// if instrument is not set, ensure that instrument is not in environment variables!
		cmd.env(
			"RUSTFLAGS",
			env::var("RUSTFLAGS")
				.unwrap_or_else(|_| "".into())
				.replace("-Z instrument-mcount", ""),
		);
	}

	let output = cmd.output().expect("Unable to build kernel");
	let stdout = std::string::String::from_utf8(output.stdout);
	let stderr = std::string::String::from_utf8(output.stderr);

	println!("Build libhermit-rs output-status: {}", output.status);
	println!("Build libhermit-rs output-stdout: {}", stdout.unwrap());
	println!("Build libhermit-rs output-stderr: {}", stderr.unwrap());
	assert!(output.status.success());

	let lib_location = if target.target_arch() == "x86_64" {
		target_dir
			.join("x86_64-unknown-none-hermitkernel")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else if target.target_arch() == "aarch64" {
		target_dir
			.join("aarch64-unknown-hermit")
			.join(&profile)
			.canonicalize()
			.unwrap() // Must exist after building
	} else {
		panic!("Try to build for an unsupported platform");
	};
	println!("Lib location: {}", lib_location.display());

	#[cfg(feature = "mem")]
	{
		// Kernel and user space has its own versions of memcpy, memset, etc,
		// Consequently, we rename the functions in the libos to avoid collisions.
		// In addition, it provides us the offer to create a optimized version of memcpy
		// in user space.

		// get access to llvm tools shipped in the llvm-tools-preview rustup component
		let llvm_tools = match llvm_tools::LlvmTools::new() {
			Ok(tools) => tools,
			Err(llvm_tools::Error::NotFound) => {
				eprintln!("Error: llvm-tools not found");
				eprintln!("Maybe the rustup component `llvm-tools-preview` is missing?");
				eprintln!("  Install it through: `rustup component add llvm-tools-preview`");
				process::exit(1);
			}
			Err(err) => {
				eprintln!("Failed to retrieve llvm-tools component: {:?}", err);
				process::exit(1);
			}
		};

		let lib = lib_location.join("libhermit.a");

		let symbols: [&str; 5] = ["memcpy", "memmove", "memset", "memcmp", "bcmp"];
		for symbol in symbols.iter() {
			// determine llvm_objcopy
			let llvm_objcopy = llvm_tools
				.tool(&llvm_tools::exe("llvm-objcopy"))
				.expect("llvm_objcopy not found in llvm-tools");

			// rename symbols
			let mut cmd = Command::new(llvm_objcopy);
			cmd.arg("--redefine-sym")
				.arg(String::from(*symbol) + &String::from("=kernel") + &String::from(*symbol))
				.arg(lib.display().to_string());

			println!("cmd {:?}", cmd);
			let output = cmd.output().expect("Unable to rename symbols");
			let stdout = std::string::String::from_utf8(output.stdout);
			let stderr = std::string::String::from_utf8(output.stderr);
			println!("Rename symbols output-status: {}", output.status);
			println!("Rename symbols output-stdout: {}", stdout.unwrap());
			println!("Rename symbols output-stderr: {}", stderr.unwrap());
		}
	}

	println!("cargo:rustc-link-search=native={}", lib_location.display());
	println!("cargo:rustc-link-lib=static=hermit");

	//HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time
	// Doesn't actually rebuild atm - see: https://github.com/rust-lang/cargo/issues/8306
	println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER");
}

#[cfg(all(not(feature = "rustc-dep-of-std"), not(feature = "with_submodule")))]
fn build() {
	#[cfg(windows)]
	let out_dir = env::temp_dir();
	#[cfg(not(windows))]
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let src_dir = out_dir.join("rusty-hermit");

	let _output = Command::new("cargo")
		.current_dir(out_dir)
		.arg("download")
		.arg("--output")
		.arg(src_dir.clone().into_os_string())
		.arg("--extract")
		.arg("rusty-hermit")
		.output()
		.expect("Unable to download rusty-hermit. Please install `cargo-download`.");

	build_hermit(src_dir.as_ref(), None);
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn build() {
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let target_dir = out_dir.clone().join("target");
	let src_dir = env::current_dir()
		.unwrap()
		.parent()
		.unwrap()
		.join("libhermit-rs");

	build_hermit(src_dir.as_ref(), Some(target_dir.as_ref()));
	configure_cargo_rerun_if_changed(src_dir.as_ref());
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn configure_cargo_rerun_if_changed(src_dir: &Path) {
	fn is_not_ignored(entry: &DirEntry) -> bool {
		// Ignore .git .vscode and target directories, but not .cargo or .github
		if entry.depth() == 1
			&& entry.path().is_dir()
			&& (entry.path().ends_with("target")
				|| entry.path().ends_with(".git")
				|| entry.path().ends_with(".vscode"))
		{
			return false;
		}
		true
	}

	WalkDir::new(src_dir)
		.into_iter()
		.filter_entry(|e| is_not_ignored(e))
		.filter_map(|v| v.ok())
		.filter_map(|v| v.path().canonicalize().ok())
		.for_each(|x| println!("cargo:rerun-if-changed={}", x.display()));
}

#[cfg(not(feature = "rustc-dep-of-std"))]
fn create_constants() {
	let out_dir = env::var("OUT_DIR").expect("No out dir");
	let dest_path = Path::new(&out_dir).join("constants.rs");
	let mut f = File::create(&dest_path).expect("Could not create file");

	let ip = option_env!("HERMIT_IP");
	let ip = ip.map_or("10.0.5.3", |v| v);

	let gateway = option_env!("HERMIT_GATEWAY");
	let gateway = gateway.map_or("10.0.5.1", |v| v);

	let mask = option_env!("HERMIT_MASK");
	let mask = mask.map_or("255.255.255.0", |v| v);

	writeln!(&mut f, "const HERMIT_IP: &str = \"{}\";", ip).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_IP");

	writeln!(&mut f, "const HERMIT_GATEWAY: &str = \"{}\";", gateway)
		.expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_GATEWAY");

	writeln!(&mut f, "const HERMIT_MASK: &str = \"{}\";", mask).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_MASK");
}

fn main() {
	#[cfg(not(feature = "rustc-dep-of-std"))]
	create_constants();
	#[cfg(not(feature = "rustc-dep-of-std"))]
	build();
}
<|endoftext|>


<commit_before>extern crate walkdir;

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::Command;

use walkdir::{DirEntry, WalkDir};

fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) {
	let profile = env::var("PROFILE").expect("PROFILE was not set");
	let mut cmd = Command::new("cargo");
	cmd.current_dir(src_dir)
		.arg("build")
		.arg("-Z")
		.arg("build-std=core,alloc")
		.arg("--target")
		.arg("x86_64-unknown-hermit-kernel");

	if let Some(target_dir) = target_dir_opt {
		cmd.arg("--target-dir").arg(target_dir);
	}
	let target_dir = match target_dir_opt {
		Some(target_dir) => target_dir.to_path_buf(),
		None => src_dir.join("target"),
	};

	if profile == "release" {
		cmd.arg("--release");
	}

	#[cfg(feature = "instrument")]
	cmd.env("RUSTFLAGS", "-Z instrument-mcount");
	// if instrument is not set, ensure that instrument is not in environment variables!
	#[cfg(not(feature = "instrument"))]
	cmd.env(
		"RUSTFLAGS",
		env::var("RUSTFLAGS")
			.unwrap_or_else(|_| "".into())
			.replace("-Z instrument-mcount", ""),
	);

	let output = cmd.output().expect("Unable to build kernel");
	let stdout = std::string::String::from_utf8(output.stdout);
	let stderr = std::string::String::from_utf8(output.stderr);

	println!("Build libhermit-rs output-status: {}", output.status);
	println!("Build libhermit-rs output-stdout: {}", stdout.unwrap());
	println!("Build libhermit-rs output-stderr: {}", stderr.unwrap());
	assert!(output.status.success());

	let lib_location = target_dir
		.join("x86_64-unknown-hermit-kernel")
		.join(&profile)
		.canonicalize()
		.unwrap(); // Must exist after building
	println!("cargo:rustc-link-search=native={}", lib_location.display());
	println!("cargo:rustc-link-lib=static=hermit");

	//HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time
	// Doesn't actually rebuild atm - see: https://github.com/rust-lang/cargo/issues/8306
	println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER");
}

#[cfg(all(not(feature = "rustc-dep-of-std"), not(feature = "with_submodule")))]
fn build() {
	#[cfg(windows)]
	let out_dir = env::temp_dir();
	#[cfg(not(windows))]
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let src_dir = out_dir.join("rusty-hermit");

	let _output = Command::new("cargo")
		.current_dir(out_dir)
		.arg("download")
		.arg("--output")
		.arg(src_dir.clone().into_os_string())
		.arg("--extract")
		.arg("rusty-hermit")
		.output()
		.expect("Unable to download rusty-hermit. Please install `cargo-download`.");

	build_hermit(src_dir.as_ref(), None);
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn build() {
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let target_dir = out_dir.clone().join("target");
	let src_dir = env::current_dir()
		.unwrap()
		.parent()
		.unwrap()
		.join("libhermit-rs");

	build_hermit(src_dir.as_ref(), Some(target_dir.as_ref()));
	configure_cargo_rerun_if_changed(src_dir.as_ref());
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn configure_cargo_rerun_if_changed(src_dir: &Path) {
	fn is_not_ignored(entry: &DirEntry) -> bool {
		// Ignore .git .vscode and target directories, but not .cargo or .github
		if entry.depth() == 1
			&& entry.path().is_dir()
			&& (entry.path().ends_with("target")
				|| entry.path().ends_with(".git")
				|| entry.path().ends_with(".vscode"))
		{
			return false;
		}
		true
	}

	WalkDir::new(src_dir)
		.into_iter()
		.filter_entry(|e| is_not_ignored(e))
		.filter_map(|v| v.ok())
		.filter_map(|v| v.path().canonicalize().ok())
		.for_each(|x| println!("cargo:rerun-if-changed={}", x.display()));
}

#[cfg(not(feature = "rustc-dep-of-std"))]
fn create_constants() {
	let out_dir = env::var("OUT_DIR").expect("No out dir");
	let dest_path = Path::new(&out_dir).join("constants.rs");
	let mut f = File::create(&dest_path).expect("Could not create file");

	let ip = option_env!("HERMIT_IP");
	let ip = ip.map_or("\"10.0.5.3\"", |v| v);

	let gateway = option_env!("HERMIT_GATEWAY");
	let gateway = gateway.map_or("\"10.0.5.1\"", |v| v);

	let mask = option_env!("HERMIT_MASK");
	let mask = mask.map_or("\"255.255.255.0\"", |v| v);

	writeln!(&mut f, "const HERMIT_IP: &str = {};", ip).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_IP");

	writeln!(&mut f, "const HERMIT_GATEWAY: &str = {};", gateway).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_GATEWAY");

	writeln!(&mut f, "const HERMIT_MASK: &str = {};", mask).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_MASK");
}

fn main() {
	#[cfg(not(feature = "rustc-dep-of-std"))]
	create_constants();
	#[cfg(not(feature = "rustc-dep-of-std"))]
	build();
}
<commit_msg>add option to define the static IP<commit_after>extern crate walkdir;

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::Command;

use walkdir::{DirEntry, WalkDir};

fn build_hermit(src_dir: &Path, target_dir_opt: Option<&Path>) {
	let profile = env::var("PROFILE").expect("PROFILE was not set");
	let mut cmd = Command::new("cargo");
	cmd.current_dir(src_dir)
		.arg("build")
		.arg("-Z")
		.arg("build-std=core,alloc")
		.arg("--target")
		.arg("x86_64-unknown-hermit-kernel");

	if let Some(target_dir) = target_dir_opt {
		cmd.arg("--target-dir").arg(target_dir);
	}
	let target_dir = match target_dir_opt {
		Some(target_dir) => target_dir.to_path_buf(),
		None => src_dir.join("target"),
	};

	if profile == "release" {
		cmd.arg("--release");
	}

	#[cfg(feature = "instrument")]
	cmd.env("RUSTFLAGS", "-Z instrument-mcount");
	// if instrument is not set, ensure that instrument is not in environment variables!
	#[cfg(not(feature = "instrument"))]
	cmd.env(
		"RUSTFLAGS",
		env::var("RUSTFLAGS")
			.unwrap_or_else(|_| "".into())
			.replace("-Z instrument-mcount", ""),
	);

	let output = cmd.output().expect("Unable to build kernel");
	let stdout = std::string::String::from_utf8(output.stdout);
	let stderr = std::string::String::from_utf8(output.stderr);

	println!("Build libhermit-rs output-status: {}", output.status);
	println!("Build libhermit-rs output-stdout: {}", stdout.unwrap());
	println!("Build libhermit-rs output-stderr: {}", stderr.unwrap());
	assert!(output.status.success());

	let lib_location = target_dir
		.join("x86_64-unknown-hermit-kernel")
		.join(&profile)
		.canonicalize()
		.unwrap(); // Must exist after building
	println!("cargo:rustc-link-search=native={}", lib_location.display());
	println!("cargo:rustc-link-lib=static=hermit");

	//HERMIT_LOG_LEVEL_FILTER sets the log level filter at compile time
	// Doesn't actually rebuild atm - see: https://github.com/rust-lang/cargo/issues/8306
	println!("cargo:rerun-if-env-changed=HERMIT_LOG_LEVEL_FILTER");
}

#[cfg(all(not(feature = "rustc-dep-of-std"), not(feature = "with_submodule")))]
fn build() {
	#[cfg(windows)]
	let out_dir = env::temp_dir();
	#[cfg(not(windows))]
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let src_dir = out_dir.join("rusty-hermit");

	let _output = Command::new("cargo")
		.current_dir(out_dir)
		.arg("download")
		.arg("--output")
		.arg(src_dir.clone().into_os_string())
		.arg("--extract")
		.arg("rusty-hermit")
		.output()
		.expect("Unable to download rusty-hermit. Please install `cargo-download`.");

	build_hermit(src_dir.as_ref(), None);
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn build() {
	let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
	let target_dir = out_dir.clone().join("target");
	let src_dir = env::current_dir()
		.unwrap()
		.parent()
		.unwrap()
		.join("libhermit-rs");

	build_hermit(src_dir.as_ref(), Some(target_dir.as_ref()));
	configure_cargo_rerun_if_changed(src_dir.as_ref());
}

#[cfg(all(not(feature = "rustc-dep-of-std"), feature = "with_submodule"))]
fn configure_cargo_rerun_if_changed(src_dir: &Path) {
	fn is_not_ignored(entry: &DirEntry) -> bool {
		// Ignore .git .vscode and target directories, but not .cargo or .github
		if entry.depth() == 1
			&& entry.path().is_dir()
			&& (entry.path().ends_with("target")
				|| entry.path().ends_with(".git")
				|| entry.path().ends_with(".vscode"))
		{
			return false;
		}
		true
	}

	WalkDir::new(src_dir)
		.into_iter()
		.filter_entry(|e| is_not_ignored(e))
		.filter_map(|v| v.ok())
		.filter_map(|v| v.path().canonicalize().ok())
		.for_each(|x| println!("cargo:rerun-if-changed={}", x.display()));
}

#[cfg(not(feature = "rustc-dep-of-std"))]
fn create_constants() {
	let out_dir = env::var("OUT_DIR").expect("No out dir");
	let dest_path = Path::new(&out_dir).join("constants.rs");
	let mut f = File::create(&dest_path).expect("Could not create file");

	let ip = option_env!("HERMIT_IP");
	let ip = ip.map_or("10.0.5.3", |v| v);

	let gateway = option_env!("HERMIT_GATEWAY");
	let gateway = gateway.map_or("10.0.5.1", |v| v);

	let mask = option_env!("HERMIT_MASK");
	let mask = mask.map_or("255.255.255.0", |v| v);

	writeln!(&mut f, "const HERMIT_IP: &str = \"{}\";", ip).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_IP");

	writeln!(&mut f, "const HERMIT_GATEWAY: &str = \"{}\";", gateway).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_GATEWAY");

	writeln!(&mut f, "const HERMIT_MASK: &str = \"{}\";", mask).expect("Could not write file");
	println!("cargo:rerun-if-env-changed=HERMIT_MASK");
}

fn main() {
	#[cfg(not(feature = "rustc-dep-of-std"))]
	create_constants();
	#[cfg(not(feature = "rustc-dep-of-std"))]
	build();
}
<|endoftext|>


<commit_before>//! The serialization inputs for metadata. Covers both YAML metadata in headers
//! and associated data from JSON/TOML/YAML/JSON5/whatever else I decide to
//! support in data files.

use chrono::{DateTime, FixedOffset};
use serde_derive::Deserialize;

#[derive(Deserialize, Debug)]
pub(super) struct Metadata {
    pub(super) title: Option<String>,
    pub(super) subtitle: Option<String>,
    pub(super) summary: Option<String>,
    pub(super) qualifiers: Option<Qualifiers>,
    pub(super) date: Option<DateTime<FixedOffset>>,
    pub(super) updated: Option<DateTime<FixedOffset>>,
    pub(super) permalink: Option<String>,
    pub(super) thanks: Option<String>,
    #[serde(default)]
    pub(super) tags: Vec<String>,
    #[serde(default)]
    pub(super) featured: bool,
    pub(super) layout: Option<String>,
    pub(super) book: Option<Book>,
    pub(super) series: Option<Series>,
    pub(super) subscribe: Option<Subscribe>,
}

#[derive(Deserialize, Debug)]
pub(super) struct Qualifiers {
    audience: Option<String>,
    epistemic: Option<String>,
}

#[derive(Deserialize, Debug)]
pub(super) struct Subscribe {
    atom: Option<String>,
    json: Option<String>,
}

// TODO: This is correct for final output, but I *currently* have a bunch of
// things being handled by "the cascade" in 11ty, and this *cannot* handle that.
// As with a bunch of other things, the input from disk should have more options
// and then the final merged data fewer.
#[derive(Deserialize, Debug)]
pub(super) struct Book {
    title: String,
    author: String,
    /// Year is a `String`, rather than something like a `u16`, because years
    /// are a lot more complicated than a number represents. If I write "400
    /// B.C.", for example, the system should still work.
    year: String,
    editors: Option<Vec<String>>,
    translators: Option<Vec<String>>,
    cover: Option<String>,
    link: Option<String>,
    review: Option<Review>,
}

#[derive(Deserialize, Debug)]
pub(super) struct Review {
    rating: Rating,
    summary: String,
}

// TODO: right now this assumes it can be deserialized from the associated text,
// but in fact it should be derived from the same text as its `Display`
// implementation below. (A later enhancement: converting "****" etc. to it or
// something cool like that.)
#[derive(Deserialize, Debug)]
enum Rating {
    NotRecommended,
    WithQualifications,
    Recommended,
    Required,
}

impl std::fmt::Display for Rating {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match self {
                Rating::NotRecommended => "Not recommended",
                Rating::WithQualifications => "Recommended with qualifications",
                Rating::Recommended => "Recommended",
                Rating::Required => "Required",
            }
        )
    }
}

#[derive(Deserialize, Debug)]
pub(super) struct Series {
    name: String,
    part: u8,
}
<commit_msg>Improve de/serialization for `Book`<commit_after>//! The serialization inputs for metadata. Covers both YAML metadata in headers
//! and associated data from JSON/TOML/YAML/JSON5/whatever else I decide to
//! support in data files.

use std::str::FromStr;

use chrono::{DateTime, FixedOffset};
use serde::{de, Deserialize, Deserializer};
use serde_derive::Deserialize;

#[derive(Deserialize, Debug)]
pub(super) struct Metadata {
    pub(super) title: Option<String>,
    pub(super) subtitle: Option<String>,
    pub(super) summary: Option<String>,
    pub(super) qualifiers: Option<Qualifiers>,
    pub(super) date: Option<DateTime<FixedOffset>>,
    pub(super) updated: Option<DateTime<FixedOffset>>,
    pub(super) permalink: Option<String>,
    pub(super) thanks: Option<String>,
    #[serde(default)]
    pub(super) tags: Vec<String>,
    #[serde(default)]
    pub(super) featured: bool,
    pub(super) layout: Option<String>,
    pub(super) book: Option<Book>,
    pub(super) series: Option<Series>,
    pub(super) subscribe: Option<Subscribe>,
}

#[derive(Deserialize, Debug)]
pub(super) struct Qualifiers {
    audience: Option<String>,
    epistemic: Option<String>,
}

#[derive(Deserialize, Debug)]
pub(super) struct Subscribe {
    atom: Option<String>,
    json: Option<String>,
}

// TODO: This is correct for final output, but I *currently* have a bunch of
// things being handled by "the cascade" in 11ty, and this *cannot* handle that.
// As with a bunch of other things, the input from disk should have more options
// and then the final merged data fewer.
#[derive(Deserialize, Debug)]
pub(super) struct Book {
    title: Option<String>,
    author: Option<String>,
    /// Year is a `String`, rather than something like a `u16`, because years
    /// are a lot more complicated than a number represents. If I write "400
    /// B.C.", for example, the system should still work.
    year: Option<String>,
    editors: Option<Vec<String>>,
    translators: Option<Vec<String>>,
    cover: Option<String>,
    link: Option<String>,
    review: Option<Review>,
}

#[derive(Deserialize, Debug)]
pub(super) struct Review {
    rating: Rating,
    summary: String,
}

// TODO: right now this assumes it can be deserialized from the associated text,
// but in fact it should be derived from the same text as its `Display`
// implementation below. (A later enhancement: converting "****" etc. to it or
// something cool like that.)
#[derive(Deserialize, Debug)]
enum Rating {
    #[serde(rename = "Not recommended")]
    NotRecommended,
    #[serde(rename = "Recommended with qualifications")]
    WithQualifications,
    #[serde(rename = "Recommended")]
    Recommended,
    #[serde(rename = "Required")]
    Required,
}

impl std::fmt::Display for Rating {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match self {
                Rating::NotRecommended => "Not recommended",
                Rating::WithQualifications => "Recommended with qualifications",
                Rating::Recommended => "Recommended",
                Rating::Required => "Required",
            }
        )
    }
}

#[derive(Deserialize, Debug)]
pub(super) struct Series {
    name: String,
    part: u8,
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use crate::arch::x86_64::kernel::syscall_handler;
use crate::logging::*;
use crate::scheduler::task::BOOT_STACK;
use x86::controlregs::*;
use x86::cpuid::*;
use x86::io::*;
use x86::msr::*;

// MSR EFER bits
const EFER_SCE: u64 = 1 << 0;
const EFER_LME: u64 = 1 << 8;
const EFER_LMA: u64 = 1 << 10;
const EFER_NXE: u64 = 1 << 11;
const EFER_SVME: u64 = 1 << 12;
const EFER_LMSLE: u64 = 1 << 13;
const EFER_FFXSR: u64 = 1 << 14;
const EFER_TCE: u64 = 1 << 15;

static mut PHYSICAL_ADDRESS_BITS: u8 = 0;
static mut LINEAR_ADDRESS_BITS: u8 = 0;
static mut SUPPORTS_1GIB_PAGES: bool = false;

/// Force strict CPU ordering, serializes load and store operations.
#[inline(always)]
pub fn mb() {
	unsafe {
		asm!("mfence", options(nostack));
	}
}

/// Search the most significant bit
#[inline(always)]
pub fn msb(value: u64) -> Option<u64> {
	println!("value {}", value);
	if value > 0 {
		let ret: u64;
		unsafe {
			asm!("bsr {0}, {1}",
			    out(reg) ret,
				in(reg) value,
			    options(nomem, nostack)
			);
		}
		println!("value {} {}", value, ret);
		Some(ret)
	} else {
		None
	}
}

/// Search the least significant bit
#[inline(always)]
pub fn lsb(value: u64) -> Option<u64> {
	if value > 0 {
		let ret: u64;
		unsafe {
			asm!("bsf {0}, {1}",
			    out(reg) ret,
				in(reg) value,
			    options(nomem, nostack)
			);
		}
		Some(ret)
	} else {
		None
	}
}

#[inline(always)]
pub fn halt() {
	unsafe {
		asm!("hlt", options(nomem, nostack));
	}
}

#[inline(always)]
pub fn pause() {
	unsafe {
		asm!("pause", options(nomem, nostack));
	}
}

#[no_mangle]
pub extern "C" fn shutdown() -> ! {
	// shutdown, works like Qemu's shutdown command
	unsafe {
		outb(0xf4, 0x00);
	}

	loop {
		halt();
	}
}

pub fn supports_1gib_pages() -> bool {
	unsafe { SUPPORTS_1GIB_PAGES }
}

pub fn get_linear_address_bits() -> u8 {
	unsafe { LINEAR_ADDRESS_BITS }
}

pub fn get_physical_address_bits() -> u8 {
	unsafe { PHYSICAL_ADDRESS_BITS }
}

pub fn init() {
	debug!("enable supported processor features");

	let cpuid = CpuId::new();

	let mut cr0 = unsafe { cr0() };

	// be sure that AM, NE and MP is enabled
	cr0 = cr0 | Cr0::CR0_ALIGNMENT_MASK;
	cr0 = cr0 | Cr0::CR0_NUMERIC_ERROR;
	cr0 = cr0 | Cr0::CR0_MONITOR_COPROCESSOR;
	// enable cache
	cr0 = cr0 & !(Cr0::CR0_CACHE_DISABLE | Cr0::CR0_NOT_WRITE_THROUGH);

	debug!("set CR0 to {:?}", cr0);

	unsafe { cr0_write(cr0) };

	let mut cr4 = unsafe { cr4() };

	let has_pge = match cpuid.get_feature_info() {
		Some(finfo) => finfo.has_pge(),
		None => false,
	};

	if has_pge {
		cr4 |= Cr4::CR4_ENABLE_GLOBAL_PAGES;
	}

	let has_fsgsbase = match cpuid.get_extended_feature_info() {
		Some(efinfo) => efinfo.has_fsgsbase(),
		None => false,
	};

	if has_fsgsbase {
		cr4 |= Cr4::CR4_ENABLE_FSGSBASE;
	} else {
		panic!("eduOS-rs requires the CPU feature FSGSBASE");
	}

	let has_mce = match cpuid.get_feature_info() {
		Some(finfo) => finfo.has_mce(),
		None => false,
	};

	if has_mce {
		cr4 |= Cr4::CR4_ENABLE_MACHINE_CHECK; // enable machine check exceptions
	}

	// disable performance monitoring counter
	// allow the usage of rdtsc in user space
	cr4 &= !(Cr4::CR4_ENABLE_PPMC | Cr4::CR4_TIME_STAMP_DISABLE);

	debug!("set CR4 to {:?}", cr4);

	unsafe { cr4_write(cr4) };

	let has_syscall = match cpuid.get_extended_function_info() {
		Some(finfo) => finfo.has_syscall_sysret(),
		None => false,
	};

	if has_syscall == false {
		panic!("Syscall support is missing");
	}

	// enable support of syscall and sysret
	unsafe {
		wrmsr(IA32_EFER, rdmsr(IA32_EFER) | EFER_LMA | EFER_SCE | EFER_NXE);
		wrmsr(IA32_STAR, (0x1Bu64 << 48) | (0x08u64 << 32));
		wrmsr(IA32_LSTAR, syscall_handler as u64);
		wrmsr(IA32_FMASK, 1 << 9); // clear IF flag during system call

		// reset GS registers
		wrmsr(IA32_GS_BASE, 0);
		asm!("wrgsbase {}", in(reg) BOOT_STACK.top());
	}

	// determin processor features
	let extended_function_info = cpuid
		.get_extended_function_info()
		.expect("CPUID Extended Function Info not available!");
	unsafe {
		PHYSICAL_ADDRESS_BITS = extended_function_info
			.physical_address_bits()
			.expect("CPUID Physical Address Bits not available!");
		LINEAR_ADDRESS_BITS = extended_function_info
			.linear_address_bits()
			.expect("CPUID Linear Address Bits not available!");
		SUPPORTS_1GIB_PAGES = extended_function_info.has_1gib_pages();
	}

	if supports_1gib_pages() {
		info!("System supports 1GiB pages");
	}
	debug!("Physical address bits {}", get_physical_address_bits());
	debug!("Linear address bits {}", get_linear_address_bits());
	debug!("CR0: {:?}", cr0);
	debug!("CR4: {:?}", cr4);
}
<commit_msg>remove debug messages<commit_after>#![allow(dead_code)]

use crate::arch::x86_64::kernel::syscall_handler;
use crate::logging::*;
use crate::scheduler::task::BOOT_STACK;
use x86::controlregs::*;
use x86::cpuid::*;
use x86::io::*;
use x86::msr::*;

// MSR EFER bits
const EFER_SCE: u64 = 1 << 0;
const EFER_LME: u64 = 1 << 8;
const EFER_LMA: u64 = 1 << 10;
const EFER_NXE: u64 = 1 << 11;
const EFER_SVME: u64 = 1 << 12;
const EFER_LMSLE: u64 = 1 << 13;
const EFER_FFXSR: u64 = 1 << 14;
const EFER_TCE: u64 = 1 << 15;

static mut PHYSICAL_ADDRESS_BITS: u8 = 0;
static mut LINEAR_ADDRESS_BITS: u8 = 0;
static mut SUPPORTS_1GIB_PAGES: bool = false;

/// Force strict CPU ordering, serializes load and store operations.
#[inline(always)]
pub fn mb() {
	unsafe {
		asm!("mfence", options(nostack));
	}
}

/// Search the most significant bit
#[inline(always)]
pub fn msb(value: u64) -> Option<u64> {
	if value > 0 {
		let ret: u64;
		unsafe {
			asm!("bsr {0}, {1}",
			    out(reg) ret,
				in(reg) value,
			    options(nomem, nostack)
			);
		}
		Some(ret)
	} else {
		None
	}
}

/// Search the least significant bit
#[inline(always)]
pub fn lsb(value: u64) -> Option<u64> {
	if value > 0 {
		let ret: u64;
		unsafe {
			asm!("bsf {0}, {1}",
			    out(reg) ret,
				in(reg) value,
			    options(nomem, nostack)
			);
		}
		Some(ret)
	} else {
		None
	}
}

#[inline(always)]
pub fn halt() {
	unsafe {
		asm!("hlt", options(nomem, nostack));
	}
}

#[inline(always)]
pub fn pause() {
	unsafe {
		asm!("pause", options(nomem, nostack));
	}
}

#[no_mangle]
pub extern "C" fn shutdown() -> ! {
	// shutdown, works like Qemu's shutdown command
	unsafe {
		outb(0xf4, 0x00);
	}

	loop {
		halt();
	}
}

pub fn supports_1gib_pages() -> bool {
	unsafe { SUPPORTS_1GIB_PAGES }
}

pub fn get_linear_address_bits() -> u8 {
	unsafe { LINEAR_ADDRESS_BITS }
}

pub fn get_physical_address_bits() -> u8 {
	unsafe { PHYSICAL_ADDRESS_BITS }
}

pub fn init() {
	debug!("enable supported processor features");

	let cpuid = CpuId::new();

	let mut cr0 = unsafe { cr0() };

	// be sure that AM, NE and MP is enabled
	cr0 = cr0 | Cr0::CR0_ALIGNMENT_MASK;
	cr0 = cr0 | Cr0::CR0_NUMERIC_ERROR;
	cr0 = cr0 | Cr0::CR0_MONITOR_COPROCESSOR;
	// enable cache
	cr0 = cr0 & !(Cr0::CR0_CACHE_DISABLE | Cr0::CR0_NOT_WRITE_THROUGH);

	debug!("set CR0 to {:?}", cr0);

	unsafe { cr0_write(cr0) };

	let mut cr4 = unsafe { cr4() };

	let has_pge = match cpuid.get_feature_info() {
		Some(finfo) => finfo.has_pge(),
		None => false,
	};

	if has_pge {
		cr4 |= Cr4::CR4_ENABLE_GLOBAL_PAGES;
	}

	let has_fsgsbase = match cpuid.get_extended_feature_info() {
		Some(efinfo) => efinfo.has_fsgsbase(),
		None => false,
	};

	if has_fsgsbase {
		cr4 |= Cr4::CR4_ENABLE_FSGSBASE;
	} else {
		panic!("eduOS-rs requires the CPU feature FSGSBASE");
	}

	let has_mce = match cpuid.get_feature_info() {
		Some(finfo) => finfo.has_mce(),
		None => false,
	};

	if has_mce {
		cr4 |= Cr4::CR4_ENABLE_MACHINE_CHECK; // enable machine check exceptions
	}

	// disable performance monitoring counter
	// allow the usage of rdtsc in user space
	cr4 &= !(Cr4::CR4_ENABLE_PPMC | Cr4::CR4_TIME_STAMP_DISABLE);

	debug!("set CR4 to {:?}", cr4);

	unsafe { cr4_write(cr4) };

	let has_syscall = match cpuid.get_extended_function_info() {
		Some(finfo) => finfo.has_syscall_sysret(),
		None => false,
	};

	if has_syscall == false {
		panic!("Syscall support is missing");
	}

	// enable support of syscall and sysret
	unsafe {
		wrmsr(IA32_EFER, rdmsr(IA32_EFER) | EFER_LMA | EFER_SCE | EFER_NXE);
		wrmsr(IA32_STAR, (0x1Bu64 << 48) | (0x08u64 << 32));
		wrmsr(IA32_LSTAR, syscall_handler as u64);
		wrmsr(IA32_FMASK, 1 << 9); // clear IF flag during system call

		// reset GS registers
		wrmsr(IA32_GS_BASE, 0);
		asm!("wrgsbase {}", in(reg) BOOT_STACK.top());
	}

	// determin processor features
	let extended_function_info = cpuid
		.get_extended_function_info()
		.expect("CPUID Extended Function Info not available!");
	unsafe {
		PHYSICAL_ADDRESS_BITS = extended_function_info
			.physical_address_bits()
			.expect("CPUID Physical Address Bits not available!");
		LINEAR_ADDRESS_BITS = extended_function_info
			.linear_address_bits()
			.expect("CPUID Linear Address Bits not available!");
		SUPPORTS_1GIB_PAGES = extended_function_info.has_1gib_pages();
	}

	if supports_1gib_pages() {
		info!("System supports 1GiB pages");
	}
	debug!("Physical address bits {}", get_physical_address_bits());
	debug!("Linear address bits {}", get_linear_address_bits());
	debug!("CR0: {:?}", cr0);
	debug!("CR4: {:?}", cr4);
}
<|endoftext|>


<commit_before>#![allow(unstable)]
extern crate libc;

use libc::{c_int, c_uint};

#[repr(C)]
#[derive(Copy)]
pub struct RawEvent {
    pub etype: u8,
    pub emod: u8,
    pub key: u16,
    pub ch: u32,
    pub w: i32,
    pub h: i32,
}

extern "C" {
    pub fn tb_init() -> c_int;
    pub fn tb_shutdown();

    pub fn tb_width() -> c_uint;
    pub fn tb_height() -> c_uint;

    pub fn tb_clear();
    pub fn tb_present();

    pub fn tb_set_cursor(cx: c_int, cy: c_int);
    pub fn tb_change_cell(x: c_uint, y: c_uint, ch: u32, fg: u16, bg: u16);

    pub fn tb_select_input_mode(mode: c_int) -> c_int;
    pub fn tb_set_clear_attributes(fg: u16, bg: u16);

    pub fn tb_peek_event(ev: *const ::RawEvent, timeout: c_uint) -> c_int;
    pub fn tb_poll_event(ev: *const ::RawEvent) -> c_int;
}
<commit_msg>Updated to latest rust<commit_after>#![feature(libc)]
extern crate libc;

use libc::{c_int, c_uint};

#[repr(C)]
#[derive(Copy)]
pub struct RawEvent {
    pub etype: u8,
    pub emod: u8,
    pub key: u16,
    pub ch: u32,
    pub w: i32,
    pub h: i32,
}

extern "C" {
    pub fn tb_init() -> c_int;
    pub fn tb_shutdown();

    pub fn tb_width() -> c_uint;
    pub fn tb_height() -> c_uint;

    pub fn tb_clear();
    pub fn tb_present();

    pub fn tb_set_cursor(cx: c_int, cy: c_int);
    pub fn tb_change_cell(x: c_uint, y: c_uint, ch: u32, fg: u16, bg: u16);

    pub fn tb_select_input_mode(mode: c_int) -> c_int;
    pub fn tb_set_clear_attributes(fg: u16, bg: u16);

    pub fn tb_peek_event(ev: *const ::RawEvent, timeout: c_uint) -> c_int;
    pub fn tb_poll_event(ev: *const ::RawEvent) -> c_int;
}
<|endoftext|>