<commit_before>// This is a part of rust-encoding.
// Copyright (c) 2013-2014, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

//! Macros and utilities for testing indices.

#![feature(macro_rules)]

/// Makes a common test suite for single-byte indices.
#[macro_export]
macro_rules! single_byte_tests(
    () => (
        mod tests {
            extern crate test;
            use super::{forward, backward};
            use std::iter::range_inclusive;

            #[test]
            fn test_correct_table() {
                for i in range_inclusive(0x80u8, 0xff) {
                    let j = forward(i);
                    if j != 0xffff { assert_eq!(backward(j as u32), i); }
                }
            }

            #[bench]
            fn bench_forward_sequential_128(bencher: &mut test::Bencher) {
                bencher.iter(|| {
                    for i in range_inclusive(0x80u8, 0xff) {
                        test::black_box(forward(i));
                    }
                })
            }

            #[bench]
            fn bench_backward_sequential_128(bencher: &mut test::Bencher) {
                let mut start: u32 = 0;
                bencher.iter(|| {
                    for i in range(start, start + 0x80) {
                        test::black_box(backward(i));
                    }
                    start += 0x80;
                })
            }
        }
    );
);

/// Makes a common test suite for multi-byte indices.
#[macro_export]
macro_rules! multi_byte_tests(
    (make shared tests and benches with dups = $dups:expr) => ( // internal macro
        #[test]
        fn test_correct_table() {
            use std::iter::range_inclusive;
            static DUPS: &'static [u16] = &$dups;
            for i in range_inclusive(0u16, 0xffff) {
                if DUPS.contains(&i) { continue; }
                let j = forward(i);
                if j != 0xffff { assert_eq!(backward(j), i); }
            }
        }

        #[bench]
        fn bench_forward_sequential_128(bencher: &mut test::Bencher) {
            let mut start: u32 = 0;
            bencher.iter(|| {
                for i in range(start, start + 0x80) {
                    test::black_box(forward(i as u16));
                }
                start += 0x80;
            })
        }

        #[bench]
        fn bench_backward_sequential_128(bencher: &mut test::Bencher) {
            let mut start: u32 = 0;
            bencher.iter(|| {
                for i in range(start, start + 0x80) {
                    test::black_box(backward(i));
                }
                start += 0x80;
                if start >= 0x110000 { start = 0; }
            })
        }
    );

    (
        dups = $dups:expr
    ) => (
        mod tests {
            extern crate test;
            use super::{forward, backward};

            multi_byte_tests!(make shared tests and benches with dups = $dups)
        }
    );

    (
        remap = $remap_min:expr .. $remap_max:expr,
        dups = $dups:expr
    ) => (
        mod tests {
            extern crate test;
            use super::{forward, backward, backward_remapped};

            multi_byte_tests!(make shared tests and benches with dups = $dups)

            static REMAP_MIN: u16 = $remap_min;
            static REMAP_MAX: u16 = $remap_max;

            #[test]
            fn test_correct_remapping() {
                for i in range::<u16>(REMAP_MIN, REMAP_MAX+1) {
                    let j = forward(i);
                    if j != 0xffff {
                        let ii = backward_remapped(j);
                        assert!(ii != i && ii != 0xffff);
                        let jj = forward(ii);
                        assert_eq!(j, jj);
                    }
                }
            }

            #[bench]
            fn bench_backward_remapped_sequential_128(bencher: &mut test::Bencher) {
                let mut start: u32 = 0;
                bencher.iter(|| {
                    for i in range(start, start + 0x80) {
                        test::black_box(backward_remapped(i));
                    }
                    start += 0x80;
                    if start >= 0x110000 { start = 0; }
                })
            }
        }
    );
);

/// Makes a common test suite for multi-byte range indices.
#[macro_export]
macro_rules! multi_byte_range_tests(
    (
        key = $minkey:expr .. $maxkey:expr, key < $keyubound:expr,
        value = $minvalue:expr .. $maxvalue:expr, value < $valueubound:expr
    ) => (
        mod tests {
            extern crate test;
            use super::{forward, backward};

            static MIN_KEY: u32 = $minkey;
            static MAX_KEY: u32 = $maxkey;
            static KEY_UBOUND: u32 = $keyubound;
            static MIN_VALUE: u32 = $minvalue;
            static MAX_VALUE: u32 = $maxvalue;
            static VALUE_UBOUND: u32 = $valueubound;

            #[test]
            #[allow(unused_comparisons)]
            fn test_no_failure() {
                for i in range::<u32>(if MIN_KEY>0 {MIN_KEY-1} else {0}, MAX_KEY+2) {
                    forward(i);
                }
                for j in range::<u32>(if MIN_VALUE>0 {MIN_VALUE-1} else {0}, MAX_VALUE+2) {
                    backward(j);
                }
            }

            #[test]
            fn test_correct_table() {
                for i in range::<u32>(MIN_KEY, MAX_KEY+2) {
                    let j = forward(i);
                    if j == 0xffffffff { continue; }
                    let i_ = backward(j);
                    if i_ == 0xffffffff { continue; }
                    assert!(i_ == i,
                            "backward(forward({})) = backward({}) = {} != {}", i, j, i_, i);
                }
            }

            #[bench]
            fn bench_forward_sequential_128(bencher: &mut test::Bencher) {
                let mut start: u32 = 0;
                bencher.iter(|| {
                    for i in range(start, start + 0x80) {
                        test::black_box(forward(i));
                    }
                    start += 0x80;
                    if start >= KEY_UBOUND { start = 0; }
                })
            }

            #[bench]
            fn bench_backward_sequential_128(bencher: &mut test::Bencher) {
                let mut start: u32 = 0;
                bencher.iter(|| {
                    for i in range(start, start + 0x80) {
                        test::black_box(backward(i));
                    }
                    start += 0x80;
                    if start >= VALUE_UBOUND { start = 0; }
                })
            }
        }
    );
);

<commit_msg>0.2.7: language changes.<commit_after>// This is a part of rust-encoding.
// Copyright (c) 2013-2014, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

//! Macros and utilities for testing indices.

#![feature(macro_rules)]

/// Makes a common test suite for single-byte indices.
#[macro_export]
macro_rules! single_byte_tests(
    () => (
        mod tests {
            extern crate test;
            use super::{forward, backward};
            use std::iter::range_inclusive;

            #[test]
            fn test_correct_table() {
                for i in range_inclusive(0x80u8, 0xff) {
                    let j = forward(i);
                    if j != 0xffff { assert_eq!(backward(j as u32), i); }
                }
            }

            #[bench]
            fn bench_forward_sequential_128(bencher: &mut test::Bencher) {
                bencher.iter(|| {
                    for i in range_inclusive(0x80u8, 0xff) {
                        test::black_box(forward(i));
                    }
                })
            }

            #[bench]
            fn bench_backward_sequential_128(bencher: &mut test::Bencher) {
                let mut start: u32 = 0;
                bencher.iter(|| {
                    for i in range(start, start + 0x80) {
                        test::black_box(backward(i));
                    }
                    start += 0x80;
                })
            }
        }
    );
);

/// Makes a common test suite for multi-byte indices.
#[macro_export]
macro_rules! multi_byte_tests(
    (make shared tests and benches with dups = $dups:expr) => ( // internal macro
        #[test]
        fn test_correct_table() {
            use std::iter::range_inclusive;
            static DUPS: &'static [u16] = &$dups;
            for i in range_inclusive(0u16, 0xffff) {
                if DUPS.contains(&i) { continue; }
                let j = forward(i);
                if j != 0xffff { assert_eq!(backward(j), i); }
            }
        }

        #[bench]
        fn bench_forward_sequential_128(bencher: &mut test::Bencher) {
            let mut start: u32 = 0;
            bencher.iter(|| {
                for i in range(start, start + 0x80) {
                    test::black_box(forward(i as u16));
                }
                start += 0x80;
            })
        }

        #[bench]
        fn bench_backward_sequential_128(bencher: &mut test::Bencher) {
            let mut start: u32 = 0;
            bencher.iter(|| {
                for i in range(start, start + 0x80) {
                    test::black_box(backward(i));
                }
                start += 0x80;
                if start >= 0x110000 { start = 0; }
            })
        }
    );

    (
        dups = $dups:expr
    ) => (
        mod tests {
            extern crate test;
            use super::{forward, backward};

            multi_byte_tests!(make shared tests and benches with dups = $dups);
        }
    );

    (
        remap = $remap_min:expr .. $remap_max:expr,
        dups = $dups:expr
    ) => (
        mod tests {
            extern crate test;
            use super::{forward, backward, backward_remapped};

            multi_byte_tests!(make shared tests and benches with dups = $dups);

            static REMAP_MIN: u16 = $remap_min;
            static REMAP_MAX: u16 = $remap_max;

            #[test]
            fn test_correct_remapping() {
                for i in range::<u16>(REMAP_MIN, REMAP_MAX+1) {
                    let j = forward(i);
                    if j != 0xffff {
                        let ii = backward_remapped(j);
                        assert!(ii != i && ii != 0xffff);
                        let jj = forward(ii);
                        assert_eq!(j, jj);
                    }
                }
            }

            #[bench]
            fn bench_backward_remapped_sequential_128(bencher: &mut test::Bencher) {
                let mut start: u32 = 0;
                bencher.iter(|| {
                    for i in range(start, start + 0x80) {
                        test::black_box(backward_remapped(i));
                    }
                    start += 0x80;
                    if start >= 0x110000 { start = 0; }
                })
            }
        }
    );
);

/// Makes a common test suite for multi-byte range indices.
#[macro_export]
macro_rules! multi_byte_range_tests(
    (
        key = $minkey:expr .. $maxkey:expr, key < $keyubound:expr,
        value = $minvalue:expr .. $maxvalue:expr, value < $valueubound:expr
    ) => (
        mod tests {
            extern crate test;
            use super::{forward, backward};

            static MIN_KEY: u32 = $minkey;
            static MAX_KEY: u32 = $maxkey;
            static KEY_UBOUND: u32 = $keyubound;
            static MIN_VALUE: u32 = $minvalue;
            static MAX_VALUE: u32 = $maxvalue;
            static VALUE_UBOUND: u32 = $valueubound;

            #[test]
            #[allow(unused_comparisons)]
            fn test_no_failure() {
                for i in range::<u32>(if MIN_KEY>0 {MIN_KEY-1} else {0}, MAX_KEY+2) {
                    forward(i);
                }
                for j in range::<u32>(if MIN_VALUE>0 {MIN_VALUE-1} else {0}, MAX_VALUE+2) {
                    backward(j);
                }
            }

            #[test]
            fn test_correct_table() {
                for i in range::<u32>(MIN_KEY, MAX_KEY+2) {
                    let j = forward(i);
                    if j == 0xffffffff { continue; }
                    let i_ = backward(j);
                    if i_ == 0xffffffff { continue; }
                    assert!(i_ == i,
                            "backward(forward({})) = backward({}) = {} != {}", i, j, i_, i);
                }
            }

            #[bench]
            fn bench_forward_sequential_128(bencher: &mut test::Bencher) {
                let mut start: u32 = 0;
                bencher.iter(|| {
                    for i in range(start, start + 0x80) {
                        test::black_box(forward(i));
                    }
                    start += 0x80;
                    if start >= KEY_UBOUND { start = 0; }
                })
            }

            #[bench]
            fn bench_backward_sequential_128(bencher: &mut test::Bencher) {
                let mut start: u32 = 0;
                bencher.iter(|| {
                    for i in range(start, start + 0x80) {
                        test::black_box(backward(i));
                    }
                    start += 0x80;
                    if start >= VALUE_UBOUND { start = 0; }
                })
            }
        }
    );
);

<|endoftext|>


<commit_before>use num::Zero;
use std::fmt;
use std::fmt::Debug;
use std::hash;
use std::hash::Hash;
use std::ops::{Add, Sub};

extern crate num;
use num::{CheckedAdd, CheckedSub, FromPrimitive, ToPrimitive};

/// Type infrastructure that describes an architecture,
///  with details such as pointer size.
///
/// Useful for specifying the appropriate member types for pointers, etc.
/// That is, when a struct contains an RVA, its 32-bits or 64-bits depending on Arch.
///
/// Example:
///
/// ```
/// use lancelot::arch::{Arch, Arch32};
///
/// struct Section<A: Arch> {
///   addr: A::RVA,
///   buf:  Vec<u8>,
///   name: String,
/// }
///
/// let s: Section<Arch32> = Section {
///   addr: 0x0,
///   buf: vec![],
///   name: "foo".to_string(),
/// };
/// ```
///
/// see: https://stackoverflow.com/q/55785858/87207
pub trait Arch {
    /// The type used for Virtual Addresses (which are unsigned).
    type VA: Ord + Add<Output = Self::VA> + Zero + FromPrimitive + ToPrimitive + Copy + Debug;

    /// The type used for Relative Virtual Addresses (signed).
    type RVA: Ord
        + Zero
        + Hash
        + fmt::LowerHex
        + Add<Output = Self::RVA>
        + Sub<Output = Self::RVA>
        + Add<Self::RVA, Output = Self::RVA>
        + CheckedAdd<Output = Self::RVA>
        + CheckedSub<Output = Self::RVA>
        + FromPrimitive
        + ToPrimitive
        + Copy
        + Debug;

    fn get_bits() -> u8;
}

/// 32-bit Intel architecture.
pub struct Arch32;
impl Arch for Arch32 {
    type VA = u32;
    type RVA = i32;
    fn get_bits() -> u8 {
        32
    }
}

impl fmt::Display for Arch32 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "x32")
    }
}

impl fmt::Debug for Arch32 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "x32")
    }
}

impl hash::Hash for Arch32 {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        "x32".hash(state);
    }
}

impl PartialEq for Arch32 {
    fn eq(&self, _other: &Arch32) -> bool {
        true
    }
}

impl Eq for Arch32 {}

/// 64-bit Intel architecture.
pub struct Arch64;
impl Arch for Arch64 {
    type VA = u64;
    type RVA = i64;
    fn get_bits() -> u8 {
        64
    }
}

impl fmt::Display for Arch64 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "x64")
    }
}

impl fmt::Debug for Arch64 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "x64")
    }
}

impl hash::Hash for Arch64 {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        "x64".hash(state);
    }
}

impl PartialEq for Arch64 {
    fn eq(&self, _: &Arch64) -> bool {
        true
    }
}

impl Eq for Arch64 {}

/// Checked arithmetic across RVA and usize.
///
/// We'd like RVA to be trait `Add<usize, Output=RVA>`.
/// However, this cannot be the case when `<RVA=u32>`
///  as we then have `i32 + u32` which can overflow `i32`.
/// So, we have to do checked arithmetic.
///
/// Example:
///
/// ```
/// use lancelot::arch::*;
///
/// // returns Some if the operation does not wrap:
/// assert_eq!(true, rva_add_usize::<Arch32>(0x0, 0x1).is_some());
/// assert_eq!(0x1,  rva_add_usize::<Arch32>(0x0, 0x1).unwrap());
///
/// // returns None if the operation wraps.
/// assert_eq!(true, rva_add_usize::<Arch32>(0x0, 0xFFFFFFFF).is_none());
/// ```
pub fn rva_add_usize<A: Arch>(base: A::RVA, offset: usize) -> Option<A::RVA> {
    if let Some(v) = A::RVA::from_usize(offset) {
        base.checked_add(&v)
    } else {
        None
    }
}

/// Checked arithmetic across RVA and usize.
///
/// We'd like RVA to be trait `Sub<usize, Output=RVA>`.
/// However, this cannot be the case when `<RVA=u32>`
///  as we then have `i32 - u32` which can underflow `i32`.
/// So, we have to do checked arithmetic.
///
/// Example:
///
/// ```
/// use std::i32;
/// use lancelot::arch::*;
///
/// // returns Some if the operation does not wrap:
/// assert_eq!(true, rva_sub_usize::<Arch32>(0x1, 0x0).is_some());
/// assert_eq!(0x1,  rva_sub_usize::<Arch32>(0x1, 0x0).unwrap());
///
/// // returns None if the operation wraps.
/// assert_eq!(true, rva_sub_usize::<Arch32>(std::i32::MAX, 0xFFFFFFFF).is_none());
/// ```
pub fn rva_sub_usize<A: Arch>(base: A::RVA, offset: usize) -> Option<A::RVA> {
    if let Some(v) = A::RVA::from_usize(offset) {
        base.checked_sub(&v)
    } else {
        None
    }
}

pub fn va_compute_rva<A: Arch>(base: A::VA, va: A::VA) -> Option<A::RVA> {
    if va < base {
        None
    } else {
        let base = A::VA::to_u64(&base).unwrap();
        let va = A::VA::to_u64(&va).unwrap();
        let rva = va - base;
        A::RVA::from_u64(rva)
    }
}
<commit_msg>arch: add get_ptr_size() helper<commit_after>use num::Zero;
use std::fmt;
use std::fmt::Debug;
use std::hash;
use std::hash::Hash;
use std::ops::{Add, Sub};

extern crate num;
use num::{CheckedAdd, CheckedSub, FromPrimitive, ToPrimitive};

/// Type infrastructure that describes an architecture,
///  with details such as pointer size.
///
/// Useful for specifying the appropriate member types for pointers, etc.
/// That is, when a struct contains an RVA, its 32-bits or 64-bits depending on Arch.
///
/// Example:
///
/// ```
/// use lancelot::arch::{Arch, Arch32};
///
/// struct Section<A: Arch> {
///   addr: A::RVA,
///   buf:  Vec<u8>,
///   name: String,
/// }
///
/// let s: Section<Arch32> = Section {
///   addr: 0x0,
///   buf: vec![],
///   name: "foo".to_string(),
/// };
/// ```
///
/// see: https://stackoverflow.com/q/55785858/87207
pub trait Arch {
    /// The type used for Virtual Addresses (which are unsigned).
    type VA: Ord + Add<Output = Self::VA> + Zero + FromPrimitive + ToPrimitive + Copy + Debug;

    /// The type used for Relative Virtual Addresses (signed).
    type RVA: Ord
        + Zero
        + Hash
        + fmt::LowerHex
        + Add<Output = Self::RVA>
        + Sub<Output = Self::RVA>
        + Add<Self::RVA, Output = Self::RVA>
        + CheckedAdd<Output = Self::RVA>
        + CheckedSub<Output = Self::RVA>
        + FromPrimitive
        + ToPrimitive
        + Copy
        + Debug;

    fn get_bits() -> u8;
    fn get_ptr_size() -> u8;
}

/// 32-bit Intel architecture.
pub struct Arch32;
impl Arch for Arch32 {
    type VA = u32;
    type RVA = i32;
    fn get_bits() -> u8 {
        32
    }
    fn get_ptr_size() -> u8 {
        4
    }
}

impl fmt::Display for Arch32 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "x32")
    }
}

impl fmt::Debug for Arch32 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "x32")
    }
}

impl hash::Hash for Arch32 {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        "x32".hash(state);
    }
}

impl PartialEq for Arch32 {
    fn eq(&self, _other: &Arch32) -> bool {
        true
    }
}

impl Eq for Arch32 {}

/// 64-bit Intel architecture.
pub struct Arch64;
impl Arch for Arch64 {
    type VA = u64;
    type RVA = i64;
    fn get_bits() -> u8 {
        64
    }
    fn get_ptr_size() -> u8 {
        8
    }
}

impl fmt::Display for Arch64 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "x64")
    }
}

impl fmt::Debug for Arch64 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "x64")
    }
}

impl hash::Hash for Arch64 {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        "x64".hash(state);
    }
}

impl PartialEq for Arch64 {
    fn eq(&self, _: &Arch64) -> bool {
        true
    }
}

impl Eq for Arch64 {}

/// Checked arithmetic across RVA and usize.
///
/// We'd like RVA to be trait `Add<usize, Output=RVA>`.
/// However, this cannot be the case when `<RVA=u32>`
///  as we then have `i32 + u32` which can overflow `i32`.
/// So, we have to do checked arithmetic.
///
/// Example:
///
/// ```
/// use lancelot::arch::*;
///
/// // returns Some if the operation does not wrap:
/// assert_eq!(true, rva_add_usize::<Arch32>(0x0, 0x1).is_some());
/// assert_eq!(0x1,  rva_add_usize::<Arch32>(0x0, 0x1).unwrap());
///
/// // returns None if the operation wraps.
/// assert_eq!(true, rva_add_usize::<Arch32>(0x0, 0xFFFFFFFF).is_none());
/// ```
pub fn rva_add_usize<A: Arch>(base: A::RVA, offset: usize) -> Option<A::RVA> {
    if let Some(v) = A::RVA::from_usize(offset) {
        base.checked_add(&v)
    } else {
        None
    }
}

/// Checked arithmetic across RVA and usize.
///
/// We'd like RVA to be trait `Sub<usize, Output=RVA>`.
/// However, this cannot be the case when `<RVA=u32>`
///  as we then have `i32 - u32` which can underflow `i32`.
/// So, we have to do checked arithmetic.
///
/// Example:
///
/// ```
/// use std::i32;
/// use lancelot::arch::*;
///
/// // returns Some if the operation does not wrap:
/// assert_eq!(true, rva_sub_usize::<Arch32>(0x1, 0x0).is_some());
/// assert_eq!(0x1,  rva_sub_usize::<Arch32>(0x1, 0x0).unwrap());
///
/// // returns None if the operation wraps.
/// assert_eq!(true, rva_sub_usize::<Arch32>(std::i32::MAX, 0xFFFFFFFF).is_none());
/// ```
pub fn rva_sub_usize<A: Arch>(base: A::RVA, offset: usize) -> Option<A::RVA> {
    if let Some(v) = A::RVA::from_usize(offset) {
        base.checked_sub(&v)
    } else {
        None
    }
}

pub fn va_compute_rva<A: Arch>(base: A::VA, va: A::VA) -> Option<A::RVA> {
    if va < base {
        None
    } else {
        let base = A::VA::to_u64(&base).unwrap();
        let va = A::VA::to_u64(&va).unwrap();
        let rva = va - base;
        A::RVA::from_u64(rva)
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern mod freetype;
extern mod fontconfig;

use fontconfig::fontconfig::{
    FcChar8, FcResultMatch, FcSetSystem,
    FcResultNoMatch, FcMatchPattern, FC_SLANT_ITALIC, FC_WEIGHT_BOLD
};
use fontconfig::fontconfig::bindgen::{
    FcConfigGetCurrent, FcConfigGetFonts, FcPatternGetString,
    FcPatternDestroy, FcFontSetDestroy, FcConfigSubstitute,
    FcDefaultSubstitute, FcPatternCreate, FcPatternAddString, FcPatternAddInteger,
    FcFontMatch, FcFontSetList, FcObjectSetCreate, FcObjectSetDestroy,
    FcObjectSetAdd, FcPatternGetInteger
};

use font::{FontHandleMethods, UsedFontStyle};
use font_context::FontContextHandleMethods;
use font_list::{FontEntry, FontFamily, FontFamilyMap};
use platform::font::FontHandle;
use platform::font_context::FontContextHandle;

use core::hashmap::HashMap;
use core::libc::c_int;
use core::ptr::Ptr;

pub struct FontListHandle {
    fctx: FontContextHandle,
}

pub impl FontListHandle {
    pub fn new(fctx: &FontContextHandle) -> FontListHandle {
        FontListHandle { fctx: fctx.clone() }
    }

    fn get_available_families(&self) -> FontFamilyMap {
        let mut family_map : FontFamilyMap = HashMap::new();
        unsafe {
            let config = FcConfigGetCurrent();
            let fontSet = FcConfigGetFonts(config, FcSetSystem);
            for uint::range(0, (*fontSet).nfont as uint) |i| {
                let font = (*fontSet).fonts.offset(i);
                let family: *FcChar8 = ptr::null();
                let mut v: c_int = 0;
                do str::as_c_str("family") |FC_FAMILY| {
                    while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
                        let family_name = str::raw::from_buf(family as *u8);
                        debug!("Creating new FontFamily for family: %s", family_name);
                        let new_family = @mut FontFamily::new(family_name);
                        family_map.insert(family_name, new_family);
                        v += 1;
                    }
                }
            }
        }
        return family_map;
    }

    fn load_variations_for_family(&self, family: @mut FontFamily) {
        debug!("getting variations for %?", family);
        let config = FcConfigGetCurrent();
        let font_set = FcConfigGetFonts(config, FcSetSystem);
        let font_set_array_ptr = ptr::to_unsafe_ptr(&font_set);
        unsafe {
            do str::as_c_str("family") |FC_FAMILY| {
                do str::as_c_str(family.family_name) |family_name| {
                    let pattern = FcPatternCreate();
                    assert!(pattern.is_not_null());
                    let family_name = family_name as *FcChar8;
                    let ok = FcPatternAddString(pattern, FC_FAMILY, family_name);
                    assert!(ok != 0);

                    let object_set = FcObjectSetCreate();
                    assert!(object_set.is_not_null());

                    str::as_c_str("file", |FC_FILE| FcObjectSetAdd(object_set, FC_FILE) );
                    str::as_c_str("index", |FC_INDEX| FcObjectSetAdd(object_set, FC_INDEX) );

                    let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);

                    debug!("found %? variations", (*matches).nfont);

                    for uint::range(0, (*matches).nfont as uint) |i| {
                        let font = (*matches).fonts.offset(i);
                        let file = do str::as_c_str("file") |FC_FILE| {
                            let file: *FcChar8 = ptr::null();
                            if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
                                str::raw::from_c_str(file as *libc::c_char)
                            } else {
                                fail!();
                            }
                        };
                        let index = do str::as_c_str("index") |FC_INDEX| {
                            let index: libc::c_int = 0;
                            if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
                                index
                            } else {
                                fail!();
                            }
                        };

                        debug!("variation file: %?", file);
                        debug!("variation index: %?", index);

                        let font_handle = FontHandle::new_from_file_unstyled(&self.fctx,
                                                                             file);
                        let font_handle = font_handle.unwrap();

                        debug!("Creating new FontEntry for face: %s", font_handle.face_name());
                        let entry = @FontEntry::new(family, font_handle);
                        family.entries.push(entry);
                    }

                    FcFontSetDestroy(matches);
                    FcPatternDestroy(pattern);
                    FcObjectSetDestroy(object_set);
                }
            }
        }
    }
}

pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, ()> {
    unsafe {
        let config = FcConfigGetCurrent();
        let pattern = FcPatternCreate();
        let res = do str::as_c_str("family") |FC_FAMILY| {
            do str::as_c_str(name) |family| {
                FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
            }
        };
        if res != 1 {
            debug!("adding family to pattern failed");
            return Err(());
        }

        if style.italic {
            let res = do str::as_c_str("slant") |FC_SLANT| {
                FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC)
            };
            if res != 1 {
                debug!("adding slant to pattern failed");
                return Err(());
            }
        }
        if style.weight.is_bold() {
            let res = do str::as_c_str("weight") |FC_WEIGHT| {
                FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD)
            };
            if res != 1 {
                debug!("adding weight to pattern failed");
                return Err(());
            }
        }

        if FcConfigSubstitute(config, pattern, FcMatchPattern) != 1 {
            debug!("substitution failed");
            return Err(());
        }
        FcDefaultSubstitute(pattern);
        let result = FcResultNoMatch;
        let result_pattern = FcFontMatch(config, pattern, &result);
        if result != FcResultMatch && result_pattern.is_null() {
            debug!("obtaining match to pattern failed");
            return Err(());
        }

        let file: *FcChar8 = ptr::null();
        let res = do str::as_c_str("file") |FC_FILE| {
            FcPatternGetString(result_pattern, FC_FILE, 0, &file)
        };
        if res != FcResultMatch {
            debug!("getting filename for font failed");
            return Err(());
        }
        Ok(str::raw::from_buf(file as *u8))
    }
}
<commit_msg>Fix dynamic borrow check errors.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern mod freetype;
extern mod fontconfig;

use fontconfig::fontconfig::{
    FcChar8, FcResultMatch, FcSetSystem,
    FcResultNoMatch, FcMatchPattern, FC_SLANT_ITALIC, FC_WEIGHT_BOLD
};
use fontconfig::fontconfig::bindgen::{
    FcConfigGetCurrent, FcConfigGetFonts, FcPatternGetString,
    FcPatternDestroy, FcFontSetDestroy, FcConfigSubstitute,
    FcDefaultSubstitute, FcPatternCreate, FcPatternAddString, FcPatternAddInteger,
    FcFontMatch, FcFontSetList, FcObjectSetCreate, FcObjectSetDestroy,
    FcObjectSetAdd, FcPatternGetInteger
};

use font::{FontHandleMethods, UsedFontStyle};
use font_context::FontContextHandleMethods;
use font_list::{FontEntry, FontFamily, FontFamilyMap};
use platform::font::FontHandle;
use platform::font_context::FontContextHandle;

use core::hashmap::HashMap;
use core::libc::c_int;
use core::ptr::Ptr;

pub struct FontListHandle {
    fctx: FontContextHandle,
}

pub impl FontListHandle {
    pub fn new(fctx: &FontContextHandle) -> FontListHandle {
        FontListHandle { fctx: fctx.clone() }
    }

    fn get_available_families(&self) -> FontFamilyMap {
        let mut family_map : FontFamilyMap = HashMap::new();
        unsafe {
            let config = FcConfigGetCurrent();
            let fontSet = FcConfigGetFonts(config, FcSetSystem);
            for uint::range(0, (*fontSet).nfont as uint) |i| {
                let font = (*fontSet).fonts.offset(i);
                let family: *FcChar8 = ptr::null();
                let mut v: c_int = 0;
                do str::as_c_str("family") |FC_FAMILY| {
                    while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
                        let family_name = str::raw::from_buf(family as *u8);
                        debug!("Creating new FontFamily for family: %s", family_name);
                        let new_family = @mut FontFamily::new(family_name);
                        family_map.insert(family_name, new_family);
                        v += 1;
                    }
                }
            }
        }
        return family_map;
    }

    fn load_variations_for_family(&self, family: @mut FontFamily) {
        debug!("getting variations for %?", family);
        let config = FcConfigGetCurrent();
        let font_set = FcConfigGetFonts(config, FcSetSystem);
        let font_set_array_ptr = ptr::to_unsafe_ptr(&font_set);
        unsafe {
            let pattern = FcPatternCreate();
            let pattern = FcPatternCreate();
            assert!(pattern.is_not_null());
            do str::as_c_str("family") |FC_FAMILY| {
                do str::as_c_str(family.family_name) |family_name| {
                    let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
                    assert!(ok != 0);
                }
            }

            let object_set = FcObjectSetCreate();
            assert!(object_set.is_not_null());

            do str::as_c_str("file") |FC_FILE| {
                FcObjectSetAdd(object_set, FC_FILE);
            }
            do str::as_c_str("index") |FC_INDEX| {
                FcObjectSetAdd(object_set, FC_INDEX);
            }

            let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);

            debug!("found %? variations", (*matches).nfont);

            for uint::range(0, (*matches).nfont as uint) |i| {
                let font = (*matches).fonts.offset(i);
                let file = do str::as_c_str("file") |FC_FILE| {
                    let file: *FcChar8 = ptr::null();
                    if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
                        str::raw::from_c_str(file as *libc::c_char)
                    } else {
                        fail!();
                    }
                };
                let index = do str::as_c_str("index") |FC_INDEX| {
                    let index: libc::c_int = 0;
                    if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
                        index
                    } else {
                        fail!();
                    }
                };

                debug!("variation file: %?", file);
                debug!("variation index: %?", index);

                let font_handle = FontHandle::new_from_file_unstyled(&self.fctx,
                                                                     file);
                let font_handle = font_handle.unwrap();

                debug!("Creating new FontEntry for face: %s", font_handle.face_name());
                let entry = @FontEntry::new(family, font_handle);
                family.entries.push(entry);
            }

            FcFontSetDestroy(matches);
            FcPatternDestroy(pattern);
            FcObjectSetDestroy(object_set);
        }
    }
}

pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, ()> {
    unsafe {
        let config = FcConfigGetCurrent();
        let pattern = FcPatternCreate();
        let res = do str::as_c_str("family") |FC_FAMILY| {
            do str::as_c_str(name) |family| {
                FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
            }
        };
        if res != 1 {
            debug!("adding family to pattern failed");
            return Err(());
        }

        if style.italic {
            let res = do str::as_c_str("slant") |FC_SLANT| {
                FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC)
            };
            if res != 1 {
                debug!("adding slant to pattern failed");
                return Err(());
            }
        }
        if style.weight.is_bold() {
            let res = do str::as_c_str("weight") |FC_WEIGHT| {
                FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD)
            };
            if res != 1 {
                debug!("adding weight to pattern failed");
                return Err(());
            }
        }

        if FcConfigSubstitute(config, pattern, FcMatchPattern) != 1 {
            debug!("substitution failed");
            return Err(());
        }
        FcDefaultSubstitute(pattern);
        let result = FcResultNoMatch;
        let result_pattern = FcFontMatch(config, pattern, &result);
        if result != FcResultMatch && result_pattern.is_null() {
            debug!("obtaining match to pattern failed");
            return Err(());
        }

        let file: *FcChar8 = ptr::null();
        let res = do str::as_c_str("file") |FC_FILE| {
            FcPatternGetString(result_pattern, FC_FILE, 0, &file)
        };
        if res != FcResultMatch {
            debug!("getting filename for font failed");
            return Err(());
        }
        Ok(str::raw::from_buf(file as *u8))
    }
}
<|endoftext|>


<commit_before>//! EGL-based surface and swapchain.

use crate::{conv, native, GlContainer, PhysicalDevice};
use glow::HasContext;
use hal::{image, window as w};

#[derive(Debug)]
pub struct Swapchain {
    framebuffer: glow::Framebuffer,
    renderbuffer: glow::Renderbuffer,
    /// Extent because the window lies
    extent: w::Extent2D,
    format: native::TextureFormat,
    channel: hal::format::ChannelType,
}

#[derive(Debug)]
pub struct Instance {
    display: egl::Display,
    version: (i32, i32),
    config: egl::Config,
    context: egl::Context,
    supports_native_window: bool,
}

unsafe impl Send for Instance {}
unsafe impl Sync for Instance {}

impl hal::Instance<crate::Backend> for Instance {
    fn create(_: &str, _: u32) -> Result<Self, hal::UnsupportedBackend> {
        let client_extensions =
            egl::query_string(None, egl::EXTENSIONS).map_err(|_| hal::UnsupportedBackend)?;
        log::info!("Client extensions: {:?}", client_extensions);

        //TODO: requre  `GL_OES_surfaceless_context` or work around it

        #[cfg(feature = "x11")]
        let display = {
            const EGL_PLATFORM_X11_KHR: u32 = 0x31D5;
            let x11_display = unsafe { x11::xlib::XOpenDisplay(std::ptr::null()) };
            assert!(!x11_display.is_null());
            let display_attributes = [egl::ATTRIB_NONE];
            egl::get_platform_display(
                EGL_PLATFORM_X11_KHR,
                x11_display as *mut _,
                &display_attributes,
            )
            .unwrap()
        };
        #[cfg(not(feature = "x11"))]
        let display = egl::get_display(egl::DEFAULT_DISPLAY).unwrap();

        let version = egl::initialize(display).map_err(|_| hal::UnsupportedBackend)?;
        let vendor = egl::query_string(Some(display), egl::VENDOR).unwrap();
        let display_extensions = egl::query_string(Some(display), egl::EXTENSIONS).unwrap();
        log::info!(
            "Display vendor {:?}, version {:?}, extensions: {:?}",
            vendor,
            version,
            display_extensions
        );
        assert!(version >= (1, 4), "Unable to request GL context");

        {
            debug!("Configurations:");
            let config_count = egl::get_config_count(display).unwrap();
            let mut configurations = Vec::with_capacity(config_count);
            egl::get_configs(display, &mut configurations).unwrap();
            for &config in configurations.iter() {
                debug!("\tCONFORMANT=0x{:X}, RENDERABLE=0x{:X}, NATIVE_RENDERABLE=0x{:X}, SURFACE_TYPE=0x{:X}",
                    egl::get_config_attrib(display, config, egl::CONFORMANT).unwrap(),
                    egl::get_config_attrib(display, config, egl::RENDERABLE_TYPE).unwrap(),
                    egl::get_config_attrib(display, config, egl::NATIVE_RENDERABLE).unwrap(),
                    egl::get_config_attrib(display, config, egl::SURFACE_TYPE).unwrap(),
                );
            }
        }

        //Note: only GLES is supported here.
        let mut supports_native_window = true;
        //TODO: EGL_SLOW_CONFIG
        let config_attributes = [
            egl::CONFORMANT,
            egl::OPENGL_ES2_BIT,
            egl::RENDERABLE_TYPE,
            egl::OPENGL_ES2_BIT,
            egl::NATIVE_RENDERABLE,
            egl::TRUE as _,
            egl::SURFACE_TYPE,
            egl::WINDOW_BIT,
            egl::NONE,
        ];
        let config = match egl::choose_first_config(display, &config_attributes) {
            Ok(Some(config)) => config,
            Ok(None) => {
                log::warn!("no compatible EGL config found, trying off-screen");
                supports_native_window = false;
                let reduced_config_attributes =
                    [egl::RENDERABLE_TYPE, egl::OPENGL_ES2_BIT, egl::NONE];
                match egl::choose_first_config(display, &reduced_config_attributes) {
                    Ok(Some(config)) => config,
                    _ => return Err(hal::UnsupportedBackend),
                }
            }
            Err(e) => {
                log::error!("error in choose_first_config: {:?}", e);
                return Err(hal::UnsupportedBackend);
            }
        };

        egl::bind_api(egl::OPENGL_ES_API).unwrap();

        //TODO: make it so `Device` == EGL Context
        let gles_version = (3, 1);
        let mut context_attributes = vec![
            egl::CONTEXT_MAJOR_VERSION,
            gles_version.0,
            egl::CONTEXT_MINOR_VERSION,
            gles_version.1,
        ];
        if cfg!(debug_assertions) {
            context_attributes.push(egl::CONTEXT_OPENGL_DEBUG);
            context_attributes.push(egl::TRUE as _);
        }
        context_attributes.push(egl::NONE as _);
        let context = match egl::create_context(display, config, None, &context_attributes) {
            Ok(context) => context,
            Err(e) => {
                log::warn!("unable to create GLES {:?} context: {:?}", gles_version, e);
                return Err(hal::UnsupportedBackend);
            }
        };

        Ok(Instance {
            display,
            version,
            config,
            context,
            supports_native_window,
        })
    }

    fn enumerate_adapters(&self) -> Vec<hal::adapter::Adapter<crate::Backend>> {
        egl::make_current(self.display, None, None, Some(self.context)).unwrap();
        let gl = unsafe {
            GlContainer::from_fn_proc(|name| egl::get_proc_address(name).unwrap() as *const _)
        };

        // Create physical device
        vec![PhysicalDevice::new_adapter(gl)]
    }

    unsafe fn create_surface(
        &self,
        has_handle: &impl raw_window_handle::HasRawWindowHandle,
    ) -> Result<Surface, w::InitError> {
        use raw_window_handle::RawWindowHandle as Rwh;
        let mut native_window = match has_handle.raw_window_handle() {
            #[cfg(not(target_os = "android"))]
            Rwh::Xlib(handle) => handle.window,
            #[cfg(not(target_os = "android"))]
            Rwh::Xcb(handle) => handle.window as _,
            #[cfg(target_os = "android")]
            Rwh::Android(handle) => handle.a_native_window,
            other => panic!("Unsupported window: {:?}", other),
        };
        let attributes = [
            egl::RENDER_BUFFER as usize,
            egl::SINGLE_BUFFER as usize,
            // Always enable sRGB
            egl::GL_COLORSPACE as usize,
            egl::GL_COLORSPACE_SRGB as usize,
            egl::ATTRIB_NONE,
        ];
        match egl::create_platform_window_surface(
            self.display,
            self.config,
            &mut native_window as *mut _ as *mut _,
            &attributes,
        ) {
            Ok(raw) => Ok(Surface {
                raw,
                display: self.display,
                context: self.context,
                presentable: self.supports_native_window,
                swapchain: None,
            }),
            Err(e) => {
                log::warn!("Error in create_window_surface: {:?}", e);
                Err(w::InitError::UnsupportedWindowHandle)
            }
        }
    }

    unsafe fn destroy_surface(&self, surface: Surface) {
        egl::destroy_surface(self.display, surface.raw).unwrap();
    }
}

impl Drop for Instance {
    fn drop(&mut self) {
        if let Err(e) = egl::destroy_context(self.display, self.context) {
            log::warn!("Error in destroy_context: {:?}", e);
        }
        if let Err(e) = egl::terminate(self.display) {
            log::warn!("Error in terminate: {:?}", e);
        }
    }
}

#[derive(Debug)]
pub struct Surface {
    raw: egl::Surface,
    display: egl::Display,
    context: egl::Context,
    presentable: bool,
    pub(crate) swapchain: Option<Swapchain>,
}

unsafe impl Send for Surface {}
unsafe impl Sync for Surface {}

impl w::PresentationSurface<crate::Backend> for Surface {
    type SwapchainImage = native::SwapchainImage;

    unsafe fn configure_swapchain(
        &mut self,
        device: &crate::Device,
        config: w::SwapchainConfig,
    ) -> Result<(), w::SwapchainError> {
        self.unconfigure_swapchain(device);

        let desc = conv::describe_format(config.format).unwrap();

        let gl = &device.share.context;
        let renderbuffer = gl.create_renderbuffer().unwrap();
        gl.bind_renderbuffer(glow::RENDERBUFFER, Some(renderbuffer));
        gl.renderbuffer_storage(
            glow::RENDERBUFFER,
            desc.tex_internal,
            config.extent.width as _,
            config.extent.height as _,
        );
        let framebuffer = gl.create_framebuffer().unwrap();
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(framebuffer));
        gl.framebuffer_renderbuffer(
            glow::READ_FRAMEBUFFER,
            glow::COLOR_ATTACHMENT0,
            glow::RENDERBUFFER,
            Some(renderbuffer),
        );
        gl.bind_renderbuffer(glow::RENDERBUFFER, None);
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);

        self.swapchain = Some(Swapchain {
            renderbuffer,
            framebuffer,
            extent: config.extent,
            format: desc.tex_internal,
            channel: config.format.base_format().1,
        });

        Ok(())
    }

    unsafe fn unconfigure_swapchain(&mut self, device: &crate::Device) {
        let gl = &device.share.context;
        if let Some(sc) = self.swapchain.take() {
            gl.delete_renderbuffer(sc.renderbuffer);
            gl.delete_framebuffer(sc.framebuffer);
        }
    }

    unsafe fn acquire_image(
        &mut self,
        _timeout_ns: u64,
    ) -> Result<(Self::SwapchainImage, Option<w::Suboptimal>), w::AcquireError> {
        let sc = self.swapchain.as_ref().unwrap();
        let sc_image =
            native::SwapchainImage::new(sc.renderbuffer, sc.format, sc.extent, sc.channel);
        Ok((sc_image, None))
    }
}

impl w::Surface<crate::Backend> for Surface {
    fn supports_queue_family(&self, _: &crate::QueueFamily) -> bool {
        self.presentable
    }

    fn capabilities(&self, _physical_device: &PhysicalDevice) -> w::SurfaceCapabilities {
        w::SurfaceCapabilities {
            present_modes: w::PresentMode::FIFO,                  //TODO
            composite_alpha_modes: w::CompositeAlphaMode::OPAQUE, //TODO
            image_count: 2..=2,
            current_extent: None,
            extents: w::Extent2D {
                width: 4,
                height: 4,
            }..=w::Extent2D {
                width: 4096,
                height: 4096,
            },
            max_image_layers: 1,
            usage: image::Usage::COLOR_ATTACHMENT,
        }
    }

    fn supported_formats(
        &self,
        _physical_device: &PhysicalDevice,
    ) -> Option<Vec<hal::format::Format>> {
        use hal::format::Format;
        Some(vec![Format::Rgba8Srgb, Format::Bgra8Srgb])
    }
}

impl Surface {
    pub(crate) unsafe fn present(
        &mut self,
        _image: native::SwapchainImage,
        gl: &GlContainer,
    ) -> Result<Option<w::Suboptimal>, w::PresentError> {
        let sc = self.swapchain.as_ref().unwrap();

        egl::make_current(
            self.display,
            Some(self.raw),
            Some(self.raw),
            Some(self.context),
        )
        .unwrap();
        gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None);
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuffer));
        gl.blit_framebuffer(
            0,
            0,
            sc.extent.width as _,
            sc.extent.height as _,
            0,
            0,
            sc.extent.width as _,
            sc.extent.height as _,
            glow::COLOR_BUFFER_BIT,
            glow::NEAREST,
        );
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);

        egl::swap_buffers(self.display, self.raw).unwrap();
        egl::make_current(self.display, None, None, Some(self.context)).unwrap();

        Ok(None)
    }
}
<commit_msg>[gl] make context creation more flexible<commit_after>//! EGL-based surface and swapchain.

use crate::{conv, native, GlContainer, PhysicalDevice};
use glow::HasContext;
use hal::{image, window as w};

#[derive(Debug)]
pub struct Swapchain {
    framebuffer: glow::Framebuffer,
    renderbuffer: glow::Renderbuffer,
    /// Extent because the window lies
    extent: w::Extent2D,
    format: native::TextureFormat,
    channel: hal::format::ChannelType,
}

#[derive(Debug)]
pub struct Instance {
    display: egl::Display,
    version: (i32, i32),
    config: egl::Config,
    context: egl::Context,
    supports_native_window: bool,
}

unsafe impl Send for Instance {}
unsafe impl Sync for Instance {}

impl hal::Instance<crate::Backend> for Instance {
    fn create(_: &str, _: u32) -> Result<Self, hal::UnsupportedBackend> {
        let client_extensions = egl::query_string(None, egl::EXTENSIONS)
            .map_err(|_| hal::UnsupportedBackend)?
            .to_string_lossy();
        log::info!("Client extensions: {:?}", client_extensions);
        let client_list = client_extensions.split_whitespace().collect::<Vec<_>>();

        #[cfg(feature = "x11")]
        let display = {
            if client_list.contains(&"EGL_EXT_platform_x11") {
                const EGL_PLATFORM_X11_KHR: u32 = 0x31D5;
                let x11_display = unsafe { x11::xlib::XOpenDisplay(std::ptr::null()) };
                assert!(!x11_display.is_null());
                let display_attributes = [egl::ATTRIB_NONE];
                egl::get_platform_display(
                    EGL_PLATFORM_X11_KHR,
                    x11_display as *mut _,
                    &display_attributes,
                )
                .unwrap()
            } else {
                log::warn!("X11 is not supported");
                egl::get_display(egl::DEFAULT_DISPLAY).unwrap()
            }
        };
        #[cfg(not(feature = "x11"))]
        let display = egl::get_display(egl::DEFAULT_DISPLAY).unwrap();

        let version = egl::initialize(display).map_err(|_| hal::UnsupportedBackend)?;
        let vendor = egl::query_string(Some(display), egl::VENDOR).unwrap();
        let display_extensions = egl::query_string(Some(display), egl::EXTENSIONS)
            .unwrap()
            .to_string_lossy();
        log::info!(
            "Display vendor {:?}, version {:?}, extensions: {:?}",
            vendor,
            version,
            display_extensions
        );
        if version < (1, 4) {
            log::error!("EGL supported version is only {:?}", version);
            return Err(hal::UnsupportedBackend);
        }
        {
            let required_list = ["EGL_KHR_create_context", "EGL_KHR_surfaceless_context"];
            let list = display_extensions.split_whitespace().collect::<Vec<_>>();
            for required_ext in required_list.iter() {
                if !list.contains(required_ext) {
                    log::warn!("{} is not present", required_ext);
                }
            }
        }

        {
            debug!("Configurations:");
            let config_count = egl::get_config_count(display).unwrap();
            let mut configurations = Vec::with_capacity(config_count);
            egl::get_configs(display, &mut configurations).unwrap();
            for &config in configurations.iter() {
                debug!("\tCONFORMANT=0x{:X}, RENDERABLE=0x{:X}, NATIVE_RENDERABLE=0x{:X}, SURFACE_TYPE=0x{:X}",
                    egl::get_config_attrib(display, config, egl::CONFORMANT).unwrap(),
                    egl::get_config_attrib(display, config, egl::RENDERABLE_TYPE).unwrap(),
                    egl::get_config_attrib(display, config, egl::NATIVE_RENDERABLE).unwrap(),
                    egl::get_config_attrib(display, config, egl::SURFACE_TYPE).unwrap(),
                );
            }
        }

        //Note: only GLES is supported here.
        let mut supports_native_window = true;
        //TODO: EGL_SLOW_CONFIG
        let config_attributes = [
            egl::CONFORMANT,
            egl::OPENGL_ES2_BIT,
            egl::RENDERABLE_TYPE,
            egl::OPENGL_ES2_BIT,
            egl::NATIVE_RENDERABLE,
            egl::TRUE as _,
            egl::SURFACE_TYPE,
            egl::WINDOW_BIT,
            egl::NONE,
        ];
        let config = match egl::choose_first_config(display, &config_attributes) {
            Ok(Some(config)) => config,
            Ok(None) => {
                log::warn!("no compatible EGL config found, trying off-screen");
                supports_native_window = false;
                let reduced_config_attributes =
                    [egl::RENDERABLE_TYPE, egl::OPENGL_ES2_BIT, egl::NONE];
                match egl::choose_first_config(display, &reduced_config_attributes) {
                    Ok(Some(config)) => config,
                    _ => return Err(hal::UnsupportedBackend),
                }
            }
            Err(e) => {
                log::error!("error in choose_first_config: {:?}", e);
                return Err(hal::UnsupportedBackend);
            }
        };

        egl::bind_api(egl::OPENGL_ES_API).unwrap();

        //TODO: make it so `Device` == EGL Context
        let mut context_attributes = vec![
            egl::CONTEXT_CLIENT_VERSION,
            3, // Request GLES 3.0 or higher
        ];
        if cfg!(debug_assertions) {
            context_attributes.push(egl::CONTEXT_OPENGL_DEBUG);
            context_attributes.push(egl::TRUE as _);
        }
        context_attributes.push(egl::NONE as _);
        let context = match egl::create_context(display, config, None, &context_attributes) {
            Ok(context) => context,
            Err(e) => {
                log::warn!("unable to create GLES 3.x context: {:?}", e);
                return Err(hal::UnsupportedBackend);
            }
        };

        Ok(Instance {
            display,
            version,
            config,
            context,
            supports_native_window,
        })
    }

    fn enumerate_adapters(&self) -> Vec<hal::adapter::Adapter<crate::Backend>> {
        egl::make_current(self.display, None, None, Some(self.context)).unwrap();
        let gl = unsafe {
            GlContainer::from_fn_proc(|name| egl::get_proc_address(name).unwrap() as *const _)
        };

        // Create physical device
        vec![PhysicalDevice::new_adapter(gl)]
    }

    unsafe fn create_surface(
        &self,
        has_handle: &impl raw_window_handle::HasRawWindowHandle,
    ) -> Result<Surface, w::InitError> {
        use raw_window_handle::RawWindowHandle as Rwh;
        let mut native_window = match has_handle.raw_window_handle() {
            #[cfg(not(target_os = "android"))]
            Rwh::Xlib(handle) => handle.window,
            #[cfg(not(target_os = "android"))]
            Rwh::Xcb(handle) => handle.window as _,
            #[cfg(target_os = "android")]
            Rwh::Android(handle) => handle.a_native_window,
            other => panic!("Unsupported window: {:?}", other),
        };
        let attributes = [
            egl::RENDER_BUFFER as usize,
            egl::SINGLE_BUFFER as usize,
            // Always enable sRGB
            egl::GL_COLORSPACE as usize,
            egl::GL_COLORSPACE_SRGB as usize,
            egl::ATTRIB_NONE,
        ];
        match egl::create_platform_window_surface(
            self.display,
            self.config,
            &mut native_window as *mut _ as *mut _,
            &attributes,
        ) {
            Ok(raw) => Ok(Surface {
                raw,
                display: self.display,
                context: self.context,
                presentable: self.supports_native_window,
                swapchain: None,
            }),
            Err(e) => {
                log::warn!("Error in create_window_surface: {:?}", e);
                Err(w::InitError::UnsupportedWindowHandle)
            }
        }
    }

    unsafe fn destroy_surface(&self, surface: Surface) {
        egl::destroy_surface(self.display, surface.raw).unwrap();
    }
}

impl Drop for Instance {
    fn drop(&mut self) {
        if let Err(e) = egl::destroy_context(self.display, self.context) {
            log::warn!("Error in destroy_context: {:?}", e);
        }
        if let Err(e) = egl::terminate(self.display) {
            log::warn!("Error in terminate: {:?}", e);
        }
    }
}

#[derive(Debug)]
pub struct Surface {
    raw: egl::Surface,
    display: egl::Display,
    context: egl::Context,
    presentable: bool,
    pub(crate) swapchain: Option<Swapchain>,
}

unsafe impl Send for Surface {}
unsafe impl Sync for Surface {}

impl w::PresentationSurface<crate::Backend> for Surface {
    type SwapchainImage = native::SwapchainImage;

    unsafe fn configure_swapchain(
        &mut self,
        device: &crate::Device,
        config: w::SwapchainConfig,
    ) -> Result<(), w::SwapchainError> {
        self.unconfigure_swapchain(device);

        let desc = conv::describe_format(config.format).unwrap();

        let gl = &device.share.context;
        let renderbuffer = gl.create_renderbuffer().unwrap();
        gl.bind_renderbuffer(glow::RENDERBUFFER, Some(renderbuffer));
        gl.renderbuffer_storage(
            glow::RENDERBUFFER,
            desc.tex_internal,
            config.extent.width as _,
            config.extent.height as _,
        );
        let framebuffer = gl.create_framebuffer().unwrap();
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(framebuffer));
        gl.framebuffer_renderbuffer(
            glow::READ_FRAMEBUFFER,
            glow::COLOR_ATTACHMENT0,
            glow::RENDERBUFFER,
            Some(renderbuffer),
        );
        gl.bind_renderbuffer(glow::RENDERBUFFER, None);
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);

        self.swapchain = Some(Swapchain {
            renderbuffer,
            framebuffer,
            extent: config.extent,
            format: desc.tex_internal,
            channel: config.format.base_format().1,
        });

        Ok(())
    }

    unsafe fn unconfigure_swapchain(&mut self, device: &crate::Device) {
        let gl = &device.share.context;
        if let Some(sc) = self.swapchain.take() {
            gl.delete_renderbuffer(sc.renderbuffer);
            gl.delete_framebuffer(sc.framebuffer);
        }
    }

    unsafe fn acquire_image(
        &mut self,
        _timeout_ns: u64,
    ) -> Result<(Self::SwapchainImage, Option<w::Suboptimal>), w::AcquireError> {
        let sc = self.swapchain.as_ref().unwrap();
        let sc_image =
            native::SwapchainImage::new(sc.renderbuffer, sc.format, sc.extent, sc.channel);
        Ok((sc_image, None))
    }
}

impl w::Surface<crate::Backend> for Surface {
    fn supports_queue_family(&self, _: &crate::QueueFamily) -> bool {
        self.presentable
    }

    fn capabilities(&self, _physical_device: &PhysicalDevice) -> w::SurfaceCapabilities {
        w::SurfaceCapabilities {
            present_modes: w::PresentMode::FIFO,                  //TODO
            composite_alpha_modes: w::CompositeAlphaMode::OPAQUE, //TODO
            image_count: 2..=2,
            current_extent: None,
            extents: w::Extent2D {
                width: 4,
                height: 4,
            }..=w::Extent2D {
                width: 4096,
                height: 4096,
            },
            max_image_layers: 1,
            usage: image::Usage::COLOR_ATTACHMENT,
        }
    }

    fn supported_formats(
        &self,
        _physical_device: &PhysicalDevice,
    ) -> Option<Vec<hal::format::Format>> {
        use hal::format::Format;
        Some(vec![Format::Rgba8Srgb, Format::Bgra8Srgb])
    }
}

impl Surface {
    pub(crate) unsafe fn present(
        &mut self,
        _image: native::SwapchainImage,
        gl: &GlContainer,
    ) -> Result<Option<w::Suboptimal>, w::PresentError> {
        let sc = self.swapchain.as_ref().unwrap();

        egl::make_current(
            self.display,
            Some(self.raw),
            Some(self.raw),
            Some(self.context),
        )
        .unwrap();
        gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None);
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuffer));
        gl.blit_framebuffer(
            0,
            0,
            sc.extent.width as _,
            sc.extent.height as _,
            0,
            0,
            sc.extent.width as _,
            sc.extent.height as _,
            glow::COLOR_BUFFER_BIT,
            glow::NEAREST,
        );
        gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);

        egl::swap_buffers(self.display, self.raw).unwrap();
        egl::make_current(self.display, None, None, Some(self.context)).unwrap();

        Ok(None)
    }
}
<|endoftext|>


<commit_before>use std::alloc::alloc;
use std::alloc::dealloc;
use std::alloc::Layout;
use std::mem::size_of;
use std::ptr::eq;
use std::ptr::null;
use std::ptr::null_mut;

const _PAGE_SIZE: usize = 0x1000;

pub struct _Page<'a> {
    current_page: *mut _Page<'a>,
    next_object_offset: i32,
    exclusive_pages: i32
}

impl<'a> _Page<'a> {

    pub unsafe fn reset(&mut self) {
        *(self.get_extension_page_location() as *mut *const _Page) = null();
        self.next_object_offset = 0;
        self.exclusive_pages = 0;

        // currentPage = this;
        self.current_page = &mut *self;
    }

    pub unsafe fn clear(&mut self) {
        self.deallocate_extensions();
        self.reset();
    }

    pub fn is_oversized(&self) -> bool {
        self.current_page.is_null()
    }

    unsafe fn get_extension_page_location(&self) -> usize {

        // Convert self to page location
        let self_location = self as *const _Page as usize;

        // Advance one page size so we are past the end of our page
        let location_behind_page = self_location + _PAGE_SIZE;

        // Go back one pointer size
        location_behind_page - size_of::<*const _Page>()
    }

    unsafe fn get_next_location(&self) -> usize {
        self as *const _Page as usize + self.next_object_offset as usize
    }

    unsafe fn set_next_location(&mut self, location: usize) {
        let self_location = self as *const _Page as usize;
        self.next_object_offset = (location - self_location as usize) as i32;
    }

    unsafe fn get_next_exclusive_page_location(&self) -> usize  {
        self.get_extension_page_location() - (self.exclusive_pages as usize + 1) * size_of::<*const _Page>()
    }

    pub unsafe fn allocate_raw(&mut self, size: usize, align: usize) -> *mut u8 {
        if !eq(self, self.current_page) {

            // We're already known to be full, so we delegate to the current page
            let new_object = (*self.current_page).allocate_raw(size, align);

            // Possibly our current page was also full so we propagate back the new current page
            let allocating_page = _Page::get_page(new_object);
            if !eq(allocating_page, self.current_page) && (!allocating_page.is_oversized()) {
                self.current_page = allocating_page;
            }
            return new_object;
        }

        // Try to allocate from ourselves
        let location = self.get_next_location();
        let next_location = (location + align - 1) & !(align - 1);
        if next_location <= self.get_next_exclusive_page_location() as usize {
            self.set_next_location(next_location);
            return location as *mut u8
        }

        // So the space did not fit.

        // Calculate gross size to decide whether we're oversized
        let gross_size = size_of::<_Page>() + size + size_of::<*const _Page>();
        if gross_size > _PAGE_SIZE {
            if self.get_next_location() >= self.get_extension_page_location() {

                // Allocate an extension page with default size
                let extension_page = self.allocate_extension_page();

                // Try again with the new extension page
                return extension_page.allocate_raw(size, align);
            }

            // We allocate oversized objects directly.
            let memory = alloc(Layout::from_size_align_unchecked(size + size_of::<_Page>(), _PAGE_SIZE) );

            // Initialize a _Page object at the page start
            let page = memory as *mut _Page<'a>;
            (*page).reset();

            // Oversized pages have no current_page
            (*page).current_page = null_mut();

            *(self.get_next_exclusive_page_location() as *mut *const _Page) = page;
            self.exclusive_pages += 1;
            return page.offset(1) as *mut u8;
        }

        // So we're not oversized. Create extension page and let it allocate.
        self.allocate_extension_page().allocate_raw(size, align)
    }

    unsafe fn allocate_extension_page(&mut self) -> &'a mut _Page<'a> {
        let page = _Page::allocate_page();
        *(self.get_extension_page_location() as *mut *const _Page) = page;
        self.current_page = page;
        &mut *page
    }

    unsafe fn allocate_page() -> *mut _Page<'a> {
        let memory = alloc(Layout::from_size_align_unchecked(_PAGE_SIZE, _PAGE_SIZE));
        let page = memory as *mut _Page<'a>;
        (*page).reset();
        page
    }

    pub unsafe fn allocate_exclusive_page(&mut self) -> &'a mut _Page<'a> {

        if !eq(self, self.current_page) {
            // We're already known to be full, so we delegate to the current page
            return (*self.current_page).allocate_exclusive_page();
        }

        // Check first whether we need an ordinary extension
        if self.get_next_location() >= self.get_next_exclusive_page_location() {

            // Allocate an extension page with default size
            return self.allocate_extension_page().allocate_exclusive_page();
        }

        let page = _Page::allocate_page();
        *(self.get_next_exclusive_page_location() as *mut *const _Page) = page;
        self.exclusive_pages += 1;
        &mut *page
    }

    pub fn extend(&mut self, top: usize, size: usize) -> bool {
        unsafe {
            if top != self.get_next_location() {
                return false;
            }

            let new_top = top + size;
            if new_top > self.get_next_exclusive_page_location() {
                return false;
            }
            self.set_next_location(new_top);
        }
        true
    }

    pub fn deallocate_extensions(&mut self) {
        let mut page: *mut _Page<'a> = self;
        unsafe {
            while !page.is_null() {
                let extension_location = (*page).get_extension_page_location();
                for i in 1..(*page).exclusive_pages {
                    let mut exclusive_page = &mut *((extension_location - (i as usize * size_of::<*const _Page> as usize)) as *mut _Page<'a>);
                    if !exclusive_page.is_oversized() {
                        exclusive_page.deallocate_extensions();
                    }
                    exclusive_page.forget();
                }

                if !eq(page, self) {
                    (*page).forget();
                }

                page = extension_location as *mut _Page<'a>;
            }
        }
    }

    pub fn forget(&self) {
        unsafe {
            dealloc(self as *const _Page as *mut u8, Layout::from_size_align_unchecked(_PAGE_SIZE, _PAGE_SIZE))
        }
    }

    pub unsafe fn get_page(address: *mut u8) -> &'a mut _Page<'a> {
        &mut *((address as usize & !_PAGE_SIZE - 1) as *mut _Page)
    }
}

#[test]
fn test_page() {

    unsafe {

        // Allocate a page
        let memory = alloc(Layout::from_size_align_unchecked(_PAGE_SIZE, _PAGE_SIZE) );
        assert_ne!(memory, null_mut());

        // Write some numbers to the page memory
        for i in 0.._PAGE_SIZE {
            let ptr = memory.offset(i as isize);
            *ptr = i as u8
        }

        // Initialize a _Page object at the page start
        let page = &mut *(memory as *mut _Page);

        assert_ne!(page.next_object_offset, 0);
        assert_ne!(page.exclusive_pages, 0);

        page.reset();

        assert_eq!(page.next_object_offset, 0);
        assert_eq!(page.exclusive_pages, 0);
        assert_eq!((*(page.current_page)).next_object_offset, 0);
        assert_eq!((*(page.current_page)).exclusive_pages, 0);
        assert_eq!(page.is_oversized(), false);

    }
}<commit_msg>compiles for now, page locations not yet correct<commit_after>use std::alloc::alloc;
use std::alloc::dealloc;
use std::alloc::Layout;
use std::mem::size_of;
use std::ptr::eq;
use std::ptr::null;
use std::ptr::null_mut;

const _PAGE_SIZE: usize = 0x1000;

pub struct _Page<'a> {
    current_page: *mut _Page<'a>,
    next_object_offset: i32,
    exclusive_pages: i32
}

impl<'a> _Page<'a> {

    pub fn reset(&mut self) {
        unsafe {
            *(self.get_extension_page_location() as *mut *const _Page) = null();
        }
        self.next_object_offset = 0;
        self.exclusive_pages = 0;
        self.current_page = &mut *self;
    }

    pub fn clear(&mut self) {
        self.deallocate_extensions();
        self.reset();
    }

    pub fn is_oversized(&self) -> bool {
        self.current_page.is_null()
    }

    fn get_extension_page_location(&self) -> usize {

        // Convert self to page location
        let self_location = self as *const _Page as usize;

        // Advance one page size so we are past the end of our page
        let location_behind_page = self_location + _PAGE_SIZE;

        // Go back one pointer size
        location_behind_page - size_of::<*const _Page>()
    }

    fn get_next_location(&self) -> usize {
        self as *const _Page as usize + self.next_object_offset as usize
    }

    fn set_next_location(&mut self, location: usize) {
        let self_location = self as *const _Page as usize;
        self.next_object_offset = (location - self_location as usize) as i32;
    }

    fn get_next_exclusive_page_location(&self) -> usize  {
        self.get_extension_page_location() - (self.exclusive_pages as usize + 1) * size_of::<*const _Page>()
    }

    pub fn allocate_raw(&mut self, size: usize, align: usize) -> *mut u8 {
        if !eq(self, self.current_page) {
            unsafe {
                // We're already known to be full, so we delegate to the current page
                let new_object = (*self.current_page).allocate_raw(size, align);

                // Possibly our current page was also full so we propagate back the new current page
                let allocating_page = _Page::get_page(new_object);
                if !eq(allocating_page, self.current_page) && (!allocating_page.is_oversized()) {
                    self.current_page = allocating_page;
                }
                return new_object;
            }
        }

        // Try to allocate from ourselves
        let location = self.get_next_location();
        let next_location = (location + align - 1) & !(align - 1);
        if next_location <= self.get_next_exclusive_page_location() as usize {
            self.set_next_location(next_location);
            return location as *mut u8
        }

        // So the space did not fit.

        // Calculate gross size to decide whether we're oversized
        if size_of::<_Page>() + size + size_of::<*const _Page>() > _PAGE_SIZE {
            if self.get_next_location() >= self.get_extension_page_location() {

                // Allocate an extension page with default size
                let extension_page = self.allocate_extension_page();

                // Try again with the new extension page
                return extension_page.allocate_raw(size, align);
            }

            unsafe {
                // We allocate oversized objects directly.
                let memory = alloc(Layout::from_size_align_unchecked(size + size_of::<_Page>(), _PAGE_SIZE) );

                // Initialize a _Page object at the page start
                let page = memory as *mut _Page<'a>;

                // Oversized pages have no current_page
                (*page).current_page = null_mut();

                // Set the size since we will need it when deallocating
                (*page).next_object_offset = (size % 0x100000000) as i32;
                (*page).exclusive_pages =    (size / 0x100000000) as i32;

                *(self.get_next_exclusive_page_location() as *mut *const _Page) = page;
                self.exclusive_pages += 1;
                return page.offset(1) as *mut u8;
            }
        }

        // So we're not oversized. Create extension page and let it allocate.
        self.allocate_extension_page().allocate_raw(size, align)
    }

    fn allocate_extension_page(&mut self) -> &'a mut _Page<'a> {
        unsafe {
            let page = _Page::allocate_page();
            *(self.get_extension_page_location() as *mut *const _Page) = page;
            self.current_page = page;
            &mut *page
        }
    }

    fn allocate_page() -> *mut _Page<'a> {
        unsafe {
            let memory = alloc(Layout::from_size_align_unchecked(_PAGE_SIZE, _PAGE_SIZE));
            let page = memory as *mut _Page<'a>;
            (*page).reset();
            page
        }
    }

    pub fn allocate_exclusive_page(&mut self) -> &'a mut _Page<'a> {

        if !eq(self, self.current_page) {
            unsafe {
                // We're already known to be full, so we delegate to the current page
                return (*self.current_page).allocate_exclusive_page();
            }
        }

        // Check first whether we need an ordinary extension
        if self.get_next_location() >= self.get_next_exclusive_page_location() {

            // Allocate an extension page with default size
            return self.allocate_extension_page().allocate_exclusive_page();
        }

        let page = _Page::allocate_page();
        unsafe {
            *(self.get_next_exclusive_page_location() as *mut *const _Page) = page;
            self.exclusive_pages += 1;
            &mut *page
        }
    }

    pub fn extend(&mut self, top: usize, size: usize) -> bool {
        if top != self.get_next_location() {
            return false;
        }

        let new_top = top + size;
        if new_top > self.get_next_exclusive_page_location() {
            return false;
        }
        self.set_next_location(new_top);

        true
    }

    pub fn deallocate_extensions(&mut self) {
        let mut page: *mut _Page<'a> = self;
        unsafe {
            while !page.is_null() {
                let extension_location = (*page).get_extension_page_location();
                for i in 1..(*page).exclusive_pages {
                    let mut exclusive_page = &mut *((extension_location - (i as usize * size_of::<*const _Page> as usize)) as *mut _Page<'a>);
                    if !exclusive_page.is_oversized() {
                        exclusive_page.deallocate_extensions();
                    }
                    exclusive_page.forget();
                }

                if !eq(page, self) {
                    (*page).forget();
                }

                page = extension_location as *mut _Page<'a>;
            }
        }
    }

    pub fn forget(&self) {
        let size = if self.current_page == null_mut() {
            self.next_object_offset as usize + self.exclusive_pages as usize * 0x100000000
        } else {
            _PAGE_SIZE
        };
        unsafe {
            dealloc(self as *const _Page as *mut u8, Layout::from_size_align_unchecked(size, _PAGE_SIZE))
        }
    }

    pub fn reclaim_array(&mut self, address: usize) -> bool {
        unsafe {
            let mut page: *mut _Page<'a> = self;
            while !page.is_null() {
                if (*page).deallocate_exclusive_page(&mut *(address as *mut _Page<'a>)) {
                    return true;
                }
                page = (*page).get_extension_page_location() as *mut _Page<'a>;
            }
        }

        // If we arrive here, we have a memory leak.
        false
    }

    pub fn get_page(address: *mut u8) -> &'a mut _Page<'a> {
        unsafe {
            &mut *((address as usize & !_PAGE_SIZE - 1) as *mut _Page)
        }
    }

    fn deallocate_exclusive_page(&mut self, page: &'a mut _Page<'a>) -> bool {
        // Find the extension Page pointer
        let mut extension_location = self.get_extension_page_location() - size_of::<*const _Page>();
        let next_extension_page_location = self.get_next_exclusive_page_location();
        while extension_location > next_extension_page_location {
            if eq(extension_location as *const _Page, page) {
                break; }
            extension_location -= size_of::<*const _Page>();
        }

        // Report if we could not find it
        if extension_location == next_extension_page_location {
            return false;
        }

        // Shift the remaining array one position up
        while extension_location > next_extension_page_location {
            let pp_page = extension_location as *mut *const _Page;
            unsafe {
                *pp_page = *(pp_page.offset(- 1));
            }
            extension_location -= size_of::<*const _Page>();
        }

        // Make room for one more extension
        self.exclusive_pages -= 1;
        page.forget();

        true
    }
}

#[test]
fn test_page() {

    unsafe {

        // Allocate a page
        let memory = alloc(Layout::from_size_align_unchecked(_PAGE_SIZE, _PAGE_SIZE) );
        assert_ne!(memory, null_mut());

        // Write some numbers to the page memory
        for i in 0.._PAGE_SIZE {
            let ptr = memory.offset(i as isize);
            *ptr = i as u8
        }

        // Initialize a _Page object at the page start
        let page = &mut *(memory as *mut _Page);

        assert_ne!(page.next_object_offset, 0);
        assert_ne!(page.exclusive_pages, 0);

        page.reset();

        assert_eq!(page.next_object_offset, 0);
        assert_eq!(page.exclusive_pages, 0);
        assert_eq!((*(page.current_page)).next_object_offset, 0);
        assert_eq!((*(page.current_page)).exclusive_pages, 0);
        assert_eq!(page.is_oversized(), false);

    }
}<|endoftext|>


<commit_before>use std::io::{Write, Result as IOResult};

use term_grid as tg;

use fs::File;
use style::Colours;
use output::file_name::FileStyle;
use output::cell::DisplayWidth;

#[derive(PartialEq, Debug, Copy, Clone)]
pub struct Options {
    pub across: bool,
    pub console_width: usize,
}

impl Options {
    pub fn direction(&self) -> tg::Direction {
        if self.across { tg::Direction::LeftToRight }
                  else { tg::Direction::TopToBottom }
    }
}

pub struct Render<'a> {
    pub files: Vec<File<'a>>,
    pub colours: &'a Colours,
    pub style: &'a FileStyle,
    pub opts: &'a Options,
}

impl<'a> Render<'a> {
    pub fn render<W: Write>(&self, w: &mut W) -> IOResult<()> {
        let mut grid = tg::Grid::new(tg::GridOptions {
            direction:  self.opts.direction(),
            filling:    tg::Filling::Spaces(2),
        });

        grid.reserve(self.files.len());

        for file in self.files.iter() {
            let file_icon = icon(&file);
            let filename = self.style.for_file(file, self.colours).paint();
            let width = DisplayWidth::from(2) + filename.width();

            grid.add(tg::Cell {
                contents:  format!("{} {}", file_icon, filename.strings().to_string()),
                width:     *width,
            });
        }

        if let Some(display) = grid.fit_into_width(self.opts.console_width) {
            write!(w, "{}", display)
        }
        else {
            // File names too long for a grid - drop down to just listing them!
            // This isn’t *quite* the same as the lines view, which also
            // displays full link paths.
            for file in self.files.iter() {
                let name_cell = self.style.for_file(file, self.colours).paint();
                writeln!(w, "{}", name_cell.strings())?;
            }
            Ok(())
        }
    }
}

fn icon(file: &File) -> char {
    if file.is_directory() { '\u{f115}' }
    else {
        // possible unnecessary clone
        if let Some(ext) = file.ext.clone() {
            match ext.as_str() {
                "ai" => '\u{e7b4}',
                "android" => '\u{e70e}',
                "apple" => '\u{f179}',
                "audio" => '\u{f001}',
                "avro" => '\u{e60b}',
                "c" => '\u{e61e}',
                "clj" => '\u{e768}',
                "coffee" => '\u{f0f4}',
                "conf" => '\u{e615}',
                "cpp" => '\u{e61d}',
                "css" => '\u{e749}',
                "d" => '\u{e7af}',
                "dart" => '\u{e798}',
                "db" => '\u{f1c0}',
                "diff" => '\u{f440}',
                "doc" => '\u{f1c2}',
                "ebook" => '\u{e28b}',
                "env" => '\u{f462}',
                "epub" => '\u{e28a}',
                "erl" => '\u{e7b1}',
                "font" => '\u{f031}',
                "gform" => '\u{f298}',
                "git" => '\u{f1d3}',
                "go" => '\u{e626}',
                "hs" => '\u{e777}',
                "html" => '\u{f13b}',
                "image" => '\u{f1c5}',
                "iml" => '\u{e7b5}',
                "java" => '\u{e204}',
                "js" => '\u{e74e}',
                "json" => '\u{e60b}',
                "jsx" => '\u{e7ba}',
                "less" => '\u{e758}',
                "log" => '\u{f18d}',
                "lua" => '\u{e620}',
                "md" => '\u{f48a}',
                "mustache" => '\u{e60f}',
                "npmignore" => '\u{e71e}',
                "pdf" => '\u{f1c1}',
                "php" => '\u{e73d}',
                "pl" => '\u{e769}',
                "ppt" => '\u{f1c4}',
                "psd" => '\u{e7b8}',
                "py" => '\u{e606}',
                "r" => '\u{f25d}',
                "rb" => '\u{e21e}',
                "rdb" => '\u{e76d}',
                "rss" => '\u{f09e}',
                "rubydoc" => '\u{e73b}',
                "sass" => '\u{e603}',
                "scala" => '\u{e737}',
                "shell" => '\u{f489}',
                "sqlite3" => '\u{e7c4}',
                "styl" => '\u{e600}',
                "tex" => '\u{e600}',
                "ts" => '\u{e628}',
                "twig" => '\u{e61c}',
                "txt" => '\u{f15c}',
                "video" => '\u{f03d}',
                "vim" => '\u{e62b}',
                "windows" => '\u{f17a}',
                "xls" => '\u{f1c3}',
                "xml" => '\u{e619}',
                "yml" => '\u{f481}',
                "zip" => '\u{f410}',
                _ => '\u{f15b}'
            }
        } else {
            '\u{f15b}'
        }
    }
}
<commit_msg>Added painting to icon<commit_after>use std::io::{Write, Result as IOResult};

use term_grid as tg;

use fs::File;
use style::Colours;
use output::file_name::FileStyle;
use output::cell::DisplayWidth;

#[derive(PartialEq, Debug, Copy, Clone)]
pub struct Options {
    pub across: bool,
    pub console_width: usize,
}

impl Options {
    pub fn direction(&self) -> tg::Direction {
        if self.across { tg::Direction::LeftToRight }
                  else { tg::Direction::TopToBottom }
    }
}

pub struct Render<'a> {
    pub files: Vec<File<'a>>,
    pub colours: &'a Colours,
    pub style: &'a FileStyle,
    pub opts: &'a Options,
}

impl<'a> Render<'a> {
    pub fn render<W: Write>(&self, w: &mut W) -> IOResult<()> {
        let mut grid = tg::Grid::new(tg::GridOptions {
            direction:  self.opts.direction(),
            filling:    tg::Filling::Spaces(2),
        });

        grid.reserve(self.files.len());

        for file in self.files.iter() {
            let file_icon = icon(&file);
            let painted_icon = self.style.exts
                .colour_file(&file)
                .map_or(file_icon.to_string(), |c| { c.paint(format!("{}", file_icon)).to_string() });
            let filename = self.style.for_file(file, self.colours).paint();
            let width = DisplayWidth::from(2) + filename.width();

            grid.add(tg::Cell {
                contents:  format!("{} {}", painted_icon, filename.strings().to_string()),
                width:     *width,
            });
        }

        if let Some(display) = grid.fit_into_width(self.opts.console_width) {
            write!(w, "{}", display)
        }
        else {
            // File names too long for a grid - drop down to just listing them!
            // This isn’t *quite* the same as the lines view, which also
            // displays full link paths.
            for file in self.files.iter() {
                let name_cell = self.style.for_file(file, self.colours).paint();
                writeln!(w, "{}", name_cell.strings())?;
            }
            Ok(())
        }
    }
}

fn icon(file: &File) -> char {
    if file.is_directory() { '\u{f115}' }
    else {
        // possible unnecessary clone
        if let Some(ext) = file.ext.clone() {
            match ext.as_str() {
                "ai" => '\u{e7b4}',
                "android" => '\u{e70e}',
                "apple" => '\u{f179}',
                "audio" => '\u{f001}',
                "avro" => '\u{e60b}',
                "c" => '\u{e61e}',
                "clj" => '\u{e768}',
                "coffee" => '\u{f0f4}',
                "conf" => '\u{e615}',
                "cpp" => '\u{e61d}',
                "css" => '\u{e749}',
                "d" => '\u{e7af}',
                "dart" => '\u{e798}',
                "db" => '\u{f1c0}',
                "diff" => '\u{f440}',
                "doc" => '\u{f1c2}',
                "ebook" => '\u{e28b}',
                "env" => '\u{f462}',
                "epub" => '\u{e28a}',
                "erl" => '\u{e7b1}',
                "font" => '\u{f031}',
                "gform" => '\u{f298}',
                "git" => '\u{f1d3}',
                "go" => '\u{e626}',
                "hs" => '\u{e777}',
                "html" => '\u{f13b}',
                "image" => '\u{f1c5}',
                "iml" => '\u{e7b5}',
                "java" => '\u{e204}',
                "js" => '\u{e74e}',
                "json" => '\u{e60b}',
                "jsx" => '\u{e7ba}',
                "less" => '\u{e758}',
                "log" => '\u{f18d}',
                "lua" => '\u{e620}',
                "md" => '\u{f48a}',
                "mustache" => '\u{e60f}',
                "npmignore" => '\u{e71e}',
                "pdf" => '\u{f1c1}',
                "php" => '\u{e73d}',
                "pl" => '\u{e769}',
                "ppt" => '\u{f1c4}',
                "psd" => '\u{e7b8}',
                "py" => '\u{e606}',
                "r" => '\u{f25d}',
                "rb" => '\u{e21e}',
                "rdb" => '\u{e76d}',
                "rss" => '\u{f09e}',
                "rubydoc" => '\u{e73b}',
                "sass" => '\u{e603}',
                "scala" => '\u{e737}',
                "shell" => '\u{f489}',
                "sqlite3" => '\u{e7c4}',
                "styl" => '\u{e600}',
                "tex" => '\u{e600}',
                "ts" => '\u{e628}',
                "twig" => '\u{e61c}',
                "txt" => '\u{f15c}',
                "video" => '\u{f03d}',
                "vim" => '\u{e62b}',
                "windows" => '\u{f17a}',
                "xls" => '\u{f1c3}',
                "xml" => '\u{e619}',
                "yml" => '\u{f481}',
                "zip" => '\u{f410}',
                _ => '\u{f15b}'
            }
        } else {
            '\u{f15b}'
        }
    }
}
<|endoftext|>


<commit_before>#![feature(collections)]

extern crate elf;

use std::path::Path;

fn main() {
    let path = Path::new("stress");
    let file = match elf::File::open_path(&path) {
        Ok(f) => f,
        Err(e) => panic!("Error: {:?}", e),
    };
    println!("Debug-print ELF file:");
    println!("{:?}", file);
    println!("");
    println!("Pretty-print ELF file:");
    println!("{}", file);

    println!("Getting the .text section");
    let text = file.get_section(".text");
    match text {
        Some(s) => println!("shdr: {}", s),
        None => println!("Failed to look up .text section!"),
    }
}
<commit_msg>Remove an unknown feature.<commit_after>
extern crate elf;

use std::path::Path;

fn main() {
    let path = Path::new("stress");
    let file = match elf::File::open_path(&path) {
        Ok(f) => f,
        Err(e) => panic!("Error: {:?}", e),
    };
    println!("Debug-print ELF file:");
    println!("{:?}", file);
    println!("");
    println!("Pretty-print ELF file:");
    println!("{}", file);

    println!("Getting the .text section");
    let text = file.get_section(".text");
    match text {
        Some(s) => println!("shdr: {}", s),
        None => println!("Failed to look up .text section!"),
    }
}
<|endoftext|>


<commit_before>#[derive(Debug, Clone, PartialEq)]
pub enum TokenOperator {
    Start,
    Cmd,
    And,
    Or,
    Pipe,
    SingleRight,
    SingleLeft,
    Semicolon,
    Eof
}

#[derive(Debug, Clone)]
pub struct Token {
    pub kind: TokenOperator,
    pub value: Option<String>
}

pub struct Lexer {
    command: String,
    pos: usize,
    current_char: Option<char>,
}

impl Lexer {
    pub fn new(command: String) -> Lexer {
        let c = command.clone().chars().next();
        return Lexer {
            command,
            pos: 0,
            current_char: c
        }
    }

    fn peek(&self) -> Option<char> {
        let peek_pos = self.pos + 1;
        if peek_pos > self.command.len() {
            return None;
        }
        return self.command.chars().nth(peek_pos)
    }

    fn command(&mut self) -> Token {
        let mut result: String = String::new();
        while let Some(c) = self.current_char {
            if !";|&><".contains(c) {
                result.push(c);
                self.advance();
            } else if c.is_whitespace() {
                self.skip_whitespace();
            } else {
                break;
            }

        }
        result = result.trim().to_string();
        return Token {
            kind: TokenOperator::Cmd,
            value: Some(result)
        }
    }

    fn advance(&mut self) {
        self.pos += 1;
        self.current_char = self.command.chars().nth(self.pos);
    }

    fn skip_whitespace(&mut self) {
        while self.pos < self.command.len() && self.current_char.unwrap().is_whitespace() {
            self.advance();
        }
    }

    fn peek_check(&mut self, c: char) -> bool{
        match self.peek() {
            Some(p) => return p == c,
            None    => return false
        }
    }

    pub fn get_next_token(&mut self) -> Token {
        while self.current_char.is_some() {
            let c = self.current_char.unwrap();
            if c.is_whitespace() {
                self.skip_whitespace();
                continue;
            }

            if c.is_alphabetic() || "/.".contains(c) {
                return self.command();
            } else if c == ';' {
                self.advance();
                return Token { kind: TokenOperator::Semicolon, value: None }
            } else if c == '|' && self.peek_check(c) {
                self.advance();
                self.advance();
                return Token { kind: TokenOperator::Or, value: None }
            } else if c == '&' && self.peek_check(c) {
                self.advance();
                self.advance();
                return Token { kind: TokenOperator::And, value: None }
            } else if c.is_alphabetic() {
                return self.command();
            } else if c == '>' {
                self.advance();
                return TokenOperator { kind: TokenOperator::SingleRight, value: None}
            } else {
                panic!("Unknown token")
            }
        }
        return Token { kind: TokenOperator::EOF, value: None }
    }

    pub fn set_command(&mut self, command: String) {
        let c = command.clone().chars().next();
        self.command = command;
        self.pos = 0;
        self.current_char = c
    }
}
<commit_msg>Added single redirection left in the lexer<commit_after>#[derive(Debug, Clone, PartialEq)]
pub enum TokenOperator {
    Start,
    Cmd,
    And,
    Or,
    Pipe,
    SingleRight,
    SingleLeft,
    Semicolon,
    Eof
}

#[derive(Debug, Clone)]
pub struct Token {
    pub kind: TokenOperator,
    pub value: Option<String>
}

pub struct Lexer {
    command: String,
    pos: usize,
    current_char: Option<char>,
}

impl Lexer {
    pub fn new(command: String) -> Lexer {
        let c = command.clone().chars().next();
        return Lexer {
            command,
            pos: 0,
            current_char: c
        }
    }

    fn peek(&self) -> Option<char> {
        let peek_pos = self.pos + 1;
        if peek_pos > self.command.len() {
            return None;
        }
        return self.command.chars().nth(peek_pos)
    }

    fn command(&mut self) -> Token {
        let mut result: String = String::new();
        while let Some(c) = self.current_char {
            if !";|&><".contains(c) {
                result.push(c);
                self.advance();
            } else if c.is_whitespace() {
                self.skip_whitespace();
            } else {
                break;
            }

        }
        result = result.trim().to_string();
        return Token {
            kind: TokenOperator::Cmd,
            value: Some(result)
        }
    }

    fn advance(&mut self) {
        self.pos += 1;
        self.current_char = self.command.chars().nth(self.pos);
    }

    fn skip_whitespace(&mut self) {
        while self.pos < self.command.len() && self.current_char.unwrap().is_whitespace() {
            self.advance();
        }
    }

    fn peek_check(&mut self, c: char) -> bool{
        match self.peek() {
            Some(p) => return p == c,
            None    => return false
        }
    }

    pub fn get_next_token(&mut self) -> Token {
        while self.current_char.is_some() {
            let c = self.current_char.unwrap();
            if c.is_whitespace() {
                self.skip_whitespace();
                continue;
            }

            if c.is_alphabetic() || "/.".contains(c) {
                return self.command();
            } else if c == ';' {
                self.advance();
                return Token { kind: TokenOperator::Semicolon, value: None }
            } else if c == '|' && self.peek_check(c) {
                self.advance();
                self.advance();
                return Token { kind: TokenOperator::Or, value: None }
            } else if c == '&' && self.peek_check(c) {
                self.advance();
                self.advance();
                return Token { kind: TokenOperator::And, value: None }
            } else if c == '>' && !self.peek_check(c) {
                self.advance();
                return Token { kind: TokenOperator::SingleRight, value: None}
            } else if c == '<' && !self.peek_check(c) {
                self.advance();
                return Token { kind: TokenOperator::SingleLeft, value: None}
            } else if c == '|' && !self.peek_check(c) {
                self.advance();
                return Token { kind: TokenOperator::Pipe, value: None}
            } else {
                panic!("Unknown token {}", c)
            }
        }
        return Token { kind: TokenOperator::Eof, value: None }
    }

    pub fn set_command(&mut self, command: String) {
        let c = command.clone().chars().next();
        self.command = command;
        self.pos = 0;
        self.current_char = c
    }
}
<|endoftext|>