<commit_before>use once_cell::sync::OnceCell;
use std::ops::RangeBounds;
use std::sync::RwLock;
use serde_json::json;

/// グローバルに保持するデータ。
/// ユーザによる設定と、見つからなかった場合に使うデフォルト値からなる。
/// それぞれは Json object によるツリー構造。
struct ConfigData {
    def:  serde_json::Value,
    main: serde_json::Value,
}

// default = empty Object (map)
impl Default for ConfigData {
    fn default() -> Self {
        Self { def: json!({}), main: json!({}) }
    }
}

/// 設定データ(グローバル変数)。
/// 一応スレッドセーフとするが、初期化時に一度だけ書き換え、
/// その後は read only アクセスしかしないので RwLock とする。
static CONFIG: OnceCell<RwLock<ConfigData>> = OnceCell::new();

/// 設定データを json 文字列からロードして設定データシステムを初期化する。
pub fn init_and_load(def_json: &str, main_json: &str) -> Result<(), String>
{
    // parse
    let vdef = match serde_json::from_str(def_json) {
        Ok(json) => json,
        Err(e) => return Err(format!("{}", e)),
    };
    let vmain = match serde_json::from_str(main_json) {
        Ok(json) => json,
        Err(e) => return Err(format!("{}", e)),
    };

    // lazy inialize + wlock
    let mut config = CONFIG
        .get_or_init(|| RwLock::new(Default::default()))
        .write()
        .unwrap();

    config.def = vdef;
    config.main = vmain;

    Ok(())
}

/// Object tree を keys: 文字列の配列 (スライス) で検索する。
/// 見つからなかった場合、および
/// 数値, 真偽値, 文字列, 配列 以外が見つかった場合は json - null を返す。
/// グローバル構造内のデータを返す場合、コピーを返す。
fn search(root: &serde_json::Value, keys: &[&str]) -> serde_json::Value {
    let null_value = serde_json::Value::Null;

    let mut value = root;
    for key in keys.iter() {
        value = match value.as_object() {
            Some(map) => map.get(*key).unwrap_or(&null_value),
            None => &null_value,
        };
    }

    if value.is_number() || value.is_boolean() || value.is_string() || value.is_array() {
        value.clone()
    }
    else {
        serde_json::Value::Null
    }
}

/// main -> def の順番で検索する。
fn search_all(keys: &[&str]) -> serde_json::Value {
    // rlock
    let config = CONFIG
        .get().unwrap()
        .read().unwrap();

    let value = search(&config.main, keys);
    if !value.is_null() {
        value
    }
    else {
        search(&config.def, keys)
    }
}

/// 真偽値設定データを取得する。
/// 見つからない場合や真偽値でない場合は None を返す。
pub fn get_boolean(keys: &[&str]) -> Option<bool> {
    search_all(keys).as_bool()
}

/// 数値データを i64 で取得する。
/// 見つからない場合、数値でない場合、範囲外の場合は None を返す。
pub fn get_i64<R: RangeBounds<i64>>(keys: &[&str], range: R) -> Option<i64> {
    search_all(keys).as_i64().and_then(|num| {
        if range.contains(&num) { Some(num) }
        else { None }
    })
}

/// 数値データを u64 で取得する。
/// 見つからない場合、数値でない場合、範囲外の場合は None を返す。
pub fn get_u64<R: RangeBounds<u64>>(keys: &[&str], range: R) -> Option<u64> {
    search_all(keys).as_u64().and_then(|num| {
        if range.contains(&num) { Some(num) }
        else { None }
    })
}

/// 文字列設定データを取得する。
/// 見つからない場合や文字列でない場合は None を返す。
pub fn get_string(keys: &[&str]) -> Option<String> {
    search_all(keys).as_str().map(|s| s.into())
}

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

    #[test]
    #[serial(config)]
    fn search() {
        let main = r#"{"a": {"b": {"c": "main"}}}"#;
        let def = r#"{"a": {"b": {"d": "default"}}}"#;

        init_and_load(def, main).unwrap();

        let v = get_string(&["a", "b", "c"]);
        assert!(v.unwrap() == "main");
        let v = get_string(&["a", "b", "C"]);
        assert!(v.is_none());
        let v = get_string(&["a", "b", "d"]);
        assert!(v.unwrap() == "default");
        let v = get_string(&["a", "b", "D"]);
        assert!(v.is_none());
    }

    #[test]
    #[serial(config)]
    fn i64() {
        let main = r#"{"i64": {"min": -9223372036854775808, "max": 9223372036854775807}}"#;
        let def = "{}";

        init_and_load(def, main).unwrap();

        let v = get_i64(&["i64", "min"], ..);
        assert_eq!(v.unwrap(), i64::MIN);
        let v = get_i64(&["i64", "max"], ..);
        assert_eq!(v.unwrap(), i64::MAX);

        let v = get_i64(&["i64", "min"], i64::MIN+1..);
        assert!(v.is_none());
        let v = get_i64(&["i64", "max"], ..=i64::MAX-1);
        assert!(v.is_none());
    }

    #[test]
    #[serial(config)]
    fn u64() {
        let main = r#"{"u64": {"min": 0, "max": 18446744073709551615}}"#;
        let def = "{}";

        init_and_load(def, main).unwrap();

        let v = get_u64(&["u64", "min"], ..);
        assert_eq!(v.unwrap(), u64::MIN);
        let v = get_u64(&["u64", "max"], ..);
        assert_eq!(v.unwrap(), u64::MAX);

        let v = get_u64(&["u64", "min"], u64::MIN+1..);
        assert!(v.is_none());
        let v = get_u64(&["u64", "max"], ..=u64::MAX-1);
        assert!(v.is_none());
    }

    #[test]
    #[should_panic]
    fn parse_error() {
        let jsonstr = "{1: 2";
        init_and_load(jsonstr, jsonstr).unwrap();
    }
}
<commit_msg>bool, string のテスト追加<commit_after>use once_cell::sync::OnceCell;
use std::ops::RangeBounds;
use std::sync::RwLock;
use serde_json::json;

/// グローバルに保持するデータ。
/// ユーザによる設定と、見つからなかった場合に使うデフォルト値からなる。
/// それぞれは Json object によるツリー構造。
struct ConfigData {
    def:  serde_json::Value,
    main: serde_json::Value,
}

// default = empty Object (map)
impl Default for ConfigData {
    fn default() -> Self {
        Self { def: json!({}), main: json!({}) }
    }
}

/// 設定データ(グローバル変数)。
/// 一応スレッドセーフとするが、初期化時に一度だけ書き換え、
/// その後は read only アクセスしかしないので RwLock とする。
static CONFIG: OnceCell<RwLock<ConfigData>> = OnceCell::new();

/// 設定データを json 文字列からロードして設定データシステムを初期化する。
pub fn init_and_load(def_json: &str, main_json: &str) -> Result<(), String>
{
    // parse
    let vdef = match serde_json::from_str(def_json) {
        Ok(json) => json,
        Err(e) => return Err(format!("{}", e)),
    };
    let vmain = match serde_json::from_str(main_json) {
        Ok(json) => json,
        Err(e) => return Err(format!("{}", e)),
    };

    // lazy inialize + wlock
    let mut config = CONFIG
        .get_or_init(|| RwLock::new(Default::default()))
        .write()
        .unwrap();

    config.def = vdef;
    config.main = vmain;

    Ok(())
}

/// Object tree を keys: 文字列の配列 (スライス) で検索する。
/// 見つからなかった場合、および
/// 数値, 真偽値, 文字列, 配列 以外が見つかった場合は json - null を返す。
/// グローバル構造内のデータを返す場合、コピーを返す。
fn search(root: &serde_json::Value, keys: &[&str]) -> serde_json::Value {
    let null_value = serde_json::Value::Null;

    let mut value = root;
    for key in keys.iter() {
        value = match value.as_object() {
            Some(map) => map.get(*key).unwrap_or(&null_value),
            None => &null_value,
        };
    }

    if value.is_number() || value.is_boolean() || value.is_string() || value.is_array() {
        value.clone()
    }
    else {
        serde_json::Value::Null
    }
}

/// main -> def の順番で検索する。
fn search_all(keys: &[&str]) -> serde_json::Value {
    // rlock
    let config = CONFIG
        .get().unwrap()
        .read().unwrap();

    let value = search(&config.main, keys);
    if !value.is_null() {
        value
    }
    else {
        search(&config.def, keys)
    }
}

/// 真偽値設定データを取得する。
/// 見つからない場合や真偽値でない場合は None を返す。
pub fn get_bool(keys: &[&str]) -> Option<bool> {
    search_all(keys).as_bool()
}

/// 数値データを i64 で取得する。
/// 見つからない場合、数値でない場合、範囲外の場合は None を返す。
pub fn get_i64<R: RangeBounds<i64>>(keys: &[&str], range: R) -> Option<i64> {
    search_all(keys).as_i64().and_then(|num| {
        if range.contains(&num) { Some(num) }
        else { None }
    })
}

/// 数値データを u64 で取得する。
/// 見つからない場合、数値でない場合、範囲外の場合は None を返す。
pub fn get_u64<R: RangeBounds<u64>>(keys: &[&str], range: R) -> Option<u64> {
    search_all(keys).as_u64().and_then(|num| {
        if range.contains(&num) { Some(num) }
        else { None }
    })
}

/// 文字列設定データを取得する。
/// 見つからない場合や文字列でない場合は None を返す。
pub fn get_string(keys: &[&str]) -> Option<String> {
    search_all(keys).as_str().map(|s| s.into())
}

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

    #[test]
    #[serial(config)]
    fn search() {
        let main = r#"{"a": {"b": {"c": "main"}}}"#;
        let def = r#"{"a": {"b": {"d": "default"}}}"#;
        init_and_load(def, main).unwrap();

        let v = get_string(&["a", "b", "c"]);
        assert!(v.unwrap() == "main");
        let v = get_string(&["a", "b", "C"]);
        assert!(v.is_none());
        let v = get_string(&["a", "b", "d"]);
        assert!(v.unwrap() == "default");
        let v = get_string(&["a", "b", "D"]);
        assert!(v.is_none());
    }

    #[test]
    #[serial(config)]
    fn bool_string() {
        let main = r#"{"root": {"bool1": false, "bool2": true, "str": "Hello"}}"#;
        let def = "{}";
        init_and_load(def, main).unwrap();

        let v = get_bool(&["root", "bool1"]);
        assert!(v.unwrap() == false);
        let v = get_bool(&["root", "bool2"]);
        assert!(v.unwrap() == true);
        let v = get_string(&["root", "str"]);
        assert!(v.unwrap() == "Hello");
    }

    #[test]
    #[serial(config)]
    fn i64() {
        let main = r#"{"i64": {"min": -9223372036854775808, "max": 9223372036854775807}}"#;
        let def = "{}";
        init_and_load(def, main).unwrap();

        let v = get_i64(&["i64", "min"], ..);
        assert_eq!(v.unwrap(), i64::MIN);
        let v = get_i64(&["i64", "max"], ..);
        assert_eq!(v.unwrap(), i64::MAX);

        let v = get_i64(&["i64", "min"], i64::MIN+1..);
        assert!(v.is_none());
        let v = get_i64(&["i64", "max"], ..=i64::MAX-1);
        assert!(v.is_none());
    }

    #[test]
    #[serial(config)]
    fn u64() {
        let main = r#"{"u64": {"min": 0, "max": 18446744073709551615}}"#;
        let def = "{}";
        init_and_load(def, main).unwrap();

        let v = get_u64(&["u64", "min"], ..);
        assert_eq!(v.unwrap(), u64::MIN);
        let v = get_u64(&["u64", "max"], ..);
        assert_eq!(v.unwrap(), u64::MAX);

        let v = get_u64(&["u64", "min"], u64::MIN+1..);
        assert!(v.is_none());
        let v = get_u64(&["u64", "max"], ..=u64::MAX-1);
        assert!(v.is_none());
    }

    #[test]
    #[should_panic]
    fn parse_error() {
        let jsonstr = "{1: 2";
        init_and_load(jsonstr, jsonstr).unwrap();
    }
}
<|endoftext|>


<commit_before>use core::fmt::{self, Display};

use super::{Date, DateTime, Duration, Time};

impl Display for Date {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            // like `2015-11-02`
            Date::YMD { year, month, day } => write!(f, "{:04}-{:02}-{:02}", year, month, day),
            // like `2015-W45-01`
            Date::Week { year, ww, d } => write!(f, "{:04}-{:02}-{:02}", year, ww, d),
            // like `2015-306`
            Date::Ordinal { year, ddd } => write!(f, "{:04}-{:03}", year, ddd),
        }
    }
}

impl Display for Time {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // like `16:43:16.123+00:00`
        write!(
            f,
            "{:02}:{:02}:{:02}.{}+{:02}:{:02}",
            self.hour,
            self.minute,
            self.second,
            self.millisecond,
            self.tz_offset_hours,
            self.tz_offset_hours
        )
    }
}

impl Display for DateTime {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // like `16:43:16.123+00:00`
        write!(f, "{}T{}", self.date, self.time)
    }
}

impl Display for Duration {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // P1Y2M3DT4H5M6S
        match self {
            Duration::YMDHMS {
                year,
                month,
                day,
                hour,
                minute,
                second,
                millisecond,
            } => {
                if self.is_zero() {
                    write!(f, "P0D")?;
                    return Ok(());
                }

                write!(f, "P")?;

                if *year > 0 {
                    write!(f, "{}Y", year)?
                }

                if *month > 0 {
                    write!(f, "{}M", month)?
                }

                if *day > 0 {
                    write!(f, "{}D", day)?
                }

                if *hour > 0 || *minute > 0 || *second > 0 || *millisecond > 0 {
                    write!(f, "T")?
                }
                if *hour > 0 {
                    write!(f, "{}H", hour)?
                }
                if *minute > 0 {
                    write!(f, "{}M", minute)?
                }

                if *millisecond > 0 {
                    write!(f, "{}.{}S", second, millisecond)?
                } else if *second > 0 {
                    write!(f, "{}S", second)?
                }
                Ok(())
            }
            Duration::Weeks(w) => write!(f, "P{}W", w),
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::parsers::parse_duration;

    use super::*;

    fn test_duration_reparse(duration: Duration) {
        let serialized = format!("{}", duration);
        let reparsed = parse_duration(serialized.as_bytes()).unwrap().1;
        assert_eq!(duration, reparsed);
    }

    #[test]
    fn display_duration_0() {
        let duration = Duration::YMDHMS {
            year: 2021,
            month: 11,
            day: 16,
            hour: 23,
            minute: 26,
            second: 59,
            millisecond: 0,
        };
        test_duration_reparse(duration);
    }

    #[test]
    fn display_duration_1() {
        let duration = Duration::YMDHMS {
            year: 2021,
            month: 11,
            day: 16,
            hour: 23,
            minute: 26,
            second: 59,
            millisecond: 123,
        };
        test_duration_reparse(duration);
    }

    #[test]
    fn display_duration_2() {
        let duration = Duration::Weeks(50);
        test_duration_reparse(duration);
    }
}
<commit_msg>remove dead comment<commit_after>use core::fmt::{self, Display};

use super::{Date, DateTime, Duration, Time};

impl Display for Date {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            // like `2015-11-02`
            Date::YMD { year, month, day } => write!(f, "{:04}-{:02}-{:02}", year, month, day),
            // like `2015-W45-01`
            Date::Week { year, ww, d } => write!(f, "{:04}-{:02}-{:02}", year, ww, d),
            // like `2015-306`
            Date::Ordinal { year, ddd } => write!(f, "{:04}-{:03}", year, ddd),
        }
    }
}

impl Display for Time {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // like `16:43:16.123+00:00`
        write!(
            f,
            "{:02}:{:02}:{:02}.{}+{:02}:{:02}",
            self.hour,
            self.minute,
            self.second,
            self.millisecond,
            self.tz_offset_hours,
            self.tz_offset_hours
        )
    }
}

impl Display for DateTime {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // like `16:43:16.123+00:00`
        write!(f, "{}T{}", self.date, self.time)
    }
}

impl Display for Duration {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Duration::YMDHMS {
                year,
                month,
                day,
                hour,
                minute,
                second,
                millisecond,
            } => {
                if self.is_zero() {
                    write!(f, "P0D")?;
                    return Ok(());
                }

                write!(f, "P")?;

                if *year > 0 {
                    write!(f, "{}Y", year)?
                }

                if *month > 0 {
                    write!(f, "{}M", month)?
                }

                if *day > 0 {
                    write!(f, "{}D", day)?
                }

                if *hour > 0 || *minute > 0 || *second > 0 || *millisecond > 0 {
                    write!(f, "T")?
                }
                if *hour > 0 {
                    write!(f, "{}H", hour)?
                }
                if *minute > 0 {
                    write!(f, "{}M", minute)?
                }

                if *millisecond > 0 {
                    write!(f, "{}.{}S", second, millisecond)?
                } else if *second > 0 {
                    write!(f, "{}S", second)?
                }
                Ok(())
            }
            Duration::Weeks(w) => write!(f, "P{}W", w),
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::parsers::parse_duration;

    use super::*;

    fn test_duration_reparse(duration: Duration) {
        let serialized = format!("{}", duration);
        let reparsed = parse_duration(serialized.as_bytes()).unwrap().1;
        assert_eq!(duration, reparsed);
    }

    #[test]
    fn display_duration_0() {
        let duration = Duration::YMDHMS {
            year: 2021,
            month: 11,
            day: 16,
            hour: 23,
            minute: 26,
            second: 59,
            millisecond: 0,
        };
        test_duration_reparse(duration);
    }

    #[test]
    fn display_duration_1() {
        let duration = Duration::YMDHMS {
            year: 2021,
            month: 11,
            day: 16,
            hour: 23,
            minute: 26,
            second: 59,
            millisecond: 123,
        };
        test_duration_reparse(duration);
    }

    #[test]
    fn display_duration_2() {
        let duration = Duration::Weeks(50);
        test_duration_reparse(duration);
    }
}
<|endoftext|>


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

//! Interface to System Control Block.
//  Link: http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/CIHFDJCA.html

#[path="../../util/ioreg.rs"] mod ioreg;

/// Returns the CPUID.
#[allow(dead_code)]
pub fn cpuid() -> u32 {
  reg::SCB.CPUID()
}

/// Sets the pending state of the PendSV interrupt.
pub fn set_pendsv(val: bool) {
  if val {
    reg::SCB.set_ICSR(1 << 28);
  } else {
    reg::SCB.set_ICSR(1 << 27);
  }
}

mod reg {
  use util::volatile_cell::VolatileCell;

  ioreg_old!(SCBACTLRReg: u32, ACTLR)
  reg_rw!(SCBACTLRReg, u32, ACTLR, set_ACTLR, ACTLR)

  ioreg_old!(SCBReg: u32, CPUID, ICSR, VTOR, AIRCR, SCR, CCR, SHPR1, SHPR2,
         SHPR3, SHCRS, CFSR, HFSR, _pad_0, MMAR, BFAR, AFSR)
  reg_r!( SCBReg, u32, CPUID,                    CPUID)
  reg_rw!(SCBReg, u32, ICSR,     set_ICSR,       ICSR)
  reg_rw!(SCBReg, u32, VTOR,     set_VTOR,       VTOR)
  reg_rw!(SCBReg, u32, AIRCR,    set_AIRCR,      AIRCR)
  reg_rw!(SCBReg, u32, SCR,      set_SCR,        SCR)
  reg_rw!(SCBReg, u32, CCR,      set_CCR,        CCR)
  reg_rw!(SCBReg, u32, SHPR1,    set_SHPR1,      SHPR1)
  reg_rw!(SCBReg, u32, SHPR2,    set_SHPR2,      SHPR2)
  reg_rw!(SCBReg, u32, SHPR3,    set_SHPR3,      SHPR3)
  reg_rw!(SCBReg, u32, SHCRS,    set_SHCRS,      SHCRS)
  reg_rw!(SCBReg, u32, CFSR,     set_CFSR,       CFSR)
  reg_rw!(SCBReg, u32, HFSR,     set_HFSR,       HFSR)
  reg_rw!(SCBReg, u32, MMAR,     set_MMAR,       MMAR)
  reg_rw!(SCBReg, u32, BFAR,     set_BFAR,       BFAR)
  reg_rw!(SCBReg, u32, AFSR,     set_AFSR,       AFSR)

  #[allow(dead_code)]
  extern {
    #[link_name="armmem_SCB"] pub static SCB: SCBReg;
    #[link_name="armmem_SCB_ACTLR"] pub static SCB_ACTLR: SCBACTLRReg;
  }
}
<commit_msg>scb: Port to ioregs!<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Harris <mail@bharr.is>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Interface to System Control Block.
//  Link: http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/CIHFDJCA.html

/// Returns the CPUID.
#[allow(dead_code)]
pub fn cpuid() -> reg::SCB_cpuid_Get {
  reg::SCB.cpuid.get()
}

/// Sets the pending state of the PendSV interrupt.
pub fn set_pendsv(val: bool) {
  if val {
    reg::SCB.icsr.set_pendsvset(true);
  } else {
    reg::SCB.icsr.set_pendsvclr(true);
  }
}

mod reg {
  use util::volatile_cell::VolatileCell;
  use core::ops::Drop;

  ioregs!(SCB = {
    0x0       => reg32 cpuid { //! CPUID base register
      0..3    => revision,
      4..15   => partno,
      20..23  => variant,
      24..31  => implementer,
    }
    0x4       => reg32 icsr {  //! Interrupt control and state register
      0..8    => vectactive,
      11      => rettobase,
      12..20  => vectpending,
      22      => isrpending,
      23      => isrprempt,
      25      => pendstclr,
      26      => pendstset,
      27      => pendsvclr,
      28      => pendsvset,
      31      => nmipendset,
    }
    0x8       => reg32 vtor {  //! Vector table offset register
      7..31   => tbloff,
    }
    0xc       => reg32 aircr { //! Application interrupt and reset control register
      0       => vectreset,
      1       => vectclractive,
      2       => sysresetreq,
      8..10   => prigroup,
      15      => endianness,
      16..31  => vectkey,
    }
    0x10      => reg32 scr {   //! System control register
      1       => sleeponexit,
      2       => sleepdeep,
      4       => sevonpend,
    }
    0x14      => reg32 ccr {   //! Configuration and control register
      0       => nonbasethrdena,
      1       => usersetmpend,
      3       => unalign_trp,
      4       => div_0_trp,
      8       => bfhfnmign,
      9       => stkalign,
    }
    0x18      => reg32 shpr[3] { //! System handler priority register
      0..31   => pri[4],
    }
    0x24      => reg32 shcsr { //! System handler control and state register
      0       => memfaultact,
      1       => busfaultact,
      3       => usgfaultact,
      7       => svcallact,
      8       => monitoract,
      10      => pendsvact,
      11      => systickact,
      12      => usgfaultpended,
      13      => memfaultpended,
      14      => busfaultpended,
      15      => svfaultpended,
      16      => memfaultpendena,
      17      => busfaultena,
      18      => usgfaultena,
    }
    0x28      => reg32 cfsr {  //! Configurable fault status register
      0..7    => memmanage,
      8..15   => busfault,
      16..31  => usagefault,
    }
    0x2c      => reg32 hfsr {  //! HardFault status register
      1       => vecttbl,
      30      => forced,
      31      => debugevt,
    }
    0x30      => reg32 dfsr {  //! DebugFault status register
      0       => halted,
      1       => bkpt,
      2       => dwttrap,
      3       => vcatch,
      4       => external,
    }
    0x34      => reg32 mmfar { //! MemManage address register
      0..31   => address,
    }
    0x38      => reg32 bfar {  //! BusFault address register
      0..31   => address,
    }
    0x3c      => reg32 afsr {  //! Auxilary fault address register
      0..31   => afsr,
    }
    0x88      => reg32 cpacr { //! Coprocessor access control register
      0..23   => cp[24],
    }
  })

  #[allow(dead_code)]
  extern {
    #[link_name="armmem_SCB"] pub static SCB: SCB;
  }
}
<|endoftext|>


<commit_before>use libc::c_void;
use std::ffi::CString;
use std::path::Path;

use merger;
use mtbl_sys;
use reader::{Read, Iter};

/// Options for opening an MTBL fileset.
///
/// # Examples
///
/// ```
/// FilesetOptions::new().reload_interval_seconds(10).open_from_path("/tmp/data-fileset")
/// ```
#[derive(Clone,Copy)]
pub struct FilesetOptions {
    /// How often, in seconds, to reload the fileset description file to look for new file entries.
    /// The mtbl default is 60 seconds.
    pub reload_interval_seconds: Option<u32>,
}

impl FilesetOptions {
    /// Create a `FilesetOptions` with only defaults.
    pub fn new() -> FilesetOptions {
        FilesetOptions { reload_interval_seconds: None }
    }

    /// Create a modified `FilesetOptions` with reload_interval_seconds set.
    pub fn reload_interval_seconds(self: &Self, reload_interval_seconds: u32) -> FilesetOptions {
        FilesetOptions { reload_interval_seconds: Some(reload_interval_seconds), ..*self }
    }

    /// Open a `Fileset` with these options from the specified setfile. Note that you must include
    /// a `MergeFn` to combine colliding entries that have the same key.
    pub fn open_from_path<T: AsRef<Path>>(self: &Self,
                                          setfile: T,
                                          merge_fn: Box<merger::MergeFn>)
                                          -> Fileset {
        let mut merge_fn = Box::new(merge_fn);
        unsafe {
            let mut opts = mtbl_sys::mtbl_fileset_options_init();
            mtbl_sys::mtbl_fileset_options_set_merge_func(
                // Wacky casting to get a void pointer for the C lib.
                opts, merger::_merge_cb_shim, &mut (*merge_fn) as *mut _ as *mut c_void);
            if let Some(reload_interval_seconds) = self.reload_interval_seconds {
                mtbl_sys::mtbl_fileset_options_set_reload_interval(opts, reload_interval_seconds);
            }
            let c_path = CString::new(setfile.as_ref().to_str().unwrap().as_bytes()).unwrap();
            let mtbl_fileset = mtbl_sys::mtbl_fileset_init(c_path.as_ptr(), opts);
            let fileset = Fileset {
                options: *self,
                mtbl_fileset: mtbl_fileset,
                mtbl_source: mtbl_sys::mtbl_fileset_source(mtbl_fileset),
                _merge_fn: merge_fn,
            };
            mtbl_sys::mtbl_fileset_options_destroy(&mut opts);
            fileset
        }
    }
}

/// An MTBL reader that watches a "setfile" containing a list of MTBL files to
/// read from.
///
/// It acts like a [`Merger`](type.Merger.html) that watches that setfile for
/// updates to a list of MTBL files. Note that paths in the setfile are
/// *relative* paths from the directory of the setfile.
///
/// `Fileset`s are not thread-safe because reloading, which happens
/// automatically when reading, is not thread-safe--so only one thread can read
/// from a `Fileset`.
///
/// To create a Fileset with non-default options, see
/// [FilesetOptions](struct.FilesetOptions.html).
///
/// # Examples
///
/// ```
/// $ cp my-data.mtbl /tmp/my-data.mtbl
/// $ echo 'my-data.mtbl' >> /tmp/fs.mtbl-fileset
/// ...
/// let fileset = Fileset::open_from_path("/tmp/fs.mtbl-fileset", my_merge_fn);
/// ```
pub struct Fileset {
    /// The options used to open this `Fileset`.
    pub options: FilesetOptions,
    mtbl_fileset: *mut mtbl_sys::mtbl_fileset,
    mtbl_source: *const mtbl_sys::mtbl_source,
    _merge_fn: Box<Box<merger::MergeFn>>,
}

impl Fileset {
    /// Open a `Fileset` from a path. Note that you must include a `MergeFn` to
    /// combine colliding entries (entries that have the same key).
    pub fn open_from_path<T: AsRef<Path>>(setfile: T, merge_fn: Box<merger::MergeFn>) -> Fileset {
        FilesetOptions::new().open_from_path(setfile, merge_fn)
    }

    /// Reload the list of MTBL files (ignored if less than the configured reload
    /// interval has passed).
    pub fn reload(&mut self) {
        unsafe {
            mtbl_sys::mtbl_fileset_reload(self.mtbl_fileset);
        }
    }
}

impl Read for Fileset {
    fn raw_mtbl_source(&self) -> &*const mtbl_sys::mtbl_source {
        &self.mtbl_source
    }
}

impl<'a> IntoIterator for &'a Fileset {
    type Item = (Vec<u8>, Vec<u8>);
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

// TODO: Implement IntoIterator for Fileset? I'm not sure how to cleanly do the needed lifetime
// stuff, though.

impl Drop for Fileset {
    fn drop(&mut self) {
        unsafe {
            mtbl_sys::mtbl_fileset_destroy(&mut self.mtbl_fileset);
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate tempfile;
    use self::tempfile::NamedTempFile;
    use std::io::Write;

    use fileset::FilesetOptions;
    use reader::Read;
    use writer;
    use writer::Write as iWrite;

    #[test]
    fn test_fileset() {
        let f1 = NamedTempFile::new().unwrap();
        {
            let mut writer = writer::Writer::create_from_path(f1.path()).unwrap();
            writer.add("one", "Hello").unwrap();
            writer.add("two", "world").unwrap();
        }
        let f2 = NamedTempFile::new().unwrap();
        {
            let mut writer = writer::Writer::create_from_path(f2.path()).unwrap();
            writer.add("one", "blue").unwrap();
            writer.add("three", "green").unwrap();
        }
        let mut fileset_f = NamedTempFile::new().unwrap();
        write!(fileset_f,
               "{}\n",
               f1.path().file_name().unwrap().to_str().unwrap())
            .unwrap();
        write!(fileset_f,
               "{}\n",
               f2.path().file_name().unwrap().to_str().unwrap())
            .unwrap();
        fileset_f.sync_all().unwrap();
        let fileset = FilesetOptions::new()
                          .reload_interval_seconds(50)
                          .open_from_path(fileset_f.path(),
                                          Box::new(|_key, _val0, _val1| "wat".as_bytes().to_vec()));
        assert_eq!(fileset.get("a"), None);
        // "one" collides
        assert_eq!(fileset.get("one"), Some("wat".as_bytes().to_vec()));
        assert_eq!(fileset.get("two"), Some("world".as_bytes().to_vec()));
        assert_eq!(fileset.get("three"), Some("green".as_bytes().to_vec()));
        // Iter
        for (k, v) in &fileset {
            println!("{} {}", k.len(), v.len());
        }
    }
}
<commit_msg>Fix quotes so cargo doc works<commit_after>use libc::c_void;
use std::ffi::CString;
use std::path::Path;

use merger;
use mtbl_sys;
use reader::{Read, Iter};

/// Options for opening an MTBL fileset.
///
/// # Examples
///
/// ```
/// FilesetOptions::new().reload_interval_seconds(10).open_from_path("/tmp/data-fileset")
/// ```
#[derive(Clone,Copy)]
pub struct FilesetOptions {
    /// How often, in seconds, to reload the fileset description file to look for new file entries.
    /// The mtbl default is 60 seconds.
    pub reload_interval_seconds: Option<u32>,
}

impl FilesetOptions {
    /// Create a `FilesetOptions` with only defaults.
    pub fn new() -> FilesetOptions {
        FilesetOptions { reload_interval_seconds: None }
    }

    /// Create a modified `FilesetOptions` with reload_interval_seconds set.
    pub fn reload_interval_seconds(self: &Self, reload_interval_seconds: u32) -> FilesetOptions {
        FilesetOptions { reload_interval_seconds: Some(reload_interval_seconds), ..*self }
    }

    /// Open a `Fileset` with these options from the specified setfile. Note that you must include
    /// a `MergeFn` to combine colliding entries that have the same key.
    pub fn open_from_path<T: AsRef<Path>>(self: &Self,
                                          setfile: T,
                                          merge_fn: Box<merger::MergeFn>)
                                          -> Fileset {
        let mut merge_fn = Box::new(merge_fn);
        unsafe {
            let mut opts = mtbl_sys::mtbl_fileset_options_init();
            mtbl_sys::mtbl_fileset_options_set_merge_func(
                // Wacky casting to get a void pointer for the C lib.
                opts, merger::_merge_cb_shim, &mut (*merge_fn) as *mut _ as *mut c_void);
            if let Some(reload_interval_seconds) = self.reload_interval_seconds {
                mtbl_sys::mtbl_fileset_options_set_reload_interval(opts, reload_interval_seconds);
            }
            let c_path = CString::new(setfile.as_ref().to_str().unwrap().as_bytes()).unwrap();
            let mtbl_fileset = mtbl_sys::mtbl_fileset_init(c_path.as_ptr(), opts);
            let fileset = Fileset {
                options: *self,
                mtbl_fileset: mtbl_fileset,
                mtbl_source: mtbl_sys::mtbl_fileset_source(mtbl_fileset),
                _merge_fn: merge_fn,
            };
            mtbl_sys::mtbl_fileset_options_destroy(&mut opts);
            fileset
        }
    }
}

/// An MTBL reader that watches a "setfile" containing a list of MTBL files to
/// read from.
///
/// It acts like a [`Merger`](type.Merger.html) that watches that setfile for
/// updates to a list of MTBL files. Note that paths in the setfile are
/// *relative* paths from the directory of the setfile.
///
/// `Fileset`s are not thread-safe because reloading, which happens
/// automatically when reading, is not thread-safe--so only one thread can read
/// from a `Fileset`.
///
/// To create a Fileset with non-default options, see
/// [FilesetOptions](struct.FilesetOptions.html).
///
/// # Examples
///
/// ```
/// $ cp my-data.mtbl /tmp/my-data.mtbl
/// $ echo "my-data.mtbl" >> /tmp/fs.mtbl-fileset
/// ...
/// let fileset = Fileset::open_from_path("/tmp/fs.mtbl-fileset", my_merge_fn);
/// ```
pub struct Fileset {
    /// The options used to open this `Fileset`.
    pub options: FilesetOptions,
    mtbl_fileset: *mut mtbl_sys::mtbl_fileset,
    mtbl_source: *const mtbl_sys::mtbl_source,
    _merge_fn: Box<Box<merger::MergeFn>>,
}

impl Fileset {
    /// Open a `Fileset` from a path. Note that you must include a `MergeFn` to
    /// combine colliding entries (entries that have the same key).
    pub fn open_from_path<T: AsRef<Path>>(setfile: T, merge_fn: Box<merger::MergeFn>) -> Fileset {
        FilesetOptions::new().open_from_path(setfile, merge_fn)
    }

    /// Reload the list of MTBL files (ignored if less than the configured reload
    /// interval has passed).
    pub fn reload(&mut self) {
        unsafe {
            mtbl_sys::mtbl_fileset_reload(self.mtbl_fileset);
        }
    }
}

impl Read for Fileset {
    fn raw_mtbl_source(&self) -> &*const mtbl_sys::mtbl_source {
        &self.mtbl_source
    }
}

impl<'a> IntoIterator for &'a Fileset {
    type Item = (Vec<u8>, Vec<u8>);
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

// TODO: Implement IntoIterator for Fileset? I'm not sure how to cleanly do the needed lifetime
// stuff, though.

impl Drop for Fileset {
    fn drop(&mut self) {
        unsafe {
            mtbl_sys::mtbl_fileset_destroy(&mut self.mtbl_fileset);
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate tempfile;
    use self::tempfile::NamedTempFile;
    use std::io::Write;

    use fileset::FilesetOptions;
    use reader::Read;
    use writer;
    use writer::Write as iWrite;

    #[test]
    fn test_fileset() {
        let f1 = NamedTempFile::new().unwrap();
        {
            let mut writer = writer::Writer::create_from_path(f1.path()).unwrap();
            writer.add("one", "Hello").unwrap();
            writer.add("two", "world").unwrap();
        }
        let f2 = NamedTempFile::new().unwrap();
        {
            let mut writer = writer::Writer::create_from_path(f2.path()).unwrap();
            writer.add("one", "blue").unwrap();
            writer.add("three", "green").unwrap();
        }
        let mut fileset_f = NamedTempFile::new().unwrap();
        write!(fileset_f,
               "{}\n",
               f1.path().file_name().unwrap().to_str().unwrap())
            .unwrap();
        write!(fileset_f,
               "{}\n",
               f2.path().file_name().unwrap().to_str().unwrap())
            .unwrap();
        fileset_f.sync_all().unwrap();
        let fileset = FilesetOptions::new()
                          .reload_interval_seconds(50)
                          .open_from_path(fileset_f.path(),
                                          Box::new(|_key, _val0, _val1| "wat".as_bytes().to_vec()));
        assert_eq!(fileset.get("a"), None);
        // "one" collides
        assert_eq!(fileset.get("one"), Some("wat".as_bytes().to_vec()));
        assert_eq!(fileset.get("two"), Some("world".as_bytes().to_vec()));
        assert_eq!(fileset.get("three"), Some("green".as_bytes().to_vec()));
        // Iter
        for (k, v) in &fileset {
            println!("{} {}", k.len(), v.len());
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use std::sync::Arc;

use libfuzzer_sys::arbitrary::{Arbitrary, Error, Unstructured};

use crate::prelude::*;

// Adding new fuzz targets
//
// 1. Add a function to this file which looks like this:
//
//    pub fn fuzz_something(data: Data) {
//      // Invoke everything you need.
//      //
//      // Your function may accept a value of any type that implements
//      // Arbitrary [1]. This is how fuzzer affects the execution—by
//      // feeding in different bytes, which result in different
//      // arbitrary values being generated.
//      // [1]: https://docs.rs/arbitrary/0.3.3/arbitrary/trait.Arbitrary.html
//      //
//      // Derive Debug for the structures you create with arbitrary data.
//    }
//
// 2. cargo fuzz add something
// 3. Copy the contents of any other .rs file from fuzz/fuzz_targets/ into the
//    newly created fuzz/fuzz_targets/something.rs and change the function
//    being called to fuzz_something.
//
// Now you can fuzz the new target with cargo fuzz.

#[derive(Debug)]
pub struct ArbitraryConfig {
  config: Config,
}

impl Arbitrary for ArbitraryConfig {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut config = Config::default();
    config.threads = 1;
    config.enc.width = Arbitrary::arbitrary(u)?;
    config.enc.height = Arbitrary::arbitrary(u)?;
    config.enc.bit_depth = u.int_in_range(0..=16)?;
    config.enc.still_picture = Arbitrary::arbitrary(u)?;
    config.enc.time_base =
      Rational::new(Arbitrary::arbitrary(u)?, Arbitrary::arbitrary(u)?);
    config.enc.min_key_frame_interval = Arbitrary::arbitrary(u)?;
    config.enc.max_key_frame_interval = Arbitrary::arbitrary(u)?;
    config.enc.reservoir_frame_delay = Arbitrary::arbitrary(u)?;
    config.enc.low_latency = Arbitrary::arbitrary(u)?;
    config.enc.quantizer = Arbitrary::arbitrary(u)?;
    config.enc.min_quantizer = Arbitrary::arbitrary(u)?;
    config.enc.bitrate = Arbitrary::arbitrary(u)?;
    config.enc.tile_cols = Arbitrary::arbitrary(u)?;
    config.enc.tile_rows = Arbitrary::arbitrary(u)?;
    config.enc.tiles = Arbitrary::arbitrary(u)?;
    config.enc.rdo_lookahead_frames = Arbitrary::arbitrary(u)?;
    config.enc.speed_settings =
      SpeedSettings::from_preset(Arbitrary::arbitrary(u)?);
    Ok(Self { config })
  }
}

pub fn fuzz_construct_context(arbitrary: ArbitraryConfig) {
  let _: Result<Context<u16>, _> = arbitrary.config.new_context();
}

fn encode_frames(
  ctx: &mut Context<u8>, mut frames: impl Iterator<Item = Frame<u8>>,
) -> Result<(), EncoderStatus> {
  loop {
    let rv = ctx.receive_packet();
    debug!("ctx.receive_packet() = {:#?}", rv);

    match rv {
      Ok(_packet) => {}
      Err(EncoderStatus::Encoded) => {}
      Err(EncoderStatus::LimitReached) => {
        break;
      }
      Err(EncoderStatus::NeedMoreData) => {
        ctx.send_frame(frames.next().map(Arc::new))?;
      }
      Err(EncoderStatus::EnoughData) => {
        unreachable!();
      }
      Err(EncoderStatus::NotReady) => {
        unreachable!();
      }
      Err(EncoderStatus::Failure) => {
        return Err(EncoderStatus::Failure);
      }
    }
  }

  Ok(())
}

#[derive(Debug)]
pub struct ArbitraryEncoder {
  config: Config,
  frame_count: u8,
  pixels: Box<[u8]>,
}

impl Arbitrary for ArbitraryEncoder {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut config = Config::default();
    config.threads = 1;
    config.enc.width = u.int_in_range(1..=256)?;
    config.enc.height = u.int_in_range(1..=256)?;
    config.enc.still_picture = Arbitrary::arbitrary(u)?;
    config.enc.time_base =
      Rational::new(Arbitrary::arbitrary(u)?, Arbitrary::arbitrary(u)?);
    config.enc.min_key_frame_interval = u.int_in_range(0..=3)?;
    config.enc.max_key_frame_interval = u.int_in_range(1..=4)?;
    config.enc.low_latency = Arbitrary::arbitrary(u)?;
    config.enc.quantizer = Arbitrary::arbitrary(u)?;
    config.enc.min_quantizer = Arbitrary::arbitrary(u)?;
    config.enc.bitrate = Arbitrary::arbitrary(u)?;
    // config.enc.tile_cols = Arbitrary::arbitrary(u)?;
    // config.enc.tile_rows = Arbitrary::arbitrary(u)?;
    // config.enc.tiles = Arbitrary::arbitrary(u)?;
    config.enc.rdo_lookahead_frames = Arbitrary::arbitrary(u)?;
    config.enc.speed_settings = SpeedSettings::from_preset(10);
    let frame_count = u.int_in_range(1..=3)?;
    if u.is_empty() {
      return Err(Error::NotEnoughData);
    }
    let pixels = u.get_bytes(u.len())?.to_vec().into_boxed_slice();
    Ok(Self { config, frame_count, pixels })
  }
}

pub fn fuzz_encode(arbitrary: ArbitraryEncoder) {
  let res = arbitrary.config.new_context();
  if res.is_err() {
    return;
  }
  let mut context: Context<u8> = res.unwrap();

  let mut pixels = arbitrary.pixels.iter().cycle();
  let mut frame = context.new_frame();
  let frames = (0..arbitrary.frame_count).map(|_| {
    for plane in &mut frame.planes {
      let stride = plane.cfg.stride;
      for row in plane.data_origin_mut().chunks_mut(stride) {
        for pixel in row {
          *pixel = *pixels.next().unwrap();
        }
      }
    }

    frame.clone()
  });

  let _ = encode_frames(&mut context, frames);
}

#[derive(Debug)]
pub struct DecodeTestParameters {
  w: usize,
  h: usize,
  speed: usize,
  q: usize,
  limit: usize,
  bit_depth: usize,
  chroma_sampling: ChromaSampling,
  min_keyint: u64,
  max_keyint: u64,
  switch_frame_interval: u64,
  low_latency: bool,
  error_resilient: bool,
  bitrate: i32,
  tile_cols_log2: usize,
  tile_rows_log2: usize,
  still_picture: bool,
}

impl Arbitrary for DecodeTestParameters {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    Ok(Self {
      w: u.int_in_range(16..=16 + 255)?,
      h: u.int_in_range(16..=16 + 255)?,
      speed: 10,
      q: u8::arbitrary(u)?.into(),
      limit: u.int_in_range(1..=3)?,
      bit_depth: 8,
      chroma_sampling: Default::default(),
      min_keyint: u.int_in_range(0..=3)?,
      max_keyint: u.int_in_range(1..=4)?,
      switch_frame_interval: 0,
      low_latency: bool::arbitrary(u)?,
      error_resilient: false,
      bitrate: i32::arbitrary(u)?,
      tile_cols_log2: 1,
      tile_rows_log2: 1,
      still_picture: false,
    })
  }
}

#[cfg(feature = "decode_test_dav1d")]
pub fn fuzz_encode_decode(p: DecodeTestParameters) {
  use crate::test_encode_decode::*;

  let mut dec = get_decoder::<u8>("dav1d", p.w, p.h);
  dec.encode_decode(
    p.w,
    p.h,
    p.speed,
    p.q,
    p.limit,
    p.bit_depth,
    p.chroma_sampling,
    p.min_keyint,
    p.max_keyint,
    p.switch_frame_interval,
    p.low_latency,
    p.error_resilient,
    p.bitrate,
    p.tile_cols_log2,
    p.tile_rows_log2,
    p.still_picture,
  );
}
<commit_msg>fuzz: Use new API Config::with_encoder_config()<commit_after>// Copyright (c) 2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

use std::sync::Arc;

use libfuzzer_sys::arbitrary::{Arbitrary, Error, Unstructured};

use crate::prelude::*;

// Adding new fuzz targets
//
// 1. Add a function to this file which looks like this:
//
//    pub fn fuzz_something(data: Data) {
//      // Invoke everything you need.
//      //
//      // Your function may accept a value of any type that implements
//      // Arbitrary [1]. This is how fuzzer affects the execution—by
//      // feeding in different bytes, which result in different
//      // arbitrary values being generated.
//      // [1]: https://docs.rs/arbitrary/0.3.3/arbitrary/trait.Arbitrary.html
//      //
//      // Derive Debug for the structures you create with arbitrary data.
//    }
//
// 2. cargo fuzz add something
// 3. Copy the contents of any other .rs file from fuzz/fuzz_targets/ into the
//    newly created fuzz/fuzz_targets/something.rs and change the function
//    being called to fuzz_something.
//
// Now you can fuzz the new target with cargo fuzz.

#[derive(Debug)]
pub struct ArbitraryConfig {
  config: Config,
}

impl Arbitrary for ArbitraryConfig {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut enc = EncoderConfig::with_speed_preset(Arbitrary::arbitrary(u)?);
    enc.width = Arbitrary::arbitrary(u)?;
    enc.height = Arbitrary::arbitrary(u)?;
    enc.bit_depth = u.int_in_range(0..=16)?;
    enc.still_picture = Arbitrary::arbitrary(u)?;
    enc.time_base =
      Rational::new(Arbitrary::arbitrary(u)?, Arbitrary::arbitrary(u)?);
    enc.min_key_frame_interval = Arbitrary::arbitrary(u)?;
    enc.max_key_frame_interval = Arbitrary::arbitrary(u)?;
    enc.reservoir_frame_delay = Arbitrary::arbitrary(u)?;
    enc.low_latency = Arbitrary::arbitrary(u)?;
    enc.quantizer = Arbitrary::arbitrary(u)?;
    enc.min_quantizer = Arbitrary::arbitrary(u)?;
    enc.bitrate = Arbitrary::arbitrary(u)?;
    enc.tile_cols = Arbitrary::arbitrary(u)?;
    enc.tile_rows = Arbitrary::arbitrary(u)?;
    enc.tiles = Arbitrary::arbitrary(u)?;
    enc.rdo_lookahead_frames = Arbitrary::arbitrary(u)?;
    let config = Config::new().with_encoder_config(enc).with_threads(1);
    Ok(Self { config })
  }
}

pub fn fuzz_construct_context(arbitrary: ArbitraryConfig) {
  let _: Result<Context<u16>, _> = arbitrary.config.new_context();
}

fn encode_frames(
  ctx: &mut Context<u8>, mut frames: impl Iterator<Item = Frame<u8>>,
) -> Result<(), EncoderStatus> {
  loop {
    let rv = ctx.receive_packet();
    debug!("ctx.receive_packet() = {:#?}", rv);

    match rv {
      Ok(_packet) => {}
      Err(EncoderStatus::Encoded) => {}
      Err(EncoderStatus::LimitReached) => {
        break;
      }
      Err(EncoderStatus::NeedMoreData) => {
        ctx.send_frame(frames.next().map(Arc::new))?;
      }
      Err(EncoderStatus::EnoughData) => {
        unreachable!();
      }
      Err(EncoderStatus::NotReady) => {
        unreachable!();
      }
      Err(EncoderStatus::Failure) => {
        return Err(EncoderStatus::Failure);
      }
    }
  }

  Ok(())
}

#[derive(Debug)]
pub struct ArbitraryEncoder {
  config: Config,
  frame_count: u8,
  pixels: Box<[u8]>,
}

impl Arbitrary for ArbitraryEncoder {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    let mut enc = EncoderConfig::with_speed_preset(10);
    enc.width = u.int_in_range(1..=256)?;
    enc.height = u.int_in_range(1..=256)?;
    enc.still_picture = Arbitrary::arbitrary(u)?;
    enc.time_base =
      Rational::new(Arbitrary::arbitrary(u)?, Arbitrary::arbitrary(u)?);
    enc.min_key_frame_interval = u.int_in_range(0..=3)?;
    enc.max_key_frame_interval = u.int_in_range(1..=4)?;
    enc.low_latency = Arbitrary::arbitrary(u)?;
    enc.quantizer = Arbitrary::arbitrary(u)?;
    enc.min_quantizer = Arbitrary::arbitrary(u)?;
    enc.bitrate = Arbitrary::arbitrary(u)?;
    // enc.tile_cols = Arbitrary::arbitrary(u)?;
    // enc.tile_rows = Arbitrary::arbitrary(u)?;
    // enc.tiles = Arbitrary::arbitrary(u)?;
    enc.rdo_lookahead_frames = Arbitrary::arbitrary(u)?;
    let frame_count = u.int_in_range(1..=3)?;
    if u.is_empty() {
      return Err(Error::NotEnoughData);
    }
    let pixels = u.get_bytes(u.len())?.to_vec().into_boxed_slice();
    let config = Config::new().with_encoder_config(enc).with_threads(1);
    Ok(Self { config, frame_count, pixels })
  }
}

pub fn fuzz_encode(arbitrary: ArbitraryEncoder) {
  let res = arbitrary.config.new_context();
  if res.is_err() {
    return;
  }
  let mut context: Context<u8> = res.unwrap();

  let mut pixels = arbitrary.pixels.iter().cycle();
  let mut frame = context.new_frame();
  let frames = (0..arbitrary.frame_count).map(|_| {
    for plane in &mut frame.planes {
      let stride = plane.cfg.stride;
      for row in plane.data_origin_mut().chunks_mut(stride) {
        for pixel in row {
          *pixel = *pixels.next().unwrap();
        }
      }
    }

    frame.clone()
  });

  let _ = encode_frames(&mut context, frames);
}

#[derive(Debug)]
pub struct DecodeTestParameters {
  w: usize,
  h: usize,
  speed: usize,
  q: usize,
  limit: usize,
  bit_depth: usize,
  chroma_sampling: ChromaSampling,
  min_keyint: u64,
  max_keyint: u64,
  switch_frame_interval: u64,
  low_latency: bool,
  error_resilient: bool,
  bitrate: i32,
  tile_cols_log2: usize,
  tile_rows_log2: usize,
  still_picture: bool,
}

impl Arbitrary for DecodeTestParameters {
  fn arbitrary(u: &mut Unstructured<'_>) -> Result<Self, Error> {
    Ok(Self {
      w: u.int_in_range(16..=16 + 255)?,
      h: u.int_in_range(16..=16 + 255)?,
      speed: 10,
      q: u8::arbitrary(u)?.into(),
      limit: u.int_in_range(1..=3)?,
      bit_depth: 8,
      chroma_sampling: Default::default(),
      min_keyint: u.int_in_range(0..=3)?,
      max_keyint: u.int_in_range(1..=4)?,
      switch_frame_interval: 0,
      low_latency: bool::arbitrary(u)?,
      error_resilient: false,
      bitrate: i32::arbitrary(u)?,
      tile_cols_log2: 1,
      tile_rows_log2: 1,
      still_picture: false,
    })
  }
}

#[cfg(feature = "decode_test_dav1d")]
pub fn fuzz_encode_decode(p: DecodeTestParameters) {
  use crate::test_encode_decode::*;

  let mut dec = get_decoder::<u8>("dav1d", p.w, p.h);
  dec.encode_decode(
    p.w,
    p.h,
    p.speed,
    p.q,
    p.limit,
    p.bit_depth,
    p.chroma_sampling,
    p.min_keyint,
    p.max_keyint,
    p.switch_frame_interval,
    p.low_latency,
    p.error_resilient,
    p.bitrate,
    p.tile_cols_log2,
    p.tile_rows_log2,
    p.still_picture,
  );
}
<|endoftext|>


<commit_before>use tcod;
use tcod::{BackgroundFlag, Console, Key, KeyCode};
use tcod::{KEY_PRESSED, FONT_LAYOUT_ASCII_INROW, FONT_TYPE_GREYSCALE};

use engine::Game;
use util::units::{Direction, Size};

#[deriving(PartialEq)]
pub enum State {
    Running,
    Exited
}

pub struct GUI {
    pub size: Size,
    pub console: Console,
    game: Game,
    state: State,
}

impl GUI {
    pub fn new(game: Game) -> GUI {
        let width = 100;
        let height = 50;
        let size = Size::new(width, height);

        tcod::system::set_fps(60);
        Console::set_custom_font(Path::new("/home/jonny/code/rslike/assets/fonts/terminal12x12_gs_ro.png"), FONT_LAYOUT_ASCII_INROW | FONT_TYPE_GREYSCALE, 0, 0);
        let console = Console::init_root(width as int, height as int, "Libtcod Rust Tutorial", false);

        GUI {
            game: game,
            size: size,
            console: console,
            state: State::Running,
        }
    }

    pub fn run(&mut self) {
        while !self.window_closed() && !self.exited() {
            self.render();
            self.handle_input();
        }
    }

    fn handle_input(&mut self) {
        let check_key = Console::check_for_keypress(KEY_PRESSED);

        if let Some(keypress) = check_key {
            match keypress.key {
                Key::Special(KeyCode::Up) => {
                    self.game.walk(Direction::Up);
                },
                Key::Special(KeyCode::Down) => {
                    self.game.walk(Direction::Down);
                },
                Key::Special(KeyCode::Left) => {
                    self.game.walk(Direction::Left);
                },
                Key::Special(KeyCode::Right) => {
                    self.game.walk(Direction::Right);
                },
                Key::Special(KeyCode::Escape) => {
                    self.state = State::Exited;
                },
                _ => {}
            }
        }

    }

    fn render(&mut self) {
        self.clear();

        let repr = self.game.world.player.repr;
        let pos = self.game.world.player.pos;

        self.console.put_char(pos.x, pos.y, repr, BackgroundFlag::Set);

        self.flush();
    }

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

    pub fn flush(&mut self) {
        Console::flush();
    }

    pub fn exited(&self) -> bool {
        self.state == State::Exited
    }

    pub fn window_closed(&self) -> bool {
        Console::window_closed()
    }
}
<commit_msg>Move rslike imports to the top of the file<commit_after>use engine::Game;
use util::units::{Direction, Size};

use tcod;
use tcod::{BackgroundFlag, Console, Key, KeyCode};
use tcod::{KEY_PRESSED, FONT_LAYOUT_ASCII_INROW, FONT_TYPE_GREYSCALE};

#[deriving(PartialEq)]
pub enum State {
    Running,
    Exited
}

pub struct GUI {
    pub size: Size,
    pub console: Console,
    game: Game,
    state: State,
}

impl GUI {
    pub fn new(game: Game) -> GUI {
        let width = 100;
        let height = 50;
        let size = Size::new(width, height);

        tcod::system::set_fps(60);
        Console::set_custom_font(Path::new("/home/jonny/code/rslike/assets/fonts/terminal12x12_gs_ro.png"), FONT_LAYOUT_ASCII_INROW | FONT_TYPE_GREYSCALE, 0, 0);
        let console = Console::init_root(width as int, height as int, "Libtcod Rust Tutorial", false);

        GUI {
            game: game,
            size: size,
            console: console,
            state: State::Running,
        }
    }

    pub fn run(&mut self) {
        while !self.window_closed() && !self.exited() {
            self.render();
            self.handle_input();
        }
    }

    fn handle_input(&mut self) {
        let check_key = Console::check_for_keypress(KEY_PRESSED);

        if let Some(keypress) = check_key {
            match keypress.key {
                Key::Special(KeyCode::Up) => {
                    self.game.walk(Direction::Up);
                },
                Key::Special(KeyCode::Down) => {
                    self.game.walk(Direction::Down);
                },
                Key::Special(KeyCode::Left) => {
                    self.game.walk(Direction::Left);
                },
                Key::Special(KeyCode::Right) => {
                    self.game.walk(Direction::Right);
                },
                Key::Special(KeyCode::Escape) => {
                    self.state = State::Exited;
                },
                _ => {}
            }
        }

    }

    fn render(&mut self) {
        self.clear();

        let repr = self.game.world.player.repr;
        let pos = self.game.world.player.pos;

        self.console.put_char(pos.x, pos.y, repr, BackgroundFlag::Set);

        self.flush();
    }

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

    pub fn flush(&mut self) {
        Console::flush();
    }

    pub fn exited(&self) -> bool {
        self.state == State::Exited
    }

    pub fn window_closed(&self) -> bool {
        Console::window_closed()
    }
}
<|endoftext|>


<commit_before>//use std::ops::Fn;
use std::num::Float;
use serialize::json::Json;

use render::{Renderable, RenderContext, RenderError, render_error, EMPTY};
use template::{Helper};
use registry::{Registry};
use context::{Context};

pub trait HelperDef {
    fn resolve(&self, ctx: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<String, RenderError>;
}

#[deriving(Copy)]
pub struct DummyHelper;

impl HelperDef for DummyHelper {
    fn resolve(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<String, RenderError> {
        h.template().unwrap().render(c, r, rc)
    }
}

pub static DUMMY_HELPER: DummyHelper = DummyHelper;

#[deriving(Copy)]
pub struct IfHelper;

impl HelperDef for IfHelper{
    fn resolve(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<String, RenderError> {
        let param = h.params().get(0);

        if param.is_none() {
            return Err(render_error("Param not found for helper \"if\""));
        }

        let value = c.navigate(rc.get_path(), param.unwrap());

        let bool_value:bool = match *value {
            Json::I64(i) => i != 0,
            Json::U64(i) => i != 0,
            Json::F64(i) => i != Float::zero() || ! i.is_nan(),
            Json::Boolean (ref i) => *i,
            Json::Null => false,
            Json::String (ref i) => i.len() > 0,
            Json::Array (ref i) => true,
            Json::Object (ref i) => true
        };

        print!("{}", bool_value);
        let tmpl = if bool_value { h.template() } else { h.inverse() };
        match tmpl {
            Some(ref t) => t.render(c, r, rc),
            None => Ok(EMPTY.to_string())
        }
    }
}

pub static IF_HELPER: IfHelper = IfHelper;

/*
pub type HelperDef = for <'a, 'b, 'c> Fn<(&'a Context, &'b Helper, &'b Registry, &'c mut RenderContext), Result<String, RenderError>>;

pub fn helper_dummy (ctx: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<String, RenderError> {
    h.template().unwrap().render(ctx, r, rc).unwrap()
}
*/

#[cfg(test)]
mod test {
    use template::{Template};
    use registry::{Registry};
    use helpers::{IF_HELPER};

    #[test]
    fn test_if() {
        let t0 = Template::compile("{{#if this}}hello{{/if}}".to_string()).unwrap();
        let t1 = Template::compile("{{#if this}}hello{{else}}world{{/if}}".to_string()).unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", &t0);
        handlebars.register_template("t1", &t1);
        handlebars.register_helper("if", box IF_HELPER);

        let r0 = handlebars.render("t0", &true);
        assert_eq!(r0.unwrap(), "hello".to_string());

        let r1 = handlebars.render("t1", &false);
        assert_eq!(r1.unwrap(), "world".to_string());

        let r2 = handlebars.render("t0", &false);
        assert_eq!(r2.unwrap(), "".to_string());
    }

}
<commit_msg>Added built-in helper: unless<commit_after>//use std::ops::Fn;
use std::num::Float;
use serialize::json::Json;

use render::{Renderable, RenderContext, RenderError, render_error, EMPTY};
use template::{Helper};
use registry::{Registry};
use context::{Context};

pub trait HelperDef {
    fn resolve(&self, ctx: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<String, RenderError>;
}

#[deriving(Copy)]
pub struct DummyHelper;

impl HelperDef for DummyHelper {
    fn resolve(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<String, RenderError> {
        h.template().unwrap().render(c, r, rc)
    }
}

pub static DUMMY_HELPER: DummyHelper = DummyHelper;

#[deriving(Copy)]
pub struct IfHelper {
    positive: bool
}

impl HelperDef for IfHelper{
    fn resolve(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<String, RenderError> {
        let param = h.params().get(0);

        if param.is_none() {
            return Err(render_error("Param not found for helper \"if\""));
        }

        let value = c.navigate(rc.get_path(), param.unwrap());

        let mut bool_value:bool = match *value {
            Json::I64(i) => i != 0,
            Json::U64(i) => i != 0,
            Json::F64(i) => i != Float::zero() || ! i.is_nan(),
            Json::Boolean (ref i) => *i,
            Json::Null => false,
            Json::String (ref i) => i.len() > 0,
            Json::Array (ref i) => true,
            Json::Object (ref i) => true
        };

        if !self.positive {
            bool_value = !bool_value;
        }

        let tmpl = if bool_value { h.template() } else { h.inverse() };
        match tmpl {
            Some(ref t) => t.render(c, r, rc),
            None => Ok(EMPTY.to_string())
        }
    }
}

pub static IF_HELPER: IfHelper = IfHelper { positive: true };
pub static UNLESS_HELPER: IfHelper = IfHelper { positive: false };

/*
pub type HelperDef = for <'a, 'b, 'c> Fn<(&'a Context, &'b Helper, &'b Registry, &'c mut RenderContext), Result<String, RenderError>>;

pub fn helper_dummy (ctx: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<String, RenderError> {
    h.template().unwrap().render(ctx, r, rc).unwrap()
}
*/

#[cfg(test)]
mod test {
    use template::{Template};
    use registry::{Registry};
    use helpers::{IF_HELPER, UNLESS_HELPER};

    #[test]
    fn test_if() {
        let t0 = Template::compile("{{#if this}}hello{{/if}}".to_string()).unwrap();
        let t1 = Template::compile("{{#unless this}}hello{{else}}world{{/unless}}".to_string()).unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", &t0);
        handlebars.register_template("t1", &t1);
        handlebars.register_helper("if", box IF_HELPER);
        handlebars.register_helper("unless", box UNLESS_HELPER);

        let r0 = handlebars.render("t0", &true);
        assert_eq!(r0.unwrap(), "hello".to_string());

        let r1 = handlebars.render("t1", &true);
        assert_eq!(r1.unwrap(), "world".to_string());

        let r2 = handlebars.render("t0", &false);
        assert_eq!(r2.unwrap(), "".to_string());
    }

}
<|endoftext|>


<commit_before>use ffi;
use std::{mem, raw};
use libc::{c_short, c_char};

pub use ffi::FT_Vector as Vector;

pub enum Curve<'a> {
    Line(Vector),
    Bezier2(Vector, Vector),
    Bezier3(Vector, Vector, Vector),
}

pub struct Outline<'a> {
    raw: &'a ffi::FT_Outline,
}

impl<'a> Outline<'a> {
    pub unsafe fn from_raw(raw: &'a ffi::FT_Outline) -> Outline<'a> {
        Outline { raw: raw }
    }

    pub fn points(&self) -> &'a [Vector] {
        unsafe { mem::transmute(raw::Slice { data: self.raw.points, len: self.raw.n_points as uint }) }
    }

    pub fn tags(&self) -> &'a [c_char] {
        unsafe { mem::transmute(raw::Slice { data: self.raw.tags, len: self.raw.n_points as uint }) }
    }

    pub fn contours(&self) -> &'a [c_short] {
        unsafe { mem::transmute(raw::Slice { data: self.raw.contours, len: self.raw.n_contours as uint }) }
    }

    pub fn contours_iter(&self) -> ContourIterator<'a> {
        unsafe { ContourIterator::from_raw(self.raw) }
    }
}

const TAG_ONCURVE: c_char = 0x01;
const TAG_BEZIER3: c_char = 0x02;

pub struct CurveIterator<'a> {
    start_point: *const Vector,
    start_tag: *const c_char,
    idx: int,
    length: int,
}

impl<'a> CurveIterator<'a> {
    pub unsafe fn from_raw<'a>(outline: &'a ffi::FT_Outline,
                               start_idx: int,
                               end_idx: int) -> CurveIterator<'a> {
        CurveIterator {
            start_point: outline.points.offset(start_idx),
            start_tag: outline.tags.offset(start_idx),
            idx: 0,
            length: end_idx - start_idx + 1,
        }
    }

    pub fn start(&self) -> &'a Vector {
        unsafe { mem::transmute(self.start_point) }
    }

    // Retrieves the point at offset i from the current point. Note that contours implicitly repeat their
    // first point at the end.
    unsafe fn pt(&self, i: int) -> Vector {
        if self.idx + i < self.length {
            *self.start_point.offset(self.idx + i)
        } else {
            *self.start_point
        }
    }

    unsafe fn tg(&self, i: int) -> c_char {
        if self.idx + i < self.length {
            *self.start_tag.offset(self.idx + i)
        } else {
            *self.start_tag
        }
    }
}

impl<'a> Iterator<Curve<'a>> for CurveIterator<'a> {
    fn next(&mut self) -> Option<Curve<'a>> {
        if self.idx >= self.length {
            None
        } else {
            unsafe {
                let tag1 = self.tg(1);

                let (shift, curve) = if (tag1 & TAG_ONCURVE) == TAG_ONCURVE {
                    (1, Curve::Line(self.pt(1)))
                } else if (tag1 & TAG_BEZIER3) == TAG_BEZIER3 {
                    (3, Curve::Bezier3(self.pt(1), self.pt(2), self.pt(3)))
                } else {
                    // We are some kind of quadratic Bezier.
                    // Quadratic Bezier curves have a special treatment in TTF outlines:
                    // as an optimization, curves are often constructed from sequences
                    // of off-curve control points. In this case, there are implied on-curve
                    // points in between each pair of off-curve points.
                    if (self.tg(2) & TAG_ONCURVE) == TAG_ONCURVE {
                        (2, Curve::Bezier2(self.pt(1), self.pt(2)))
                    } else {
                        (1, Curve::Bezier2(self.pt(1), (self.pt(1) + self.pt(2))/2))
                    }
                };

                self.idx += shift;
                Some(curve)
            }
        }
    }
}

pub struct ContourIterator<'a> {
    outline: &'a ffi::FT_Outline,
    contour_start: c_short,
    contour_end_idx: *const c_short,
    last_end_idx: *const c_short,
}

impl<'a> ContourIterator<'a> {
    pub unsafe fn from_raw<'a>(outline: &'a ffi::FT_Outline) -> ContourIterator<'a> {
        ContourIterator {
            outline: outline,
            contour_start: 0,
            contour_end_idx: outline.contours,
            last_end_idx: outline.contours.offset(outline.n_contours as int - 1),
        }
    }
}

impl<'a> Iterator<CurveIterator<'a>> for ContourIterator<'a> {
    fn next(&mut self) -> Option<CurveIterator<'a>> {
        if self.contour_end_idx > self.last_end_idx {
            None
        } else {
            unsafe {
                let contour_end = *self.contour_end_idx;
                let curves = CurveIterator::from_raw(self.outline, self.contour_start as int, contour_end as int);

                self.contour_start = contour_end + 1;
                self.contour_end_idx = self.contour_end_idx.offset(1);

                Some(curves)
            }
        }
    }
}

<commit_msg>Update for traits removal in freetype-sys<commit_after>use ffi;
use std::{mem, raw};
use libc::{c_short, c_char};

pub use ffi::FT_Vector as Vector;

pub enum Curve<'a> {
    Line(Vector),
    Bezier2(Vector, Vector),
    Bezier3(Vector, Vector, Vector),
}

pub struct Outline<'a> {
    raw: &'a ffi::FT_Outline,
}

impl<'a> Outline<'a> {
    pub unsafe fn from_raw(raw: &'a ffi::FT_Outline) -> Outline<'a> {
        Outline { raw: raw }
    }

    pub fn points(&self) -> &'a [Vector] {
        unsafe { mem::transmute(raw::Slice { data: self.raw.points, len: self.raw.n_points as uint }) }
    }

    pub fn tags(&self) -> &'a [c_char] {
        unsafe { mem::transmute(raw::Slice { data: self.raw.tags, len: self.raw.n_points as uint }) }
    }

    pub fn contours(&self) -> &'a [c_short] {
        unsafe { mem::transmute(raw::Slice { data: self.raw.contours, len: self.raw.n_contours as uint }) }
    }

    pub fn contours_iter(&self) -> ContourIterator<'a> {
        unsafe { ContourIterator::from_raw(self.raw) }
    }
}

const TAG_ONCURVE: c_char = 0x01;
const TAG_BEZIER3: c_char = 0x02;

pub struct CurveIterator<'a> {
    start_point: *const Vector,
    start_tag: *const c_char,
    idx: int,
    length: int,
}

impl<'a> CurveIterator<'a> {
    pub unsafe fn from_raw<'a>(outline: &'a ffi::FT_Outline,
                               start_idx: int,
                               end_idx: int) -> CurveIterator<'a> {
        CurveIterator {
            start_point: outline.points.offset(start_idx),
            start_tag: outline.tags.offset(start_idx),
            idx: 0,
            length: end_idx - start_idx + 1,
        }
    }

    pub fn start(&self) -> &'a Vector {
        unsafe { mem::transmute(self.start_point) }
    }

    // Retrieves the point at offset i from the current point. Note that contours implicitly repeat their
    // first point at the end.
    unsafe fn pt(&self, i: int) -> Vector {
        if self.idx + i < self.length {
            *self.start_point.offset(self.idx + i)
        } else {
            *self.start_point
        }
    }

    unsafe fn tg(&self, i: int) -> c_char {
        if self.idx + i < self.length {
            *self.start_tag.offset(self.idx + i)
        } else {
            *self.start_tag
        }
    }
}

impl<'a> Iterator<Curve<'a>> for CurveIterator<'a> {
    fn next(&mut self) -> Option<Curve<'a>> {
        if self.idx >= self.length {
            None
        } else {
            unsafe {
                let tag1 = self.tg(1);

                let (shift, curve) = if (tag1 & TAG_ONCURVE) == TAG_ONCURVE {
                    (1, Curve::Line(self.pt(1)))
                } else if (tag1 & TAG_BEZIER3) == TAG_BEZIER3 {
                    (3, Curve::Bezier3(self.pt(1), self.pt(2), self.pt(3)))
                } else {
                    // We are some kind of quadratic Bezier.
                    // Quadratic Bezier curves have a special treatment in TTF outlines:
                    // as an optimization, curves are often constructed from sequences
                    // of off-curve control points. In this case, there are implied on-curve
                    // points in between each pair of off-curve points.
                    if (self.tg(2) & TAG_ONCURVE) == TAG_ONCURVE {
                        (2, Curve::Bezier2(self.pt(1), self.pt(2)))
                    } else {
                        let pt = ffi::FT_Vector {
                            x: (self.pt(1).x + self.pt(2).x) / 2,
                            y: (self.pt(1).y + self.pt(2).y) / 2,
                        };

                        (1, Curve::Bezier2(self.pt(1), pt))
                    }
                };

                self.idx += shift;
                Some(curve)
            }
        }
    }
}

pub struct ContourIterator<'a> {
    outline: &'a ffi::FT_Outline,
    contour_start: c_short,
    contour_end_idx: *const c_short,
    last_end_idx: *const c_short,
}

impl<'a> ContourIterator<'a> {
    pub unsafe fn from_raw<'a>(outline: &'a ffi::FT_Outline) -> ContourIterator<'a> {
        ContourIterator {
            outline: outline,
            contour_start: 0,
            contour_end_idx: outline.contours,
            last_end_idx: outline.contours.offset(outline.n_contours as int - 1),
        }
    }
}

impl<'a> Iterator<CurveIterator<'a>> for ContourIterator<'a> {
    fn next(&mut self) -> Option<CurveIterator<'a>> {
        if self.contour_end_idx > self.last_end_idx {
            None
        } else {
            unsafe {
                let contour_end = *self.contour_end_idx;
                let curves = CurveIterator::from_raw(self.outline, self.contour_start as int, contour_end as int);

                self.contour_start = contour_end + 1;
                self.contour_end_idx = self.contour_end_idx.offset(1);

                Some(curves)
            }
        }
    }
}

<|endoftext|>


<commit_before>use luminance::{Dim2, Equation, Factor, Flat, Framebuffer, Mode, Pipe, Pipeline, RenderCommand, ShadingCommand, Tess, TessRender, TessVertices, Uniform, Unit, Vertex, VertexFormat};

use resource::Res;
use scene::Scene;
use shader::Program;
use text::TextTexture;
use texture::{RGBA32F, Texture};

/// Vertex used in overlay’s objects.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Vert {
  /// Position.
  pub pos: [f32; 3],
  /// Color.
  pub color: [f32; 4]
}

impl Vert {
  pub fn new(pos: [f32; 3], color: [f32; 4]) -> Self {
    Vert {
      pos: pos,
      color: color
    }
  }
}

impl Vertex for Vert {
  fn vertex_format() -> VertexFormat {
    <([f32; 3], [f32; 4]) as Vertex>::vertex_format()
  }
}

pub struct Triangle(pub Vert, pub Vert, pub Vert);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Disc {
  center: Vert,
  radius: f32
}

impl Disc {
  pub fn new(center: Vert, radius: f32) -> Self {
    Disc {
      center: center,
      radius: radius
    }
  }
}

impl Vertex for Disc {
  fn vertex_format() -> VertexFormat {
    <(Vert, f32) as Vertex>::vertex_format()
  }
}

pub type Texture2D = Texture<Flat, Dim2, RGBA32F>;

pub struct Text<'a> {
  text_texture: &'a TextTexture,
  left_upper: Vert
}

impl<'a> Text<'a> {
  pub fn new(text_texture: &'a TextTexture, left_upper: Vert) -> Self {
    Text {
      text_texture: text_texture,
      left_upper: left_upper
    }
  }
}

const DISC_SCREEN_RATIO: &'static Uniform<f32> = &Uniform::new(0);

const TEXT_SAMPLER: &'static Uniform<Unit> = &Uniform::new(0);
const TEXT_POS: &'static Uniform<[f32; 3]> = &Uniform::new(1);
const TEXT_SIZE: &'static Uniform<[f32; 2]> = &Uniform::new(2);
const TEXT_SCALE: &'static Uniform<f32> = &Uniform::new(3);
const TEXT_COLOR: &'static Uniform<[f32; 4]> = &Uniform::new(4);

/// A renderer responsible of rendering shapes.
pub struct Renderer {
  framebuffer: Framebuffer<Flat, Dim2, Texture2D, ()>,
  ratio: f32,
  tri_program: Res<Program>,
  tris: Tess,
  tri_vert_nb: usize,
  disc_program: Res<Program>,
  discs: Tess,
  disc_vert_nb: usize,
  text_program: Res<Program>,
  text_quad: Tess,
  overlay_unit: OverlayUnit,
}

impl Renderer {
  pub fn new(w: u32, h: u32, max_tris: usize, max_discs: usize, scene: &mut Scene) -> Self {
    let fb = Framebuffer::new((w, h), 0).unwrap();

    let tri_program = scene.get("spectra/overlay/triangle.glsl", vec![]).unwrap();
    let tris = Tess::new(Mode::Triangle, TessVertices::Reserve::<Vert>(max_tris * 3), None);

    let disc_program = scene.get("spectra/overlay/disc.glsl", vec![DISC_SCREEN_RATIO.sem("ratio")]).unwrap();
    let discs = Tess::new(Mode::Point, TessVertices::Reserve::<Disc>(max_discs), None);

    let text_program = scene.get("spectra/overlay/text.glsl", vec![
      TEXT_SAMPLER.sem("text_texture"),
      TEXT_POS.sem("pos"),
      TEXT_SIZE.sem("size"),
      TEXT_SCALE.sem("scale"),
      TEXT_COLOR.sem("color")
    ]).unwrap();

    let text_quad = Tess::attributeless(Mode::TriangleStrip, 4);

    Renderer {
      framebuffer: fb,
      ratio: w as f32 / h as f32,
      tri_program: tri_program,
      tris: tris,
      tri_vert_nb: 0,
      disc_program: disc_program,
      discs: discs,
      disc_vert_nb: 0,
      text_program: text_program,
      text_quad: text_quad,
      overlay_unit: OverlayUnit::new(w, h)
    }
  }

  fn dispatch(&mut self, input: &RenderInput) {
    let mut tris = self.tris.as_slice_mut().unwrap();
    let mut tri_i = 0;
    let mut discs = self.discs.as_slice_mut().unwrap();
    let mut disc_i = 0;

    for &Triangle(a, b, c) in input.triangles {
      tris[tri_i] = a;
      tri_i += 1;

      tris[tri_i] = b;
      tri_i += 1;

      tris[tri_i] = c;
      tri_i += 1;
    }

    for disc in input.discs {
      discs[disc_i] = *disc;
      disc_i += 1;
    }

    self.tri_vert_nb = tri_i;
    self.disc_vert_nb = disc_i;
  }

  pub fn render(&mut self, input: RenderInput) -> &Texture2D {
    self.dispatch(&input);

    let tris = TessRender::one_sub(&self.tris, self.tri_vert_nb);
    let discs = TessRender::one_sub(&self.discs, self.disc_vert_nb);
    let text_quad = TessRender::one_whole(&self.text_quad);

    // FIXME: no alloc?
    let text_uniforms: Vec<_> = input.texts.map(|(texts, text_scale)| texts.iter().map(|text| {
      let (tex_w, tex_h) = text.text_texture.size();

      [
        TEXT_SAMPLER.alter(Unit::new(0)),
        TEXT_POS.alter(text.left_upper.pos),
        TEXT_SIZE.alter(self.overlay_unit.from_window(tex_w, tex_h)),
        TEXT_SCALE.alter(text_scale),
        TEXT_COLOR.alter(text.left_upper.color),
      ]
    }).collect()).unwrap_or(Vec::new());

    let text_textures: Vec<_> = input.texts.map(|(texts, _)| texts.iter().map(|text| [&***text.text_texture]).collect()).unwrap_or(Vec::new());

    let text_render_cmds: Vec<_> = input.texts.iter().enumerate().map(|(i, _)| {
        let blending = (Equation::Additive, Factor::One, Factor::SrcAlphaComplement);
        Pipe::empty()
          .uniforms(&text_uniforms[i])
          .textures(&text_textures[i])
          .unwrap(RenderCommand::new(Some(blending), true, vec![
            Pipe::new(text_quad.clone())
          ]))
      }).collect();

    let disc_uniforms = [
      DISC_SCREEN_RATIO.alter(self.ratio)
    ];

    Pipeline::new(&self.framebuffer, [0., 0., 0., 0.], &[], &[], vec![
      // render triangles
      Pipe::new(ShadingCommand::new(&self.tri_program.borrow(), vec![
        Pipe::new(RenderCommand::new(None, true, vec![
          Pipe::new(tris)
        ]))
      ])),
      // render discs
      Pipe::empty()
        .uniforms(&disc_uniforms)
        .unwrap(ShadingCommand::new(&self.disc_program.borrow(), vec![
          Pipe::new(RenderCommand::new(None, true, vec![
            Pipe::new(discs)
          ]))
        ])),
      // render texts
      Pipe::new(ShadingCommand::new(&self.text_program.borrow(), text_render_cmds))
    ]).run();

    &self.framebuffer.color_slot
  }
}

#[derive(Clone)]
pub struct RenderInput<'a, 'b> where 'b: 'a {
  triangles: &'a [Triangle],
  discs: &'a [Disc],
  texts: Option<(&'a [Text<'b>], f32)>
}

impl<'a, 'b> RenderInput<'a, 'b> where 'b: 'a {
  pub fn new() -> Self {
    RenderInput {
      triangles: &[],
      discs: &[],
      texts: None,
    }
  }

  pub fn triangles(self, triangles: &'a [Triangle]) -> Self {
    RenderInput {
      triangles: triangles, ..self
    }
  }

  pub fn discs(self, discs: &'a [Disc]) -> Self {
    RenderInput {
      discs: discs,
      ..self
    }
  }

  pub fn texts(self, texts: &'a [Text<'b>], scale: f32) -> Self {
    RenderInput {
      texts: Some((texts, scale.max(0.))),
      ..self
    }
  }
}

/// Overlay units are used to position stuff in overlay in a universal way and screen independent
/// way. The screen uses normalized coordinates with the origin at lower left as the following
/// diagram:
///
/// ^ y (1)
/// |
/// |
/// |
/// O------> x (1)
#[derive(Copy, Clone, Debug, PartialEq)]
struct OverlayUnit {
  rw: f32,
  rh: f32
}

impl OverlayUnit {
  pub fn new(w: u32, h: u32) -> Self {
    OverlayUnit {
      rw: 1. / (w as f32),
      rh: 1. / (h as f32)
    }
  }

  pub fn from_window(&self, x: u32, y: u32) -> [f32; 2] {
    let x_ = x as f32 * self.rw;
    assert!(x_ >= 0. && x_ <= 1., "x={}", x_);

    let y_ = y as f32 * self.rh;
    assert!(y_ >= 0. && y_ <= 1., "y={}", y_);

    [x_, y_]
  }
}
<commit_msg>Should fix the lifetime issue in clip.<commit_after>use luminance::{Dim2, Equation, Factor, Flat, Framebuffer, Mode, Pipe, Pipeline, RenderCommand, ShadingCommand, Tess, TessRender, TessVertices, Uniform, Unit, Vertex, VertexFormat};
use std::cell::RefCell;

use resource::Res;
use scene::Scene;
use shader::Program;
use text::TextTexture;
use texture::{RGBA32F, Texture};

/// Vertex used in overlay’s objects.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Vert {
  /// Position.
  pub pos: [f32; 3],
  /// Color.
  pub color: [f32; 4]
}

impl Vert {
  pub fn new(pos: [f32; 3], color: [f32; 4]) -> Self {
    Vert {
      pos: pos,
      color: color
    }
  }
}

impl Vertex for Vert {
  fn vertex_format() -> VertexFormat {
    <([f32; 3], [f32; 4]) as Vertex>::vertex_format()
  }
}

pub struct Triangle(pub Vert, pub Vert, pub Vert);

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Disc {
  center: Vert,
  radius: f32
}

impl Disc {
  pub fn new(center: Vert, radius: f32) -> Self {
    Disc {
      center: center,
      radius: radius
    }
  }
}

impl Vertex for Disc {
  fn vertex_format() -> VertexFormat {
    <(Vert, f32) as Vertex>::vertex_format()
  }
}

pub type Texture2D = Texture<Flat, Dim2, RGBA32F>;

pub struct Text<'a> {
  text_texture: &'a TextTexture,
  left_upper: Vert
}

impl<'a> Text<'a> {
  pub fn new(text_texture: &'a TextTexture, left_upper: Vert) -> Self {
    Text {
      text_texture: text_texture,
      left_upper: left_upper
    }
  }
}

const DISC_SCREEN_RATIO: &'static Uniform<f32> = &Uniform::new(0);

const TEXT_SAMPLER: &'static Uniform<Unit> = &Uniform::new(0);
const TEXT_POS: &'static Uniform<[f32; 3]> = &Uniform::new(1);
const TEXT_SIZE: &'static Uniform<[f32; 2]> = &Uniform::new(2);
const TEXT_SCALE: &'static Uniform<f32> = &Uniform::new(3);
const TEXT_COLOR: &'static Uniform<[f32; 4]> = &Uniform::new(4);

/// A renderer responsible of rendering shapes.
pub struct Renderer {
  framebuffer: Framebuffer<Flat, Dim2, Texture2D, ()>,
  ratio: f32,
  tri_program: Res<Program>,
  tris: RefCell<Tess>,
  tri_vert_nb: RefCell<usize>,
  disc_program: Res<Program>,
  discs: RefCell<Tess>,
  disc_vert_nb: RefCell<usize>,
  text_program: Res<Program>,
  text_quad: Tess,
  overlay_unit: OverlayUnit,
}

impl Renderer {
  pub fn new(w: u32, h: u32, max_tris: usize, max_discs: usize, scene: &mut Scene) -> Self {
    let fb = Framebuffer::new((w, h), 0).unwrap();

    let tri_program = scene.get("spectra/overlay/triangle.glsl", vec![]).unwrap();
    let tris = Tess::new(Mode::Triangle, TessVertices::Reserve::<Vert>(max_tris * 3), None);

    let disc_program = scene.get("spectra/overlay/disc.glsl", vec![DISC_SCREEN_RATIO.sem("ratio")]).unwrap();
    let discs = Tess::new(Mode::Point, TessVertices::Reserve::<Disc>(max_discs), None);

    let text_program = scene.get("spectra/overlay/text.glsl", vec![
      TEXT_SAMPLER.sem("text_texture"),
      TEXT_POS.sem("pos"),
      TEXT_SIZE.sem("size"),
      TEXT_SCALE.sem("scale"),
      TEXT_COLOR.sem("color")
    ]).unwrap();

    let text_quad = Tess::attributeless(Mode::TriangleStrip, 4);

    Renderer {
      framebuffer: fb,
      ratio: w as f32 / h as f32,
      tri_program: tri_program,
      tris: RefCell::new(tris),
      tri_vert_nb: RefCell::new(0),
      disc_program: disc_program,
      discs: RefCell::new(discs),
      disc_vert_nb: RefCell::new(0),
      text_program: text_program,
      text_quad: text_quad,
      overlay_unit: OverlayUnit::new(w, h)
    }
  }

  fn dispatch(&self, tris: &mut Tess, discs: &mut Tess, input: &RenderInput) {
    let mut tris = tris.as_slice_mut().unwrap();
    let mut tri_i = 0;
    let mut discs = discs.as_slice_mut().unwrap();
    let mut disc_i = 0;

    for &Triangle(a, b, c) in input.triangles {
      tris[tri_i] = a;
      tri_i += 1;

      tris[tri_i] = b;
      tri_i += 1;

      tris[tri_i] = c;
      tri_i += 1;
    }

    for disc in input.discs {
      discs[disc_i] = *disc;
      disc_i += 1;
    }

    *self.tri_vert_nb.borrow_mut() = tri_i;
    *self.disc_vert_nb.borrow_mut() = disc_i;
  }

  pub fn render(&self, input: RenderInput) -> &Texture2D {
    self.dispatch(&mut self.tris.borrow_mut(), &mut self.discs.borrow_mut(), &input);

    let tris_ref = self.tris.borrow();
    let tris = TessRender::one_sub(&tris_ref, *self.tri_vert_nb.borrow());
    let discs_ref = self.discs.borrow();
    let discs = TessRender::one_sub(&discs_ref, *self.disc_vert_nb.borrow());
    let text_quad = TessRender::one_whole(&self.text_quad);

    // FIXME: no alloc?
    let text_uniforms: Vec<_> = input.texts.map(|(texts, text_scale)| texts.iter().map(|text| {
      let (tex_w, tex_h) = text.text_texture.size();

      [
        TEXT_SAMPLER.alter(Unit::new(0)),
        TEXT_POS.alter(text.left_upper.pos),
        TEXT_SIZE.alter(self.overlay_unit.from_window(tex_w, tex_h)),
        TEXT_SCALE.alter(text_scale),
        TEXT_COLOR.alter(text.left_upper.color),
      ]
    }).collect()).unwrap_or(Vec::new());

    let text_textures: Vec<_> = input.texts.map(|(texts, _)| texts.iter().map(|text| [&***text.text_texture]).collect()).unwrap_or(Vec::new());

    let text_render_cmds: Vec<_> = input.texts.iter().enumerate().map(|(i, _)| {
        let blending = (Equation::Additive, Factor::One, Factor::SrcAlphaComplement);
        Pipe::empty()
          .uniforms(&text_uniforms[i])
          .textures(&text_textures[i])
          .unwrap(RenderCommand::new(Some(blending), true, vec![
            Pipe::new(text_quad.clone())
          ]))
      }).collect();

    let disc_uniforms = [
      DISC_SCREEN_RATIO.alter(self.ratio)
    ];

    Pipeline::new(&self.framebuffer, [0., 0., 0., 0.], &[], &[], vec![
      // render triangles
      Pipe::new(ShadingCommand::new(&self.tri_program.borrow(), vec![
        Pipe::new(RenderCommand::new(None, true, vec![
          Pipe::new(tris)
        ]))
      ])),
      // render discs
      Pipe::empty()
        .uniforms(&disc_uniforms)
        .unwrap(ShadingCommand::new(&self.disc_program.borrow(), vec![
          Pipe::new(RenderCommand::new(None, true, vec![
            Pipe::new(discs)
          ]))
        ])),
      // render texts
      Pipe::new(ShadingCommand::new(&self.text_program.borrow(), text_render_cmds))
    ]).run();

    &self.framebuffer.color_slot
  }
}

#[derive(Clone)]
pub struct RenderInput<'a, 'b> where 'b: 'a {
  triangles: &'a [Triangle],
  discs: &'a [Disc],
  texts: Option<(&'a [Text<'b>], f32)>
}

impl<'a, 'b> RenderInput<'a, 'b> where 'b: 'a {
  pub fn new() -> Self {
    RenderInput {
      triangles: &[],
      discs: &[],
      texts: None,
    }
  }

  pub fn triangles(self, triangles: &'a [Triangle]) -> Self {
    RenderInput {
      triangles: triangles, ..self
    }
  }

  pub fn discs(self, discs: &'a [Disc]) -> Self {
    RenderInput {
      discs: discs,
      ..self
    }
  }

  pub fn texts(self, texts: &'a [Text<'b>], scale: f32) -> Self {
    RenderInput {
      texts: Some((texts, scale.max(0.))),
      ..self
    }
  }
}

/// Overlay units are used to position stuff in overlay in a universal way and screen independent
/// way. The screen uses normalized coordinates with the origin at lower left as the following
/// diagram:
///
/// ^ y (1)
/// |
/// |
/// |
/// O------> x (1)
#[derive(Copy, Clone, Debug, PartialEq)]
struct OverlayUnit {
  rw: f32,
  rh: f32
}

impl OverlayUnit {
  pub fn new(w: u32, h: u32) -> Self {
    OverlayUnit {
      rw: 1. / (w as f32),
      rh: 1. / (h as f32)
    }
  }

  pub fn from_window(&self, x: u32, y: u32) -> [f32; 2] {
    let x_ = x as f32 * self.rw;
    assert!(x_ >= 0. && x_ <= 1., "x={}", x_);

    let y_ = y as f32 * self.rh;
    assert!(y_ >= 0. && y_ <= 1., "y={}", y_);

    [x_, y_]
  }
}
<|endoftext|>