<commit_before>// (C)opyleft 2013,2014 Frank Denis

/*!
 * Bloom filter for Rust
 *
 * This is a simple but fast Bloom filter implementation, that requires only
 * 2 hash functions, generated with SipHash-2-4 using randomized keys.
 */

#![desc = "A fast Bloom filter implementation."]
#![license = "BSD"]
#![crate_id="bloomfilter#0.1"]
#![crate_type = "rlib"]
#![warn(non_camel_case_types, non_uppercase_statics, unnecessary_qualification, managed_heap_memory)]

extern crate collections;
extern crate rand;

use std::cmp;
use std::hash::Hash;
use std::num;
use std::hash::sip::SipHasher;
use std::hash::Hasher;
use collections::bitv;

#[cfg(test)]
use rand::Rng;

/// Bloom filter structure
pub struct Bloom {
    priv bitmap: bitv::Bitv,
    priv bitmap_bits: u64,
    priv k_num: uint,
    priv sips: [SipHasher, ..2]
}

impl Bloom {
/// Create a new bloom filter structure.
/// bitmap_size is the size in bytes (not bits) that will be allocated in memory
/// items_count is an estimation of the maximum number of items to store.
    pub fn new(bitmap_size: uint, items_count: uint) -> Bloom {
        assert!(bitmap_size > 0u && items_count > 0u);
        let bitmap_bits = (bitmap_size as u64) * 8u64;
        let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
        let bitmap = bitv::Bitv::new(bitmap_bits as uint, false);
        let sips = [ Bloom::sip_new(), Bloom::sip_new() ];
        Bloom {
            bitmap: bitmap,
            bitmap_bits: bitmap_bits,
            k_num: k_num,
            sips: sips
        }
    }

/// Create a new bloom filter structure.
/// items_count is an estimation of the maximum number of items to store.
/// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
    pub fn new_for_fp_rate(items_count: uint, fp_p: f64) -> Bloom {
        let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
        Bloom::new(bitmap_size, items_count)
    }

/// Compute a recommended bitmap size for items_count items
/// and a fp_p rate of false positives.
/// fp_p obviously has to be within the ]0.0, 1.0[ range.
    pub fn compute_bitmap_size(items_count: uint, fp_p: f64) -> uint {
        assert!(items_count > 0u);
        assert!(fp_p > 0.0 && fp_p < 1.0);
        let log2 = num::ln(2.0f64);
        let log2_2 = log2 * log2;
        ((items_count as f64) * num::ln(fp_p) / (-8.0 * log2_2)).ceil() as uint
    }

/// Record the presence of an item.
    pub fn set<T: Hash>(& mut self, item: T) {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            self.bitmap.set(bit_offset, true);
        }
    }

/// Check if an item is present in the set.
/// There can be false positives, but no false negatives.
    pub fn check<T: Hash>(&self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            if self.bitmap.get(bit_offset) == false {
                return false;
            }
        }
        true
    }

/// Record the presence of an item in the set,
/// and return the previous state of this item.
    pub fn check_and_set<T: Hash>(&mut self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        let mut found = true;
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            if self.bitmap.get(bit_offset) == false {
                found = false;
                self.bitmap.set(bit_offset, true);
            }
        }
        found
    }

    fn optimal_k_num(bitmap_bits: u64, items_count: uint) -> uint {
        let m = bitmap_bits as f64;
        let n = items_count as f64;
        let k_num = (m / n * num::ln(2.0f64).ceil()) as uint;
        cmp::max(k_num, 1)
    }

    fn bloom_hash<T: Hash>(&self, hashes: & mut [u64, ..2],
                  item: &T, k_i: uint) -> u64 {
        if k_i < 2 {
            let sip = self.sips[k_i];
            let hash = sip.hash(item);
            hashes[k_i] = hash;
            hash
        } else {
            hashes[0] + (((k_i as u64) * hashes[1]) % 0xffffffffffffffc5)
        }
    }

    fn sip_new() -> SipHasher {
        let mut rng = rand::task_rng();
        SipHasher::new_with_keys(rand::Rand::rand(& mut rng),
                                 rand::Rand::rand(& mut rng))
    }
}

#[test]
fn bloom_test_set() {
    let mut bloom = Bloom::new(10, 80);
    let key = &rand::task_rng().gen_ascii_str(16u);
    assert!(bloom.check(key) == false);
    bloom.set(&key);
    assert!(bloom.check(key.clone()) == true);
}

#[test]
fn bloom_test_check_and_set() {
    let mut bloom = Bloom::new(10, 80);
    let key = &rand::task_rng().gen_ascii_str(16u);
    assert!(bloom.check_and_set(key) == false);
    assert!(bloom.check_and_set(key.clone()) == true);
}
<commit_msg>Remove unnecessary `priv` visibility<commit_after>// (C)opyleft 2013,2014 Frank Denis

/*!
 * Bloom filter for Rust
 *
 * This is a simple but fast Bloom filter implementation, that requires only
 * 2 hash functions, generated with SipHash-2-4 using randomized keys.
 */

#![desc = "A fast Bloom filter implementation."]
#![license = "BSD"]
#![crate_id="bloomfilter#0.1"]
#![crate_type = "rlib"]
#![warn(non_camel_case_types, non_uppercase_statics, unnecessary_qualification, managed_heap_memory)]

extern crate collections;
extern crate rand;

use std::cmp;
use std::hash::Hash;
use std::num;
use std::hash::sip::SipHasher;
use std::hash::Hasher;
use collections::bitv;

#[cfg(test)]
use rand::Rng;

/// Bloom filter structure
pub struct Bloom {
    bitmap: bitv::Bitv,
    bitmap_bits: u64,
    k_num: uint,
    sips: [SipHasher, ..2]
}

impl Bloom {
/// Create a new bloom filter structure.
/// bitmap_size is the size in bytes (not bits) that will be allocated in memory
/// items_count is an estimation of the maximum number of items to store.
    pub fn new(bitmap_size: uint, items_count: uint) -> Bloom {
        assert!(bitmap_size > 0u && items_count > 0u);
        let bitmap_bits = (bitmap_size as u64) * 8u64;
        let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
        let bitmap = bitv::Bitv::new(bitmap_bits as uint, false);
        let sips = [ Bloom::sip_new(), Bloom::sip_new() ];
        Bloom {
            bitmap: bitmap,
            bitmap_bits: bitmap_bits,
            k_num: k_num,
            sips: sips
        }
    }

/// Create a new bloom filter structure.
/// items_count is an estimation of the maximum number of items to store.
/// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
    pub fn new_for_fp_rate(items_count: uint, fp_p: f64) -> Bloom {
        let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
        Bloom::new(bitmap_size, items_count)
    }

/// Compute a recommended bitmap size for items_count items
/// and a fp_p rate of false positives.
/// fp_p obviously has to be within the ]0.0, 1.0[ range.
    pub fn compute_bitmap_size(items_count: uint, fp_p: f64) -> uint {
        assert!(items_count > 0u);
        assert!(fp_p > 0.0 && fp_p < 1.0);
        let log2 = num::ln(2.0f64);
        let log2_2 = log2 * log2;
        ((items_count as f64) * num::ln(fp_p) / (-8.0 * log2_2)).ceil() as uint
    }

/// Record the presence of an item.
    pub fn set<T: Hash>(& mut self, item: T) {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            self.bitmap.set(bit_offset, true);
        }
    }

/// Check if an item is present in the set.
/// There can be false positives, but no false negatives.
    pub fn check<T: Hash>(&self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            if self.bitmap.get(bit_offset) == false {
                return false;
            }
        }
        true
    }

/// Record the presence of an item in the set,
/// and return the previous state of this item.
    pub fn check_and_set<T: Hash>(&mut self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        let mut found = true;
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            if self.bitmap.get(bit_offset) == false {
                found = false;
                self.bitmap.set(bit_offset, true);
            }
        }
        found
    }

    fn optimal_k_num(bitmap_bits: u64, items_count: uint) -> uint {
        let m = bitmap_bits as f64;
        let n = items_count as f64;
        let k_num = (m / n * num::ln(2.0f64).ceil()) as uint;
        cmp::max(k_num, 1)
    }

    fn bloom_hash<T: Hash>(&self, hashes: & mut [u64, ..2],
                  item: &T, k_i: uint) -> u64 {
        if k_i < 2 {
            let sip = self.sips[k_i];
            let hash = sip.hash(item);
            hashes[k_i] = hash;
            hash
        } else {
            hashes[0] + (((k_i as u64) * hashes[1]) % 0xffffffffffffffc5)
        }
    }

    fn sip_new() -> SipHasher {
        let mut rng = rand::task_rng();
        SipHasher::new_with_keys(rand::Rand::rand(& mut rng),
                                 rand::Rand::rand(& mut rng))
    }
}

#[test]
fn bloom_test_set() {
    let mut bloom = Bloom::new(10, 80);
    let key = &rand::task_rng().gen_ascii_str(16u);
    assert!(bloom.check(key) == false);
    bloom.set(&key);
    assert!(bloom.check(key.clone()) == true);
}

#[test]
fn bloom_test_check_and_set() {
    let mut bloom = Bloom::new(10, 80);
    let key = &rand::task_rng().gen_ascii_str(16u);
    assert!(bloom.check_and_set(key) == false);
    assert!(bloom.check_and_set(key.clone()) == true);
}
<|endoftext|>


<commit_before>use crate::{t, VERSION};
use std::fmt::Write as _;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::{
    env, fmt, fs,
    io::{self, Write},
};

#[derive(Clone, Copy, Eq, PartialEq)]
pub enum Profile {
    Compiler,
    Codegen,
    Library,
    User,
}

impl Profile {
    fn include_path(&self, src_path: &Path) -> PathBuf {
        PathBuf::from(format!("{}/src/bootstrap/defaults/config.{}.toml", src_path.display(), self))
    }

    pub fn all() -> impl Iterator<Item = Self> {
        use Profile::*;
        // N.B. these are ordered by how they are displayed, not alphabetically
        [Library, Compiler, Codegen, User].iter().copied()
    }

    pub fn purpose(&self) -> String {
        use Profile::*;
        match self {
            Library => "Contribute to the standard library",
            Compiler => "Contribute to the compiler or rustdoc",
            Codegen => "Contribute to the compiler, and also modify LLVM or codegen",
            User => "Install Rust from source",
        }
        .to_string()
    }

    pub fn all_for_help(indent: &str) -> String {
        let mut out = String::new();
        for choice in Profile::all() {
            writeln!(&mut out, "{}{}: {}", indent, choice, choice.purpose()).unwrap();
        }
        out
    }
}

impl FromStr for Profile {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "lib" | "library" => Ok(Profile::Library),
            "compiler" | "rustdoc" => Ok(Profile::Compiler),
            "llvm" | "codegen" => Ok(Profile::Codegen),
            "maintainer" | "user" => Ok(Profile::User),
            _ => Err(format!("unknown profile: '{}'", s)),
        }
    }
}

impl fmt::Display for Profile {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Profile::Compiler => write!(f, "compiler"),
            Profile::Codegen => write!(f, "codegen"),
            Profile::Library => write!(f, "library"),
            Profile::User => write!(f, "user"),
        }
    }
}

pub fn setup(src_path: &Path, profile: Profile) {
    let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);

    if cfg_file.as_ref().map_or(false, |f| f.exists()) {
        let file = cfg_file.unwrap();
        println!(
            "error: you asked `x.py` to setup a new config file, but one already exists at `{}`",
            file.display()
        );
        println!("help: try adding `profile = \"{}\"` at the top of {}", profile, file.display());
        println!(
            "note: this will use the configuration in {}",
            profile.include_path(src_path).display()
        );
        std::process::exit(1);
    }

    let path = cfg_file.unwrap_or_else(|| src_path.join("config.toml"));
    let settings = format!(
        "# Includes one of the default files in src/bootstrap/defaults\n\
    profile = \"{}\"\n\
    changelog-seen = {}\n",
        profile, VERSION
    );
    t!(fs::write(path, settings));

    let include_path = profile.include_path(src_path);
    println!("`x.py` will now use the configuration at {}", include_path.display());

    let suggestions = match profile {
        Profile::Codegen | Profile::Compiler => &["check", "build", "test"][..],
        Profile::Library => &["check", "build", "test library/std", "doc"],
        Profile::User => &["dist", "build"],
    };

    println!();

    t!(install_git_hook_maybe(src_path));

    println!();

    println!("To get started, try one of the following commands:");
    for cmd in suggestions {
        println!("- `x.py {}`", cmd);
    }

    if profile != Profile::User {
        println!(
            "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html"
        );
    }
}

// Used to get the path for `Subcommand::Setup`
pub fn interactive_path() -> io::Result<Profile> {
    fn abbrev_all() -> impl Iterator<Item = (String, Profile)> {
        ('a'..).map(|c| c.to_string()).zip(Profile::all())
    }

    fn parse_with_abbrev(input: &str) -> Result<Profile, String> {
        let input = input.trim().to_lowercase();
        for (letter, profile) in abbrev_all() {
            if input == letter {
                return Ok(profile);
            }
        }
        input.parse()
    }

    println!("Welcome to the Rust project! What do you want to do with x.py?");
    for (letter, profile) in abbrev_all() {
        println!("{}) {}: {}", letter, profile, profile.purpose());
    }
    let template = loop {
        print!(
            "Please choose one ({}): ",
            abbrev_all().map(|(l, _)| l).collect::<Vec<_>>().join("/")
        );
        io::stdout().flush()?;
        let mut input = String::new();
        io::stdin().read_line(&mut input)?;
        break match parse_with_abbrev(&input) {
            Ok(profile) => profile,
            Err(err) => {
                println!("error: {}", err);
                println!("note: press Ctrl+C to exit");
                continue;
            }
        };
    };
    Ok(template)
}

// install a git hook to automatically run tidy --bless, if they want
fn install_git_hook_maybe(src_path: &Path) -> io::Result<()> {
    let mut input = String::new();
    println!(
        "Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
If you'd like, x.py can install a git hook for you that will automatically run `tidy --bless` on each commit
to ensure your code is up to par. If you decide later that this behavior is undesirable,
simply delete the `pre-commit` file from .git/hooks."
    );

    let should_install = loop {
        print!("Would you like to install the git hook?: [y/N] ");
        io::stdout().flush()?;
        input.clear();
        io::stdin().read_line(&mut input)?;
        break match input.trim().to_lowercase().as_str() {
            "y" | "yes" => true,
            "n" | "no" | "" => false,
            _ => {
                println!("error: unrecognized option '{}'", input.trim());
                println!("note: press Ctrl+C to exit");
                continue;
            }
        };
    };

    Ok(if should_install {
        let src = src_path.join("src").join("etc").join("pre-commit.sh");
        let dst = src_path.join(".git").join("hooks").join("pre-commit");
        match fs::hard_link(src, dst) {
            Err(e) => println!(
                "x.py encountered an error -- do you already have the git hook installed?\n{}",
                e
            ),
            Ok(_) => println!("Linked `src/etc/pre-commit.sh` to `.git/hooks/pre-commit`"),
        };
    } else {
        println!("Ok, skipping installation!");
    })
}
<commit_msg>x.py setup: Avoid infinite loop if stdin is /dev/null<commit_after>use crate::{t, VERSION};
use std::fmt::Write as _;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::{
    env, fmt, fs,
    io::{self, Write},
};

#[derive(Clone, Copy, Eq, PartialEq)]
pub enum Profile {
    Compiler,
    Codegen,
    Library,
    User,
}

impl Profile {
    fn include_path(&self, src_path: &Path) -> PathBuf {
        PathBuf::from(format!("{}/src/bootstrap/defaults/config.{}.toml", src_path.display(), self))
    }

    pub fn all() -> impl Iterator<Item = Self> {
        use Profile::*;
        // N.B. these are ordered by how they are displayed, not alphabetically
        [Library, Compiler, Codegen, User].iter().copied()
    }

    pub fn purpose(&self) -> String {
        use Profile::*;
        match self {
            Library => "Contribute to the standard library",
            Compiler => "Contribute to the compiler or rustdoc",
            Codegen => "Contribute to the compiler, and also modify LLVM or codegen",
            User => "Install Rust from source",
        }
        .to_string()
    }

    pub fn all_for_help(indent: &str) -> String {
        let mut out = String::new();
        for choice in Profile::all() {
            writeln!(&mut out, "{}{}: {}", indent, choice, choice.purpose()).unwrap();
        }
        out
    }
}

impl FromStr for Profile {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "lib" | "library" => Ok(Profile::Library),
            "compiler" | "rustdoc" => Ok(Profile::Compiler),
            "llvm" | "codegen" => Ok(Profile::Codegen),
            "maintainer" | "user" => Ok(Profile::User),
            _ => Err(format!("unknown profile: '{}'", s)),
        }
    }
}

impl fmt::Display for Profile {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Profile::Compiler => write!(f, "compiler"),
            Profile::Codegen => write!(f, "codegen"),
            Profile::Library => write!(f, "library"),
            Profile::User => write!(f, "user"),
        }
    }
}

pub fn setup(src_path: &Path, profile: Profile) {
    let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);

    if cfg_file.as_ref().map_or(false, |f| f.exists()) {
        let file = cfg_file.unwrap();
        println!(
            "error: you asked `x.py` to setup a new config file, but one already exists at `{}`",
            file.display()
        );
        println!("help: try adding `profile = \"{}\"` at the top of {}", profile, file.display());
        println!(
            "note: this will use the configuration in {}",
            profile.include_path(src_path).display()
        );
        std::process::exit(1);
    }

    let path = cfg_file.unwrap_or_else(|| src_path.join("config.toml"));
    let settings = format!(
        "# Includes one of the default files in src/bootstrap/defaults\n\
    profile = \"{}\"\n\
    changelog-seen = {}\n",
        profile, VERSION
    );
    t!(fs::write(path, settings));

    let include_path = profile.include_path(src_path);
    println!("`x.py` will now use the configuration at {}", include_path.display());

    let suggestions = match profile {
        Profile::Codegen | Profile::Compiler => &["check", "build", "test"][..],
        Profile::Library => &["check", "build", "test library/std", "doc"],
        Profile::User => &["dist", "build"],
    };

    println!();

    t!(install_git_hook_maybe(src_path));

    println!();

    println!("To get started, try one of the following commands:");
    for cmd in suggestions {
        println!("- `x.py {}`", cmd);
    }

    if profile != Profile::User {
        println!(
            "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html"
        );
    }
}

// Used to get the path for `Subcommand::Setup`
pub fn interactive_path() -> io::Result<Profile> {
    fn abbrev_all() -> impl Iterator<Item = (String, Profile)> {
        ('a'..).map(|c| c.to_string()).zip(Profile::all())
    }

    fn parse_with_abbrev(input: &str) -> Result<Profile, String> {
        let input = input.trim().to_lowercase();
        for (letter, profile) in abbrev_all() {
            if input == letter {
                return Ok(profile);
            }
        }
        input.parse()
    }

    println!("Welcome to the Rust project! What do you want to do with x.py?");
    for (letter, profile) in abbrev_all() {
        println!("{}) {}: {}", letter, profile, profile.purpose());
    }
    let template = loop {
        print!(
            "Please choose one ({}): ",
            abbrev_all().map(|(l, _)| l).collect::<Vec<_>>().join("/")
        );
        io::stdout().flush()?;
        let mut input = String::new();
        io::stdin().read_line(&mut input)?;
        if input == "" {
            eprintln!("EOF on stdin, when expecting answer to question.  Giving up.");
            std::process::exit(1);
        }
        break match parse_with_abbrev(&input) {
            Ok(profile) => profile,
            Err(err) => {
                println!("error: {}", err);
                println!("note: press Ctrl+C to exit");
                continue;
            }
        };
    };
    Ok(template)
}

// install a git hook to automatically run tidy --bless, if they want
fn install_git_hook_maybe(src_path: &Path) -> io::Result<()> {
    let mut input = String::new();
    println!(
        "Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
If you'd like, x.py can install a git hook for you that will automatically run `tidy --bless` on each commit
to ensure your code is up to par. If you decide later that this behavior is undesirable,
simply delete the `pre-commit` file from .git/hooks."
    );

    let should_install = loop {
        print!("Would you like to install the git hook?: [y/N] ");
        io::stdout().flush()?;
        input.clear();
        io::stdin().read_line(&mut input)?;
        break match input.trim().to_lowercase().as_str() {
            "y" | "yes" => true,
            "n" | "no" | "" => false,
            _ => {
                println!("error: unrecognized option '{}'", input.trim());
                println!("note: press Ctrl+C to exit");
                continue;
            }
        };
    };

    Ok(if should_install {
        let src = src_path.join("src").join("etc").join("pre-commit.sh");
        let dst = src_path.join(".git").join("hooks").join("pre-commit");
        match fs::hard_link(src, dst) {
            Err(e) => println!(
                "x.py encountered an error -- do you already have the git hook installed?\n{}",
                e
            ),
            Ok(_) => println!("Linked `src/etc/pre-commit.sh` to `.git/hooks/pre-commit`"),
        };
    } else {
        println!("Ok, skipping installation!");
    })
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use toml::Value;

use task_hookrs::task::Task as TTask;

use libimagstore::store::{FileLockEntry, Store};
use libimagstore::storeid::IntoStoreId;
use module_path::ModuleEntryPath;

use error::{TodoError, TodoErrorKind};
use result::Result;

/// Task struct containing a `FileLockEntry`
#[derive(Debug)]
pub struct Task<'a> {
    pub flentry : FileLockEntry<'a>,
}

impl<'a> Task<'a> {

    /// Concstructs a new `Task` with a `FileLockEntry`
    pub fn new(fle : FileLockEntry<'a>) -> Task<'a> {
        Task {
            flentry : fle
        }
    }

}

/// A trait to get a `libimagtodo::task::Task` out of the implementing object.
/// This Task struct is merely a wrapper for a `FileLockEntry`, therefore the function name
/// `into_filelockentry`.
pub trait IntoTask<'a> {

    /// # Usage
    /// ```ignore
    /// use std::io::stdin;
    ///
    /// use task_hookrs::task::Task;
    /// use task_hookrs::import::import;
    /// use libimagstore::store::{Store, FileLockEntry};
    ///
    /// if let Ok(task_hookrs_task) = import(stdin()) {
    ///     // Store is given at runtime
    ///     let task = task_hookrs_task.into_filelockentry(store);
    ///     println!("Task with uuid: {}", task.flentry.get_header().get("todo.uuid"));
    /// }
    /// ```
    fn into_filelockentry(self, store : &'a Store) -> Result<Task<'a>>;

}

impl<'a> IntoTask<'a> for TTask {

    fn into_filelockentry(self, store : &'a Store) -> Result<Task<'a>> {
        let uuid     = self.uuid();
        let store_id = ModuleEntryPath::new(format!("taskwarrior/{}", uuid)).into_storeid();

        match store.retrieve(store_id) {
            Err(e) => return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))),
            Ok(mut fle) => {
                {
                    let mut header = fle.get_header_mut();
                    match header.read("todo") {
                        Ok(None) => {
                            if let Err(e) = header.set("todo", Value::Table(BTreeMap::new())) {
                                return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
                            }
                        }
                        Ok(Some(_)) => { }
                        Err(e) => {
                            return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
                        }
                    }

                    if let Err(e) = header.set("todo.uuid", Value::String(format!("{}",uuid))) {
                        return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
                    }
                }

                // If none of the errors above have returned the function, everything is fine
                Ok(Task { flentry : fle } )
            }
        }
    }

}
<commit_msg>The Task type can have a unnamed member<commit_after>use std::collections::BTreeMap;
use toml::Value;

use task_hookrs::task::Task as TTask;

use libimagstore::store::{FileLockEntry, Store};
use libimagstore::storeid::IntoStoreId;
use module_path::ModuleEntryPath;

use error::{TodoError, TodoErrorKind};
use result::Result;

/// Task struct containing a `FileLockEntry`
#[derive(Debug)]
pub struct Task<'a>(FileLockEntry<'a>);

impl<'a> Task<'a> {

    /// Concstructs a new `Task` with a `FileLockEntry`
    pub fn new(fle: FileLockEntry<'a>) -> Task<'a> {
        Task(fle)
    }

}

/// A trait to get a `libimagtodo::task::Task` out of the implementing object.
/// This Task struct is merely a wrapper for a `FileLockEntry`, therefore the function name
/// `into_filelockentry`.
pub trait IntoTask<'a> {

    /// # Usage
    /// ```ignore
    /// use std::io::stdin;
    ///
    /// use task_hookrs::task::Task;
    /// use task_hookrs::import::import;
    /// use libimagstore::store::{Store, FileLockEntry};
    ///
    /// if let Ok(task_hookrs_task) = import(stdin()) {
    ///     // Store is given at runtime
    ///     let task = task_hookrs_task.into_filelockentry(store);
    ///     println!("Task with uuid: {}", task.flentry.get_header().get("todo.uuid"));
    /// }
    /// ```
    fn into_filelockentry(self, store : &'a Store) -> Result<Task<'a>>;

}

impl<'a> IntoTask<'a> for TTask {

    fn into_filelockentry(self, store : &'a Store) -> Result<Task<'a>> {
        let uuid     = self.uuid();
        let store_id = ModuleEntryPath::new(format!("taskwarrior/{}", uuid)).into_storeid();

        match store.retrieve(store_id) {
            Err(e) => return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))),
            Ok(mut fle) => {
                {
                    let mut header = fle.get_header_mut();
                    match header.read("todo") {
                        Ok(None) => {
                            if let Err(e) = header.set("todo", Value::Table(BTreeMap::new())) {
                                return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
                            }
                        }
                        Ok(Some(_)) => { }
                        Err(e) => {
                            return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
                        }
                    }

                    if let Err(e) = header.set("todo.uuid", Value::String(format!("{}",uuid))) {
                        return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
                    }
                }

                // If none of the errors above have returned the function, everything is fine
                Ok(Task::new(fle))
            }
        }
    }

}
<|endoftext|>


<commit_before>// A reference to a wire in a relatively located tile
#[derive(Clone)]
pub struct RelWire {
    pub rel_x: i32,   // (bel.x + rel_x == tile.x)
    pub rel_y: i32,   // (bel.y + rel_y == tile.y)
    pub name: String, // wire name in tile
}

impl RelWire {
    pub fn rel_name(&self) -> String {
        let mut name = String::new();
        if self.rel_y < 0 {
            name.push_str(&format!("N{}", -self.rel_y));
        }
        if self.rel_y > 0 {
            name.push_str(&format!("S{}", self.rel_y));
        }
        if self.rel_x < 0 {
            name.push_str(&format!("W{}", -self.rel_x));
        }
        if self.rel_x > 0 {
            name.push_str(&format!("E{}", self.rel_x));
        }
        if !name.is_empty() {
            name.push(':');
        }
        name.push_str(&self.name);
        name
    }
}

#[derive(Eq, PartialEq, Clone)]
pub enum PinDir {
    INPUT = 0,
    OUTPUT = 1,
    INOUT = 2,
}

#[derive(Clone)]
pub struct BelPin {
    pub name: String,  // name of pin on bel
    pub desc: String,  // description for documentation
    pub dir: PinDir,   // direction
    pub wire: RelWire, // reference to wire in tile
}

impl BelPin {
    pub fn new(
        name: &str,
        desc: &str,
        dir: PinDir,
        wirename: &str,
        rel_x: i32,
        rel_y: i32,
    ) -> BelPin {
        BelPin {
            name: name.to_string(),
            desc: desc.to_string(),
            dir: dir,
            wire: RelWire {
                rel_x: rel_x,
                rel_y: rel_y,
                name: wirename.to_string(),
            },
        }
    }

    // Standard postfixed wirename scheme
    pub fn new_p(
        name: &str,
        desc: &str,
        dir: PinDir,
        postfix: &str,
        rel_x: i32,
        rel_y: i32,
    ) -> BelPin {
        BelPin {
            name: name.to_string(),
            desc: desc.to_string(),
            dir: dir,
            wire: RelWire {
                rel_x: rel_x,
                rel_y: rel_y,
                name: format!("J{}_{}", name, postfix),
            },
        }
    }
    // Logical->physical mapped postfixed wirename scheme
    pub fn new_mapped(
        name: &str,
        desc: &str,
        dir: PinDir,
        physpin: &str,
        postfix: &str,
        rel_x: i32,
        rel_y: i32,
    ) -> BelPin {
        BelPin {
            name: name.to_string(),
            desc: desc.to_string(),
            dir: dir,
            wire: RelWire {
                rel_x: rel_x,
                rel_y: rel_y,
                name: format!("J{}_{}", physpin, postfix),
            },
        }
    }
}

pub struct Bel {
    pub name: String,
    pub beltype: String,
    pub pins: Vec<BelPin>,
    pub z: u32,
}

// Macros for common cases
macro_rules! input {
	($($rest:expr),*) =>
		( def_pin!(PinDir::INPUT, $($rest),*) );
}

macro_rules! output {
	($($rest:expr),*) =>
		( def_pin!(PinDir::OUTPUT, $($rest),*) );
}

macro_rules! def_pin {
    ($dir: expr, $postfix: expr, $name: expr) => {
        BelPin::new_p($name, "", $dir, $postfix, 0, 0)
    };

    ($dir: expr,$postfix: expr, $name: expr, $desc: expr) => {
        BelPin::new_p($name, $desc, $dir, $postfix, 0, 0)
    };
    ($dir: expr,$postfix: expr, $name: expr, $desc: expr, $rel_x: expr, $rel_y: expr) => {
        BelPin::new_p($name, $desc, $dir, $postfix, $rel_x, $rel_y)
    };
}

macro_rules! input_m {
    ($($rest:expr),*) =>
        ( def_pin_mapped!(PinDir::INPUT, $($rest),*) );
}

macro_rules! output_m {
    ($($rest:expr),*) =>
        ( def_pin_mapped!(PinDir::OUTPUT, $($rest),*) );
}

macro_rules! inout_m {
    ($($rest:expr),*) =>
        ( def_pin_mapped!(PinDir::INOUT, $($rest),*) );
}

macro_rules! def_pin_mapped {
    ($dir: expr, $postfix: expr, $name: expr) => {
        BelPin::new_p($name, "", $dir, $physpin, $postfix, 0, 0)
    };

    ($dir: expr,$postfix: expr, $name: expr, $physpin: expr, $desc: expr) => {
        BelPin::new_mapped($name, $desc, $dir, $physpin, $postfix, 0, 0)
    };
}

const Z_TO_CHAR: [char; 4] = ['A', 'B', 'C', 'D'];

impl Bel {
    pub fn make_oxide_ff(slice: usize, ff: usize) -> Bel {
        let ch = Z_TO_CHAR[slice];
        let postfix = format!("SLICE{}", ch);
        let pins = vec![
            input!(&postfix, "CLK", "FF clock"),
            input!(&postfix, "CE", "FF clock enable"),
            input!(&postfix, "LSR", "FF local set/reset"),
            input_m!(
                &postfix,
                "DI",
                &format!("DI{}", ff),
                "FF input from LUT/MUX output"
            ),
            input_m!(
                &postfix,
                "M",
                &format!("M{}", ff),
                "FF direct input from fabric M signal"
            ),
            output_m!(&postfix, "Q", &format!("Q{}", ff), "FF output"),
        ];
        Bel {
            name: format!("{}_FF{}", &postfix, ff),
            beltype: String::from("OXIDE_FF"),
            pins: pins,
            z: (slice << 3 | (ff + 2)) as u32,
        }
    }

    pub fn make_oxide_comb(slice: usize, lut: usize) -> Bel {
        let ch = Z_TO_CHAR[slice];
        let postfix = format!("SLICE{}", ch);
        let mut pins = vec![
            input_m!(&postfix, "A", &format!("A{}", lut), "LUT A input"),
            input_m!(&postfix, "B", &format!("B{}", lut), "LUT B input"),
            input_m!(&postfix, "C", &format!("C{}", lut), "LUT C input"),
            input_m!(&postfix, "D", &format!("D{}", lut), "LUT D input"),
            input_m!(
                &postfix,
                "FCI",
                if lut == 0 { "FCI" } else { "INT_CARRY" },
                "CCU2 fast carry input"
            ),
            output_m!(&postfix, "F", &format!("F{}", lut), "LUT/sum output"),
            output_m!(
                &postfix,
                "FCO",
                if lut == 1 { "FCO" } else { "INT_CARRY" },
                "CCU2 fast carry output"
            ),
        ];
        if lut == 0 {
            // MUX2 in LUT0 COMB only
            pins.append(&mut vec![
                input!(&postfix, "SEL", "MUX2 select input"),
                input!(&postfix, "F1", "input from second LUT to MUX2"),
                output_m!(&postfix, "OFX", "OFX0", "MUX2 output"),
            ]);
        }
        if slice == 0 || slice == 1 {
            // DPRAM in lower two SLICEs only
            pins.append(&mut vec![
                input!(&postfix, "WAD0", "LUTRAM write address 0 (from RAMW)"),
                input!(&postfix, "WAD1", "LUTRAM write address 1 (from RAMW)"),
                input!(&postfix, "WAD2", "LUTRAM write address 2 (from RAMW)"),
                input!(&postfix, "WAD3", "LUTRAM write address 3 (from RAMW)"),
                input_m!(
                    &postfix,
                    "WD",
                    &format!("WD{}", lut),
                    "LUTRAM write data (from RAMW)"
                ),
                input!(&postfix, "WCK", "LUTRAM write clock (from RAMW)"),
                input!(&postfix, "WRE", "LUTRAM write enable (from RAMW)"),
            ]);
        }
        Bel {
            name: format!("{}_LUT{}", &postfix, lut),
            beltype: String::from("OXIDE_COMB"),
            pins: pins,
            z: (slice << 3 | lut) as u32,
        }
    }

    pub fn make_oxide_ramw(slice: usize) -> Bel {
        assert_eq!(slice, 2);
        let ch = Z_TO_CHAR[slice];
        let postfix = format!("SLICE{}", ch);
        let pins = vec![
            input!(&postfix, "A0", "buffered to WADO3"),
            input!(&postfix, "A1", "buffered to WDO2"),
            input!(&postfix, "B0", "buffered to WADO1"),
            input!(&postfix, "B1", "buffered to WDO3"),
            input!(&postfix, "C0", "buffered to WADO2"),
            input!(&postfix, "C1", "buffered to WDO1"),
            input!(&postfix, "D0", "buffered to WADO0"),
            input!(&postfix, "D1", "buffered to WDO0"),
            input!(&postfix, "CLK", "buffered to WCKO"),
            input!(&postfix, "LSR", "buffered to WREO"),
            output!(&postfix, "WADO0", "LUTRAM write address 0 (to SLICEA/B)"),
            output!(&postfix, "WADO1", "LUTRAM write address 1 (to SLICEA/B)"),
            output!(&postfix, "WADO2", "LUTRAM write address 2 (to SLICEA/B)"),
            output!(&postfix, "WADO3", "LUTRAM write address 3 (to SLICEA/B)"),
            output!(&postfix, "WCKO", "LUTRAM write clock (to SLICEA/B)"),
            output!(&postfix, "WREO", "LUTRAM write enable (to SLICEA/B)"),
            output!(&postfix, "WDO0", "LUTRAM write data 0 (to SLICEA)"),
            output!(&postfix, "WDO1", "LUTRAM write data 1 (to SLICEA)"),
            output!(&postfix, "WDO2", "LUTRAM write data 2 (to SLICEB)"),
            output!(&postfix, "WDO3", "LUTRAM write data 3 (to SLICEB)"),
        ];
        Bel {
            name: format!("{}_RAMW", &postfix),
            beltype: String::from("RAMW"),
            pins: pins,
            z: (slice << 3 | 4) as u32,
        }
    }

    pub fn make_seio33(z: usize) -> Bel {
        let ch = Z_TO_CHAR[z];
        let postfix = format!("SEIO33_CORE_IO{}", ch);
        Bel {
            name: format!("PIO{}", ch),
            beltype: String::from("SEIO33_CORE"),
            pins: vec![
                inout_m!(&postfix, "B", "PAD", "top level pad signal"),
                input_m!(
                    &postfix,
                    "I",
                    "PADDO",
                    "output buffer input from fabric/IOLOGIC"
                ),
                input_m!(
                    &postfix,
                    "T",
                    "PADDT",
                    "output buffer tristate (0=driven, 1=hi-z)"
                ),
                output_m!(
                    &postfix,
                    "O",
                    "PADDI",
                    "input buffer output to fabric/IOLOGIC"
                ),
                input!(&postfix, "I3CRESEN", "I3C strong pullup enable"),
                input!(&postfix, "I3CWKPU", "I3C weak pullup enable"),
            ],
            z: z as u32,
        }
    }

    pub fn make_seio18(z: usize) -> Bel {
        let ch = Z_TO_CHAR[z];
        let postfix = format!("SEIO18_CORE_IO{}", ch);
        Bel {
            name: format!("PIO{}", ch),
            beltype: String::from("SEIO18_CORE"),
            pins: vec![
                inout_m!(&postfix, "B", "IOPAD", "top level pad signal"),
                input_m!(
                    &postfix,
                    "I",
                    "PADDO",
                    "output buffer input from fabric/IOLOGIC"
                ),
                input_m!(
                    &postfix,
                    "T",
                    "PADDT",
                    "output buffer tristate (0=driven, 1=hi-z)"
                ),
                output_m!(
                    &postfix,
                    "O",
                    "PADDI",
                    "input buffer output to fabric/IOLOGIC"
                ),
                input!(&postfix, "DOLP", "DPHY LP mode output buffer input"),
                output!(&postfix, "INLP", "DPHY LP mode input buffer output"),
                output!(&postfix, "INADC", "analog signal out to ADC"),
            ],
            z: z as u32,
        }
    }

    pub fn make_osc_core() -> Bel {
        let postfix = format!("OSC_CORE");
        Bel {
            name: format!("OSC_CORE"),
            beltype: String::from("OSC_CORE"),
            pins: vec![
                output!(&postfix, "HFCLKOUT", "HF oscillator output", 0, 1),
                output!(&postfix, "LFCLKOUT", "LF oscillator output", 0, 1),
                input!(&postfix, "HFOUTEN", "HF oscillator output enable", 0, 1),
            ],
            z: 0,
        }
    }
}

pub fn get_tile_bels(tiletype: &str) -> Vec<Bel> {
    match tiletype {
        "PLC" => (0..4)
            .map(|slice| {
                let mut bels = vec![
                    Bel::make_oxide_comb(slice, 0),
                    Bel::make_oxide_comb(slice, 1),
                    Bel::make_oxide_ff(slice, 0),
                    Bel::make_oxide_ff(slice, 1),
                ];
                if slice == 2 {
                    bels.push(Bel::make_oxide_ramw(slice));
                }
                bels
            })
            .flatten()
            .collect(),
        "SYSIO_B0_0" | "SYSIO_B1_0" | "SYSIO_B1_0_C" | "SYSIO_B2_0" | "SYSIO_B2_0_C"
        | "SYSIO_B6_0" | "SYSIO_B6_0_C" | "SYSIO_B7_0" | "SYSIO_B7_0_C" => {
            (0..2).map(Bel::make_seio33).collect()
        }
        "SYSIO_B3_0" | "SYSIO_B4_0" | "SYSIO_B5_0" => (0..2).map(Bel::make_seio18).collect(),
        "EFB_1_OSC" => vec![Bel::make_osc_core()],
        _ => vec![],
    }
}
<commit_msg>Fix SEIO18 bels<commit_after>// A reference to a wire in a relatively located tile
#[derive(Clone)]
pub struct RelWire {
    pub rel_x: i32,   // (bel.x + rel_x == tile.x)
    pub rel_y: i32,   // (bel.y + rel_y == tile.y)
    pub name: String, // wire name in tile
}

impl RelWire {
    pub fn rel_name(&self) -> String {
        let mut name = String::new();
        if self.rel_y < 0 {
            name.push_str(&format!("N{}", -self.rel_y));
        }
        if self.rel_y > 0 {
            name.push_str(&format!("S{}", self.rel_y));
        }
        if self.rel_x < 0 {
            name.push_str(&format!("W{}", -self.rel_x));
        }
        if self.rel_x > 0 {
            name.push_str(&format!("E{}", self.rel_x));
        }
        if !name.is_empty() {
            name.push(':');
        }
        name.push_str(&self.name);
        name
    }
}

#[derive(Eq, PartialEq, Clone)]
pub enum PinDir {
    INPUT = 0,
    OUTPUT = 1,
    INOUT = 2,
}

#[derive(Clone)]
pub struct BelPin {
    pub name: String,  // name of pin on bel
    pub desc: String,  // description for documentation
    pub dir: PinDir,   // direction
    pub wire: RelWire, // reference to wire in tile
}

impl BelPin {
    pub fn new(
        name: &str,
        desc: &str,
        dir: PinDir,
        wirename: &str,
        rel_x: i32,
        rel_y: i32,
    ) -> BelPin {
        BelPin {
            name: name.to_string(),
            desc: desc.to_string(),
            dir: dir,
            wire: RelWire {
                rel_x: rel_x,
                rel_y: rel_y,
                name: wirename.to_string(),
            },
        }
    }

    // Standard postfixed wirename scheme
    pub fn new_p(
        name: &str,
        desc: &str,
        dir: PinDir,
        postfix: &str,
        rel_x: i32,
        rel_y: i32,
    ) -> BelPin {
        BelPin {
            name: name.to_string(),
            desc: desc.to_string(),
            dir: dir,
            wire: RelWire {
                rel_x: rel_x,
                rel_y: rel_y,
                name: format!("J{}_{}", name, postfix),
            },
        }
    }
    // Logical->physical mapped postfixed wirename scheme
    pub fn new_mapped(
        name: &str,
        desc: &str,
        dir: PinDir,
        physpin: &str,
        postfix: &str,
        rel_x: i32,
        rel_y: i32,
    ) -> BelPin {
        BelPin {
            name: name.to_string(),
            desc: desc.to_string(),
            dir: dir,
            wire: RelWire {
                rel_x: rel_x,
                rel_y: rel_y,
                name: format!("J{}_{}", physpin, postfix),
            },
        }
    }
}

pub struct Bel {
    pub name: String,
    pub beltype: String,
    pub pins: Vec<BelPin>,
    pub z: u32,
}

// Macros for common cases
macro_rules! input {
	($($rest:expr),*) =>
		( def_pin!(PinDir::INPUT, $($rest),*) );
}

macro_rules! output {
	($($rest:expr),*) =>
		( def_pin!(PinDir::OUTPUT, $($rest),*) );
}

macro_rules! def_pin {
    ($dir: expr, $postfix: expr, $name: expr) => {
        BelPin::new_p($name, "", $dir, $postfix, 0, 0)
    };

    ($dir: expr,$postfix: expr, $name: expr, $desc: expr) => {
        BelPin::new_p($name, $desc, $dir, $postfix, 0, 0)
    };
    ($dir: expr,$postfix: expr, $name: expr, $desc: expr, $rel_x: expr, $rel_y: expr) => {
        BelPin::new_p($name, $desc, $dir, $postfix, $rel_x, $rel_y)
    };
}

macro_rules! input_m {
    ($($rest:expr),*) =>
        ( def_pin_mapped!(PinDir::INPUT, $($rest),*) );
}

macro_rules! output_m {
    ($($rest:expr),*) =>
        ( def_pin_mapped!(PinDir::OUTPUT, $($rest),*) );
}

macro_rules! inout_m {
    ($($rest:expr),*) =>
        ( def_pin_mapped!(PinDir::INOUT, $($rest),*) );
}

macro_rules! def_pin_mapped {
    ($dir: expr, $postfix: expr, $name: expr) => {
        BelPin::new_p($name, "", $dir, $physpin, $postfix, 0, 0)
    };

    ($dir: expr,$postfix: expr, $name: expr, $physpin: expr, $desc: expr) => {
        BelPin::new_mapped($name, $desc, $dir, $physpin, $postfix, 0, 0)
    };
}

const Z_TO_CHAR: [char; 4] = ['A', 'B', 'C', 'D'];

impl Bel {
    pub fn make_oxide_ff(slice: usize, ff: usize) -> Bel {
        let ch = Z_TO_CHAR[slice];
        let postfix = format!("SLICE{}", ch);
        let pins = vec![
            input!(&postfix, "CLK", "FF clock"),
            input!(&postfix, "CE", "FF clock enable"),
            input!(&postfix, "LSR", "FF local set/reset"),
            input_m!(
                &postfix,
                "DI",
                &format!("DI{}", ff),
                "FF input from LUT/MUX output"
            ),
            input_m!(
                &postfix,
                "M",
                &format!("M{}", ff),
                "FF direct input from fabric M signal"
            ),
            output_m!(&postfix, "Q", &format!("Q{}", ff), "FF output"),
        ];
        Bel {
            name: format!("{}_FF{}", &postfix, ff),
            beltype: String::from("OXIDE_FF"),
            pins: pins,
            z: (slice << 3 | (ff + 2)) as u32,
        }
    }

    pub fn make_oxide_comb(slice: usize, lut: usize) -> Bel {
        let ch = Z_TO_CHAR[slice];
        let postfix = format!("SLICE{}", ch);
        let mut pins = vec![
            input_m!(&postfix, "A", &format!("A{}", lut), "LUT A input"),
            input_m!(&postfix, "B", &format!("B{}", lut), "LUT B input"),
            input_m!(&postfix, "C", &format!("C{}", lut), "LUT C input"),
            input_m!(&postfix, "D", &format!("D{}", lut), "LUT D input"),
            input_m!(
                &postfix,
                "FCI",
                if lut == 0 { "FCI" } else { "INT_CARRY" },
                "CCU2 fast carry input"
            ),
            output_m!(&postfix, "F", &format!("F{}", lut), "LUT/sum output"),
            output_m!(
                &postfix,
                "FCO",
                if lut == 1 { "FCO" } else { "INT_CARRY" },
                "CCU2 fast carry output"
            ),
        ];
        if lut == 0 {
            // MUX2 in LUT0 COMB only
            pins.append(&mut vec![
                input!(&postfix, "SEL", "MUX2 select input"),
                input!(&postfix, "F1", "input from second LUT to MUX2"),
                output_m!(&postfix, "OFX", "OFX0", "MUX2 output"),
            ]);
        }
        if slice == 0 || slice == 1 {
            // DPRAM in lower two SLICEs only
            pins.append(&mut vec![
                input!(&postfix, "WAD0", "LUTRAM write address 0 (from RAMW)"),
                input!(&postfix, "WAD1", "LUTRAM write address 1 (from RAMW)"),
                input!(&postfix, "WAD2", "LUTRAM write address 2 (from RAMW)"),
                input!(&postfix, "WAD3", "LUTRAM write address 3 (from RAMW)"),
                input_m!(
                    &postfix,
                    "WD",
                    &format!("WD{}", lut),
                    "LUTRAM write data (from RAMW)"
                ),
                input!(&postfix, "WCK", "LUTRAM write clock (from RAMW)"),
                input!(&postfix, "WRE", "LUTRAM write enable (from RAMW)"),
            ]);
        }
        Bel {
            name: format!("{}_LUT{}", &postfix, lut),
            beltype: String::from("OXIDE_COMB"),
            pins: pins,
            z: (slice << 3 | lut) as u32,
        }
    }

    pub fn make_oxide_ramw(slice: usize) -> Bel {
        assert_eq!(slice, 2);
        let ch = Z_TO_CHAR[slice];
        let postfix = format!("SLICE{}", ch);
        let pins = vec![
            input!(&postfix, "A0", "buffered to WADO3"),
            input!(&postfix, "A1", "buffered to WDO2"),
            input!(&postfix, "B0", "buffered to WADO1"),
            input!(&postfix, "B1", "buffered to WDO3"),
            input!(&postfix, "C0", "buffered to WADO2"),
            input!(&postfix, "C1", "buffered to WDO1"),
            input!(&postfix, "D0", "buffered to WADO0"),
            input!(&postfix, "D1", "buffered to WDO0"),
            input!(&postfix, "CLK", "buffered to WCKO"),
            input!(&postfix, "LSR", "buffered to WREO"),
            output!(&postfix, "WADO0", "LUTRAM write address 0 (to SLICEA/B)"),
            output!(&postfix, "WADO1", "LUTRAM write address 1 (to SLICEA/B)"),
            output!(&postfix, "WADO2", "LUTRAM write address 2 (to SLICEA/B)"),
            output!(&postfix, "WADO3", "LUTRAM write address 3 (to SLICEA/B)"),
            output!(&postfix, "WCKO", "LUTRAM write clock (to SLICEA/B)"),
            output!(&postfix, "WREO", "LUTRAM write enable (to SLICEA/B)"),
            output!(&postfix, "WDO0", "LUTRAM write data 0 (to SLICEA)"),
            output!(&postfix, "WDO1", "LUTRAM write data 1 (to SLICEA)"),
            output!(&postfix, "WDO2", "LUTRAM write data 2 (to SLICEB)"),
            output!(&postfix, "WDO3", "LUTRAM write data 3 (to SLICEB)"),
        ];
        Bel {
            name: format!("{}_RAMW", &postfix),
            beltype: String::from("RAMW"),
            pins: pins,
            z: (slice << 3 | 4) as u32,
        }
    }

    pub fn make_seio33(z: usize) -> Bel {
        let ch = Z_TO_CHAR[z];
        let postfix = format!("SEIO33_CORE_IO{}", ch);
        Bel {
            name: format!("PIO{}", ch),
            beltype: String::from("SEIO33_CORE"),
            pins: vec![
                inout_m!(&postfix, "B", "PAD", "top level pad signal"),
                input_m!(
                    &postfix,
                    "I",
                    "PADDO",
                    "output buffer input from fabric/IOLOGIC"
                ),
                input_m!(
                    &postfix,
                    "T",
                    "PADDT",
                    "output buffer tristate (0=driven, 1=hi-z)"
                ),
                output_m!(
                    &postfix,
                    "O",
                    "PADDI",
                    "input buffer output to fabric/IOLOGIC"
                ),
                input!(&postfix, "I3CRESEN", "I3C strong pullup enable"),
                input!(&postfix, "I3CWKPU", "I3C weak pullup enable"),
            ],
            z: z as u32,
        }
    }

    pub fn make_seio18(z: usize) -> Bel {
        let ch = Z_TO_CHAR[z];
        let postfix = if z == 1 {
            format!("SEIO18_CORE_IO{}", ch)
        } else {
            format!("DIFFIO18_CORE_IO{}", ch)
        };
        Bel {
            name: format!("PIO{}", ch),
            beltype: String::from("SEIO18_CORE"),
            pins: vec![
                inout_m!(&postfix, "B", "IOPAD", "top level pad signal"),
                input_m!(
                    &postfix,
                    "I",
                    "PADDO",
                    "output buffer input from fabric/IOLOGIC"
                ),
                input_m!(
                    &postfix,
                    "T",
                    "PADDT",
                    "output buffer tristate (0=driven, 1=hi-z)"
                ),
                output_m!(
                    &postfix,
                    "O",
                    "PADDI",
                    "input buffer output to fabric/IOLOGIC"
                ),
                input!(&postfix, "DOLP", "DPHY LP mode output buffer input"),
                output!(&postfix, "INLP", "DPHY LP mode input buffer output"),
                output!(&postfix, "INADC", "analog signal out to ADC"),
            ],
            z: z as u32,
        }
    }

    pub fn make_osc_core() -> Bel {
        let postfix = format!("OSC_CORE");
        Bel {
            name: format!("OSC_CORE"),
            beltype: String::from("OSC_CORE"),
            pins: vec![
                output!(&postfix, "HFCLKOUT", "HF oscillator output", 0, 1),
                output!(&postfix, "LFCLKOUT", "LF oscillator output", 0, 1),
                input!(&postfix, "HFOUTEN", "HF oscillator output enable", 0, 1),
            ],
            z: 0,
        }
    }
}

pub fn get_tile_bels(tiletype: &str) -> Vec<Bel> {
    match tiletype {
        "PLC" => (0..4)
            .map(|slice| {
                let mut bels = vec![
                    Bel::make_oxide_comb(slice, 0),
                    Bel::make_oxide_comb(slice, 1),
                    Bel::make_oxide_ff(slice, 0),
                    Bel::make_oxide_ff(slice, 1),
                ];
                if slice == 2 {
                    bels.push(Bel::make_oxide_ramw(slice));
                }
                bels
            })
            .flatten()
            .collect(),
        "SYSIO_B0_0" | "SYSIO_B1_0" | "SYSIO_B1_0_C" | "SYSIO_B2_0" | "SYSIO_B2_0_C"
        | "SYSIO_B6_0" | "SYSIO_B6_0_C" | "SYSIO_B7_0" | "SYSIO_B7_0_C" => {
            (0..2).map(Bel::make_seio33).collect()
        }
        "SYSIO_B3_0" | "SYSIO_B4_0" | "SYSIO_B5_0" => (0..2).map(Bel::make_seio18).collect(),
        "EFB_1_OSC" => vec![Bel::make_osc_core()],
        _ => vec![],
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::ptr;

use gdk_pixbuf::{Colorspace, Pixbuf};
use gio::prelude::*;
use glib::translate::*;
use url::Url;

use rsvg_internals::{
    Dpi, Handle, IRect, LoadOptions, LoadingError, Pixels, RenderingError, RsvgDimensionData,
    SharedImageSurface, SizeCallback, SurfaceType,
};

use crate::c_api::set_gerror;

fn pixbuf_new(width: i32, height: i32) -> Result<Pixbuf, RenderingError> {
    assert!(width > 0 && height > 0);

    Pixbuf::new(Colorspace::Rgb, true, 8, width, height).ok_or(RenderingError::OutOfMemory)
}

pub fn empty_pixbuf() -> Result<Pixbuf, RenderingError> {
    // GdkPixbuf does not allow zero-sized pixbufs, but Cairo allows zero-sized
    // surfaces.  In this case, return a 1-pixel transparent pixbuf.

    let pixbuf = pixbuf_new(1, 1)?;
    pixbuf.put_pixel(0, 0, 0, 0, 0, 0);

    Ok(pixbuf)
}

pub fn pixbuf_from_surface(surface: &SharedImageSurface) -> Result<Pixbuf, RenderingError> {
    let width = surface.width();
    let height = surface.height();

    let pixbuf = pixbuf_new(width, height)?;
    let bounds = IRect::from_size(width, height);

    for (x, y, pixel) in Pixels::within(&surface, bounds) {
        let (r, g, b, a) = if pixel.a == 0 {
            (0, 0, 0, 0)
        } else {
            let pixel = pixel.unpremultiply();
            (pixel.r, pixel.g, pixel.b, pixel.a)
        };

        // FIXME: Use pixbuf.put_pixel when
        // https://github.com/gtk-rs/gdk-pixbuf/issues/147
        // is integrated
        my_put_pixel(&pixbuf, x as i32, y as i32, r, g, b, a);
    }

    Ok(pixbuf)
}

// Copied from gtk-rs/gdk-pixbuf
//
// See the following:
//   https://gitlab.gnome.org/GNOME/librsvg/-/issues/584
//   https://github.com/gtk-rs/gdk-pixbuf/issues/147
//
// Arithmetic can overflow in the computation of `pos` if it is not done with usize
// values (everything coming out of a Pixbuf is i32).
//
// When this fix appears in a gtk-rs release, we can remove this.
fn my_put_pixel(pixbuf: &Pixbuf, x: i32, y: i32, red: u8, green: u8, blue: u8, alpha: u8) {
    unsafe {
        let x = x as usize;
        let y = y as usize;
        let n_channels = pixbuf.get_n_channels() as usize;
        assert!(n_channels == 3 || n_channels == 4);
        let rowstride = pixbuf.get_rowstride() as usize;
        let pixels = pixbuf.get_pixels();
        let pos = y * rowstride + x * n_channels;

        pixels[pos] = red;
        pixels[pos + 1] = green;
        pixels[pos + 2] = blue;
        if n_channels == 4 {
            pixels[pos + 3] = alpha;
        }
    }
}

enum SizeKind {
    Zoom,
    WidthHeight,
    WidthHeightMax,
    ZoomMax,
}

struct SizeMode {
    kind: SizeKind,
    x_zoom: f64,
    y_zoom: f64,
    width: i32,
    height: i32,
}

fn get_final_size(dimensions: &RsvgDimensionData, size_mode: &SizeMode) -> (i32, i32) {
    if dimensions.width == 0 || dimensions.height == 0 {
        return (0, 0);
    }

    let in_width = dimensions.width;
    let in_height = dimensions.height;

    let mut out_width;
    let mut out_height;

    match size_mode.kind {
        SizeKind::Zoom => {
            out_width = (size_mode.x_zoom * f64::from(in_width) + 0.5).floor() as i32;
            out_height = (size_mode.y_zoom * f64::from(in_height) + 0.5).floor() as i32;
        }

        SizeKind::ZoomMax => {
            out_width = (size_mode.x_zoom * f64::from(in_width) + 0.5).floor() as i32;
            out_height = (size_mode.y_zoom * f64::from(in_height) + 0.5).floor() as i32;

            if out_width > size_mode.width || out_height > size_mode.height {
                let zoom_x = f64::from(size_mode.width) / f64::from(out_width);
                let zoom_y = f64::from(size_mode.height) / f64::from(out_height);
                let zoom = zoom_x.min(zoom_y);

                out_width = (zoom * f64::from(out_width) + 0.5) as i32;
                out_height = (zoom * f64::from(out_height) + 0.5) as i32;
            }
        }

        SizeKind::WidthHeightMax => {
            let zoom_x = f64::from(size_mode.width) / f64::from(in_width);
            let zoom_y = f64::from(size_mode.height) / f64::from(in_height);

            let zoom = zoom_x.min(zoom_y);

            out_width = (zoom * f64::from(in_width) + 0.5) as i32;
            out_height = (zoom * f64::from(in_height) + 0.5) as i32;
        }

        SizeKind::WidthHeight => {
            if size_mode.width != -1 {
                out_width = size_mode.width;
            } else {
                out_width = in_width;
            }

            if size_mode.height != -1 {
                out_height = size_mode.height;
            } else {
                out_height = in_height;
            }
        }
    }

    (out_width, out_height)
}

fn render_to_pixbuf_at_size(
    handle: &Handle,
    dimensions: &RsvgDimensionData,
    width: i32,
    height: i32,
    dpi: Dpi,
) -> Result<Pixbuf, RenderingError> {
    if width == 0 || height == 0 || dimensions.width == 0 || dimensions.height == 0 {
        return empty_pixbuf();
    }

    let surface = cairo::ImageSurface::create(cairo::Format::ARgb32, width, height)?;

    {
        let cr = cairo::Context::new(&surface);
        cr.scale(
            f64::from(width) / f64::from(dimensions.width),
            f64::from(height) / f64::from(dimensions.height),
        );

        let viewport = cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: f64::from(dimensions.width),
            height: f64::from(dimensions.height),
        };

        handle.render_document(&cr, &viewport, dpi, false)?;
    }

    let shared_surface = SharedImageSurface::wrap(surface, SurfaceType::SRgb)?;

    pixbuf_from_surface(&shared_surface)
}

fn get_default_dpi() -> Dpi {
    // This is ugly, but it preserves the C API semantics of
    //
    //   rsvg_set_default_dpi(...);
    //   pixbuf = rsvg_pixbuf_from_file(...);
    //
    // Passing negative numbers here means that the global default DPI will be used.
    Dpi::new(-1.0, -1.0)
}

fn url_from_file(file: &gio::File) -> Result<Url, LoadingError> {
    Ok(Url::parse(&file.get_uri()).map_err(|_| LoadingError::BadUrl)?)
}

fn pixbuf_from_file_with_size_mode(
    filename: *const libc::c_char,
    size_mode: &SizeMode,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    let dpi = get_default_dpi();

    unsafe {
        let path = PathBuf::from_glib_none(filename);
        let file = gio::File::new_for_path(path);

        let base_url = match url_from_file(&file) {
            Ok(url) => url,
            Err(e) => {
                set_gerror(error, 0, &format!("{}", e));
                return ptr::null_mut();
            }
        };

        let load_options = LoadOptions::new(Some(base_url));

        let cancellable: Option<&gio::Cancellable> = None;
        let handle = match file
            .read(cancellable)
            .map_err(|e| LoadingError::from(e))
            .and_then(|stream| Handle::from_stream(&load_options, stream.as_ref(), None))
        {
            Ok(handle) => handle,
            Err(e) => {
                set_gerror(error, 0, &format!("{}", e));
                return ptr::null_mut();
            }
        };

        handle
            .get_dimensions_sub(None, dpi, &SizeCallback::default(), false)
            .and_then(|dimensions| {
                let (width, height) = get_final_size(&dimensions, size_mode);

                render_to_pixbuf_at_size(&handle, &dimensions, width, height, dpi)
            })
            .and_then(|pixbuf| Ok(pixbuf.to_glib_full()))
            .unwrap_or_else(|e| {
                set_gerror(error, 0, &format!("{}", e));
                ptr::null_mut()
            })
    }
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_rust_pixbuf_from_file_at_size(
    filename: *const libc::c_char,
    width: i32,
    height: i32,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    rsvg_return_val_if_fail! {
        rsvg_pixbuf_from_file_at_size => ptr::null_mut();

        !filename.is_null(),
        (width >= 1 && height >= 1) || (width == -1 && height == -1),
        error.is_null() || (*error).is_null(),
    }

    pixbuf_from_file_with_size_mode(
        filename,
        &SizeMode {
            kind: SizeKind::WidthHeight,
            x_zoom: 0.0,
            y_zoom: 0.0,
            width,
            height,
        },
        error,
    )
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_rust_pixbuf_from_file_at_zoom(
    filename: *const libc::c_char,
    x_zoom: f64,
    y_zoom: f64,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    rsvg_return_val_if_fail! {
        rsvg_pixbuf_from_file_at_zoom => ptr::null_mut();

        !filename.is_null(),
        x_zoom > 0.0 && y_zoom > 0.0,
        error.is_null() || (*error).is_null(),
    }

    pixbuf_from_file_with_size_mode(
        filename,
        &SizeMode {
            kind: SizeKind::Zoom,
            x_zoom,
            y_zoom,
            width: 0,
            height: 0,
        },
        error,
    )
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_rust_pixbuf_from_file_at_zoom_with_max(
    filename: *const libc::c_char,
    x_zoom: f64,
    y_zoom: f64,
    max_width: i32,
    max_height: i32,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    rsvg_return_val_if_fail! {
        rsvg_pixbuf_from_file_at_zoom_with_max => ptr::null_mut();

        !filename.is_null(),
        x_zoom > 0.0 && y_zoom > 0.0,
        max_width >= 1 && max_height >= 1,
        error.is_null() || (*error).is_null(),
    }

    pixbuf_from_file_with_size_mode(
        filename,
        &SizeMode {
            kind: SizeKind::ZoomMax,
            x_zoom,
            y_zoom,
            width: max_width,
            height: max_height,
        },
        error,
    )
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_rust_pixbuf_from_file_at_max_size(
    filename: *const libc::c_char,
    max_width: i32,
    max_height: i32,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    rsvg_return_val_if_fail! {
        rsvg_pixbuf_from_file_at_max_size => ptr::null_mut();

        !filename.is_null(),
        max_width >= 1 && max_height >= 1,
        error.is_null() || (*error).is_null(),
    }

    pixbuf_from_file_with_size_mode(
        filename,
        &SizeMode {
            kind: SizeKind::WidthHeightMax,
            x_zoom: 0.0,
            y_zoom: 0.0,
            width: max_width,
            height: max_height,
        },
        error,
    )
}
<commit_msg>pixbuf_utils: get rid of RsvgDimensionData as early as possible<commit_after>use std::path::PathBuf;
use std::ptr;

use gdk_pixbuf::{Colorspace, Pixbuf};
use gio::prelude::*;
use glib::translate::*;
use url::Url;

use rsvg_internals::{
    Dpi, Handle, IRect, LoadOptions, LoadingError, Pixels, RenderingError, SharedImageSurface,
    SizeCallback, SurfaceType,
};

use crate::c_api::set_gerror;

fn pixbuf_new(width: i32, height: i32) -> Result<Pixbuf, RenderingError> {
    assert!(width > 0 && height > 0);

    Pixbuf::new(Colorspace::Rgb, true, 8, width, height).ok_or(RenderingError::OutOfMemory)
}

pub fn empty_pixbuf() -> Result<Pixbuf, RenderingError> {
    // GdkPixbuf does not allow zero-sized pixbufs, but Cairo allows zero-sized
    // surfaces.  In this case, return a 1-pixel transparent pixbuf.

    let pixbuf = pixbuf_new(1, 1)?;
    pixbuf.put_pixel(0, 0, 0, 0, 0, 0);

    Ok(pixbuf)
}

pub fn pixbuf_from_surface(surface: &SharedImageSurface) -> Result<Pixbuf, RenderingError> {
    let width = surface.width();
    let height = surface.height();

    let pixbuf = pixbuf_new(width, height)?;
    let bounds = IRect::from_size(width, height);

    for (x, y, pixel) in Pixels::within(&surface, bounds) {
        let (r, g, b, a) = if pixel.a == 0 {
            (0, 0, 0, 0)
        } else {
            let pixel = pixel.unpremultiply();
            (pixel.r, pixel.g, pixel.b, pixel.a)
        };

        // FIXME: Use pixbuf.put_pixel when
        // https://github.com/gtk-rs/gdk-pixbuf/issues/147
        // is integrated
        my_put_pixel(&pixbuf, x as i32, y as i32, r, g, b, a);
    }

    Ok(pixbuf)
}

// Copied from gtk-rs/gdk-pixbuf
//
// See the following:
//   https://gitlab.gnome.org/GNOME/librsvg/-/issues/584
//   https://github.com/gtk-rs/gdk-pixbuf/issues/147
//
// Arithmetic can overflow in the computation of `pos` if it is not done with usize
// values (everything coming out of a Pixbuf is i32).
//
// When this fix appears in a gtk-rs release, we can remove this.
fn my_put_pixel(pixbuf: &Pixbuf, x: i32, y: i32, red: u8, green: u8, blue: u8, alpha: u8) {
    unsafe {
        let x = x as usize;
        let y = y as usize;
        let n_channels = pixbuf.get_n_channels() as usize;
        assert!(n_channels == 3 || n_channels == 4);
        let rowstride = pixbuf.get_rowstride() as usize;
        let pixels = pixbuf.get_pixels();
        let pos = y * rowstride + x * n_channels;

        pixels[pos] = red;
        pixels[pos + 1] = green;
        pixels[pos + 2] = blue;
        if n_channels == 4 {
            pixels[pos + 3] = alpha;
        }
    }
}

enum SizeKind {
    Zoom,
    WidthHeight,
    WidthHeightMax,
    ZoomMax,
}

struct SizeMode {
    kind: SizeKind,
    x_zoom: f64,
    y_zoom: f64,
    width: i32,
    height: i32,
}

fn get_final_size(in_width: i32, in_height: i32, size_mode: &SizeMode) -> (i32, i32) {
    if in_width == 0 || in_height == 0 {
        return (0, 0);
    }

    let mut out_width;
    let mut out_height;

    match size_mode.kind {
        SizeKind::Zoom => {
            out_width = (size_mode.x_zoom * f64::from(in_width) + 0.5).floor() as i32;
            out_height = (size_mode.y_zoom * f64::from(in_height) + 0.5).floor() as i32;
        }

        SizeKind::ZoomMax => {
            out_width = (size_mode.x_zoom * f64::from(in_width) + 0.5).floor() as i32;
            out_height = (size_mode.y_zoom * f64::from(in_height) + 0.5).floor() as i32;

            if out_width > size_mode.width || out_height > size_mode.height {
                let zoom_x = f64::from(size_mode.width) / f64::from(out_width);
                let zoom_y = f64::from(size_mode.height) / f64::from(out_height);
                let zoom = zoom_x.min(zoom_y);

                out_width = (zoom * f64::from(out_width) + 0.5) as i32;
                out_height = (zoom * f64::from(out_height) + 0.5) as i32;
            }
        }

        SizeKind::WidthHeightMax => {
            let zoom_x = f64::from(size_mode.width) / f64::from(in_width);
            let zoom_y = f64::from(size_mode.height) / f64::from(in_height);

            let zoom = zoom_x.min(zoom_y);

            out_width = (zoom * f64::from(in_width) + 0.5) as i32;
            out_height = (zoom * f64::from(in_height) + 0.5) as i32;
        }

        SizeKind::WidthHeight => {
            if size_mode.width != -1 {
                out_width = size_mode.width;
            } else {
                out_width = in_width;
            }

            if size_mode.height != -1 {
                out_height = size_mode.height;
            } else {
                out_height = in_height;
            }
        }
    }

    (out_width, out_height)
}

fn render_to_pixbuf_at_size(
    handle: &Handle,
    document_width: i32,
    document_height: i32,
    desired_width: i32,
    desired_height: i32,
    dpi: Dpi,
) -> Result<Pixbuf, RenderingError> {
    if desired_width == 0 || desired_height == 0 || document_width == 0 || document_height == 0 {
        return empty_pixbuf();
    }

    let surface =
        cairo::ImageSurface::create(cairo::Format::ARgb32, desired_width, desired_height)?;

    {
        let cr = cairo::Context::new(&surface);
        cr.scale(
            f64::from(desired_width) / f64::from(document_width),
            f64::from(desired_height) / f64::from(document_height),
        );

        let viewport = cairo::Rectangle {
            x: 0.0,
            y: 0.0,
            width: f64::from(document_width),
            height: f64::from(document_height),
        };

        // We do it with a cr transform so we can scale non-proportionally.
        handle.render_document(&cr, &viewport, dpi, false)?;
    }

    let shared_surface = SharedImageSurface::wrap(surface, SurfaceType::SRgb)?;

    pixbuf_from_surface(&shared_surface)
}

fn get_default_dpi() -> Dpi {
    // This is ugly, but it preserves the C API semantics of
    //
    //   rsvg_set_default_dpi(...);
    //   pixbuf = rsvg_pixbuf_from_file(...);
    //
    // Passing negative numbers here means that the global default DPI will be used.
    Dpi::new(-1.0, -1.0)
}

fn url_from_file(file: &gio::File) -> Result<Url, LoadingError> {
    Ok(Url::parse(&file.get_uri()).map_err(|_| LoadingError::BadUrl)?)
}

fn pixbuf_from_file_with_size_mode(
    filename: *const libc::c_char,
    size_mode: &SizeMode,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    let dpi = get_default_dpi();

    unsafe {
        let path = PathBuf::from_glib_none(filename);
        let file = gio::File::new_for_path(path);

        let base_url = match url_from_file(&file) {
            Ok(url) => url,
            Err(e) => {
                set_gerror(error, 0, &format!("{}", e));
                return ptr::null_mut();
            }
        };

        let load_options = LoadOptions::new(Some(base_url));

        let cancellable: Option<&gio::Cancellable> = None;
        let handle = match file
            .read(cancellable)
            .map_err(|e| LoadingError::from(e))
            .and_then(|stream| Handle::from_stream(&load_options, stream.as_ref(), None))
        {
            Ok(handle) => handle,
            Err(e) => {
                set_gerror(error, 0, &format!("{}", e));
                return ptr::null_mut();
            }
        };

        handle
            .get_dimensions_sub(None, dpi, &SizeCallback::default(), false)
            .and_then(|dimensions| {
                let (document_width, document_height) = (dimensions.width, dimensions.height);
                let (desired_width, desired_height) =
                    get_final_size(document_width, document_height, size_mode);

                render_to_pixbuf_at_size(
                    &handle,
                    document_width,
                    document_height,
                    desired_width,
                    desired_height,
                    dpi,
                )
            })
            .and_then(|pixbuf| Ok(pixbuf.to_glib_full()))
            .unwrap_or_else(|e| {
                set_gerror(error, 0, &format!("{}", e));
                ptr::null_mut()
            })
    }
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_rust_pixbuf_from_file_at_size(
    filename: *const libc::c_char,
    width: i32,
    height: i32,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    rsvg_return_val_if_fail! {
        rsvg_pixbuf_from_file_at_size => ptr::null_mut();

        !filename.is_null(),
        (width >= 1 && height >= 1) || (width == -1 && height == -1),
        error.is_null() || (*error).is_null(),
    }

    pixbuf_from_file_with_size_mode(
        filename,
        &SizeMode {
            kind: SizeKind::WidthHeight,
            x_zoom: 0.0,
            y_zoom: 0.0,
            width,
            height,
        },
        error,
    )
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_rust_pixbuf_from_file_at_zoom(
    filename: *const libc::c_char,
    x_zoom: f64,
    y_zoom: f64,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    rsvg_return_val_if_fail! {
        rsvg_pixbuf_from_file_at_zoom => ptr::null_mut();

        !filename.is_null(),
        x_zoom > 0.0 && y_zoom > 0.0,
        error.is_null() || (*error).is_null(),
    }

    pixbuf_from_file_with_size_mode(
        filename,
        &SizeMode {
            kind: SizeKind::Zoom,
            x_zoom,
            y_zoom,
            width: 0,
            height: 0,
        },
        error,
    )
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_rust_pixbuf_from_file_at_zoom_with_max(
    filename: *const libc::c_char,
    x_zoom: f64,
    y_zoom: f64,
    max_width: i32,
    max_height: i32,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    rsvg_return_val_if_fail! {
        rsvg_pixbuf_from_file_at_zoom_with_max => ptr::null_mut();

        !filename.is_null(),
        x_zoom > 0.0 && y_zoom > 0.0,
        max_width >= 1 && max_height >= 1,
        error.is_null() || (*error).is_null(),
    }

    pixbuf_from_file_with_size_mode(
        filename,
        &SizeMode {
            kind: SizeKind::ZoomMax,
            x_zoom,
            y_zoom,
            width: max_width,
            height: max_height,
        },
        error,
    )
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_rust_pixbuf_from_file_at_max_size(
    filename: *const libc::c_char,
    max_width: i32,
    max_height: i32,
    error: *mut *mut glib_sys::GError,
) -> *mut gdk_pixbuf_sys::GdkPixbuf {
    rsvg_return_val_if_fail! {
        rsvg_pixbuf_from_file_at_max_size => ptr::null_mut();

        !filename.is_null(),
        max_width >= 1 && max_height >= 1,
        error.is_null() || (*error).is_null(),
    }

    pixbuf_from_file_with_size_mode(
        filename,
        &SizeMode {
            kind: SizeKind::WidthHeightMax,
            x_zoom: 0.0,
            y_zoom: 0.0,
            width: max_width,
            height: max_height,
        },
        error,
    )
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]
#![feature(phase)]

#![unstable]

#[phase(plugin)]
extern crate compile_msg;

extern crate libc;

#[doc(hidden)]
pub mod ffi;

///
#[doc(hidden)]
pub static mut android_app: *mut ffi::android_app = 0 as *mut ffi::android_app;

#[cfg(not(target_os = "android"))]
compile_note!("You are not compiling for Android")

#[macro_export]
macro_rules! android_start(
    ($main: ident) => (
        pub mod __android_start {
            extern crate android_glue;
            extern crate libc;
            extern crate native;

            // this function is here because we are sure that it will be included by the linker
            // so we call app_dummy in it, in order to be sure that the native glue will be included
            #[start]
            pub fn start(_: int, _: *const *const u8) -> int {
                unsafe { android_glue::ffi::app_dummy() };
                1
            }

            #[no_mangle]
            #[inline(never)]
            #[allow(non_snake_case)]
            pub extern "C" fn android_main(app: *mut android_glue::ffi::android_app) {
                use self::native::NativeTaskBuilder;
                use std::task::TaskBuilder;

                unsafe { android_glue::android_app = app };

                android_glue::write_log("ANativeActivity_onCreate has been called");

                unsafe { android_glue::ffi::app_dummy() };

                native::start(1, &b"".as_ptr(), proc() {
                    TaskBuilder::new().native().spawn(proc() {
                        super::$main();
                    });
                });
            }
        }
    )
)

/// Returns a handle to the native window.
pub fn get_native_window() -> ffi::NativeWindowType {
    unsafe { (*android_app).window }
}

///
pub fn write_log(message: &str) {
    message.with_c_str(|message| {
        b"RustAndroidGlue".with_c_str(|tag| {
            unsafe { ffi::__android_log_write(3, tag, message) };
        });
    });
}
<commit_msg>Improve android_app* handling<commit_after>#![feature(macro_rules)]
#![feature(phase)]

#![unstable]

#[phase(plugin)]
extern crate compile_msg;

extern crate libc;

#[doc(hidden)]
pub mod ffi;

/// This static variable is public because it needs to be accessible from the
///  macros in user code.
///
/// It will store the android_app* on creation, and set it back to 0 at destruction.
/// Apart from this, the static is never written, so there is no risk of race condition.
#[doc(hidden)]
pub static mut android_app: *mut ffi::android_app = 0 as *mut ffi::android_app;

#[cfg(not(target_os = "android"))]
compile_note!("You are not compiling for Android")

#[macro_export]
macro_rules! android_start(
    ($main: ident) => (
        pub mod __android_start {
            extern crate android_glue;
            extern crate libc;
            extern crate native;

            // this function is here because we are sure that it will be included by the linker
            // so we call app_dummy in it, in order to be sure that the native glue will be included
            #[start]
            pub fn start(_: int, _: *const *const u8) -> int {
                unsafe { android_glue::ffi::app_dummy() };
                1
            }

            #[no_mangle]
            #[inline(never)]
            #[allow(non_snake_case)]
            pub extern "C" fn android_main(app: *mut android_glue::ffi::android_app) {
                use self::native::NativeTaskBuilder;
                use std::task::TaskBuilder;

                unsafe { android_glue::android_app = app };

                android_glue::write_log("ANativeActivity_onCreate has been called");

                unsafe { android_glue::ffi::app_dummy() };

                native::start(1, &b"".as_ptr(), proc() {
                    super::$main();
                });

                unsafe { android_glue::android_app = 0 as *mut android_glue::ffi::android_app };
            }
        }
    )
)

/// Returns a handle to the native window.
pub unsafe fn get_native_window() -> ffi::NativeWindowType {
    if android_app.is_null() {
        fail!("The application was not initialized from android_main");
    }

    (*android_app).window
}

///
pub fn write_log(message: &str) {
    message.with_c_str(|message| {
        b"RustAndroidGlue".with_c_str(|tag| {
            unsafe { ffi::__android_log_write(3, tag, message) };
        });
    });
}
<|endoftext|>


<commit_before>use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::Vec;
use spin::Mutex;

use arch;
use super::file::File;
use super::memory::{Grant, Memory, SharedMemory};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Status {
    Runnable,
    Blocked,
    Exited(usize)
}

/// A context, which identifies either a process or a thread
#[derive(Debug)]
pub struct Context {
    /// The ID of this context
    pub id: usize,
    /// Status of context
    pub status: Status,
    /// Context running or not
    pub running: bool,
    /// The architecture specific context
    pub arch: arch::context::Context,
    /// Kernel FX
    pub kfx: Option<Box<[u8]>>,
    /// Kernel stack
    pub kstack: Option<Box<[u8]>>,
    /// Executable image
    pub image: Vec<SharedMemory>,
    /// User heap
    pub heap: Option<SharedMemory>,
    /// User stack
    pub stack: Option<Memory>,
    /// User grants
    pub grants: Arc<Mutex<Vec<Grant>>>,
    /// The current working directory
    pub cwd: Arc<Mutex<Vec<u8>>>,
    /// The open files in the scheme
    pub files: Arc<Mutex<Vec<Option<File>>>>
}

impl Context {
    /// Create a new context
    pub fn new(id: usize) -> Context {
        Context {
            id: id,
            status: Status::Blocked,
            running: false,
            arch: arch::context::Context::new(),
            kfx: None,
            kstack: None,
            image: Vec::new(),
            heap: None,
            stack: None,
            grants: Arc::new(Mutex::new(Vec::new())),
            cwd: Arc::new(Mutex::new(Vec::new())),
            files: Arc::new(Mutex::new(Vec::new()))
        }
    }

    pub fn canonicalize(&self, path: &[u8]) -> Vec<u8> {
        if path.iter().position(|&b| b == b':').is_none() {
            let cwd = self.cwd.lock();
            if path == b"." {
                cwd.clone()
            } else if path == b".." {
                cwd[..cwd[..cwd.len() - 1]
                                   .iter().rposition(|&b| b == b'/')
                                   .map_or(cwd.len(), |i| i + 1)]
                   .to_vec()
            } else if path.starts_with(b"./") {
                let mut canon = cwd.clone();
                canon.extend_from_slice(&path[2..]);
                canon
            } else if path.starts_with(b"../") {
                let mut canon = cwd[..cwd[..cwd.len() - 1]
                                   .iter().rposition(|&b| b == b'/')
                                   .map_or(cwd.len(), |i| i + 1)]
                   .to_vec();
                canon.extend_from_slice(&path[3..]);
                canon
            } else if path.starts_with(b"/") {
                let mut canon = cwd[..cwd.iter().position(|&b| b == b':').map_or(1, |i| i + 1)].to_vec();
                canon.extend_from_slice(&path);
                canon
            } else {
                let mut canon = cwd.clone();
                canon.extend_from_slice(&path);
                canon
            }
        } else {
            path.to_vec()
        }
    }

    /// Add a file to the lowest available slot.
    /// Return the file descriptor number or None if no slot was found
    pub fn add_file(&self, file: File) -> Option<usize> {
        let mut files = self.files.lock();
        for (i, mut file_option) in files.iter_mut().enumerate() {
            if file_option.is_none() {
                *file_option = Some(file);
                return Some(i);
            }
        }
        let len = files.len();
        if len < super::CONTEXT_MAX_FILES {
            files.push(Some(file));
            Some(len)
        } else {
            None
        }
    }

    /// Get a file
    pub fn get_file(&self, i: usize) -> Option<File> {
        let files = self.files.lock();
        if i < files.len() {
            files[i]
        } else {
            None
        }
    }

    /// Remove a file
    // TODO: adjust files vector to smaller size if possible
    pub fn remove_file(&self, i: usize) -> Option<File> {
        let mut files = self.files.lock();
        if i < files.len() {
            files[i].take()
        } else {
            None
        }
    }
}
<commit_msg>Fix path lookup<commit_after>use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::Vec;
use spin::Mutex;

use arch;
use super::file::File;
use super::memory::{Grant, Memory, SharedMemory};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Status {
    Runnable,
    Blocked,
    Exited(usize)
}

/// A context, which identifies either a process or a thread
#[derive(Debug)]
pub struct Context {
    /// The ID of this context
    pub id: usize,
    /// Status of context
    pub status: Status,
    /// Context running or not
    pub running: bool,
    /// The architecture specific context
    pub arch: arch::context::Context,
    /// Kernel FX
    pub kfx: Option<Box<[u8]>>,
    /// Kernel stack
    pub kstack: Option<Box<[u8]>>,
    /// Executable image
    pub image: Vec<SharedMemory>,
    /// User heap
    pub heap: Option<SharedMemory>,
    /// User stack
    pub stack: Option<Memory>,
    /// User grants
    pub grants: Arc<Mutex<Vec<Grant>>>,
    /// The current working directory
    pub cwd: Arc<Mutex<Vec<u8>>>,
    /// The open files in the scheme
    pub files: Arc<Mutex<Vec<Option<File>>>>
}

impl Context {
    /// Create a new context
    pub fn new(id: usize) -> Context {
        Context {
            id: id,
            status: Status::Blocked,
            running: false,
            arch: arch::context::Context::new(),
            kfx: None,
            kstack: None,
            image: Vec::new(),
            heap: None,
            stack: None,
            grants: Arc::new(Mutex::new(Vec::new())),
            cwd: Arc::new(Mutex::new(Vec::new())),
            files: Arc::new(Mutex::new(Vec::new()))
        }
    }

    pub fn canonicalize(&self, path: &[u8]) -> Vec<u8> {
        if path.iter().position(|&b| b == b':').is_none() {
            let cwd = self.cwd.lock();
            if path == b"." {
                cwd.clone()
            } else if path == b".." {
                cwd[..cwd[..cwd.len() - 1]
                                   .iter().rposition(|&b| b == b'/' || b == b':')
                                   .map_or(cwd.len(), |i| i + 1)]
                   .to_vec()
            } else if path.starts_with(b"./") {
                let mut canon = cwd.clone();
                canon.extend_from_slice(&path[2..]);
                canon
            } else if path.starts_with(b"../") {
                let mut canon = cwd[..cwd[..cwd.len() - 1]
                                   .iter().rposition(|&b| b == b'/' || b == b':')
                                   .map_or(cwd.len(), |i| i + 1)]
                   .to_vec();
                canon.extend_from_slice(&path[3..]);
                canon
            } else if path.starts_with(b"/") {
                let mut canon = cwd[..cwd.iter().position(|&b| b == b':').map_or(1, |i| i + 1)].to_vec();
                canon.extend_from_slice(&path);
                canon
            } else {
                let mut canon = cwd.clone();
                canon.extend_from_slice(&path);
                canon
            }
        } else {
            path.to_vec()
        }
    }

    /// Add a file to the lowest available slot.
    /// Return the file descriptor number or None if no slot was found
    pub fn add_file(&self, file: File) -> Option<usize> {
        let mut files = self.files.lock();
        for (i, mut file_option) in files.iter_mut().enumerate() {
            if file_option.is_none() {
                *file_option = Some(file);
                return Some(i);
            }
        }
        let len = files.len();
        if len < super::CONTEXT_MAX_FILES {
            files.push(Some(file));
            Some(len)
        } else {
            None
        }
    }

    /// Get a file
    pub fn get_file(&self, i: usize) -> Option<File> {
        let files = self.files.lock();
        if i < files.len() {
            files[i]
        } else {
            None
        }
    }

    /// Remove a file
    // TODO: adjust files vector to smaller size if possible
    pub fn remove_file(&self, i: usize) -> Option<File> {
        let mut files = self.files.lock();
        if i < files.len() {
            files[i].take()
        } else {
            None
        }
    }
}
<|endoftext|>