<commit_before>use arch::context::ContextMemory;
use arch::memory;

use system::error::Result;

//TODO: Refactor file to propogate results

pub fn do_sys_brk(addr: usize) -> Result<usize> {
    let mut ret = 0;

    let contexts = ::env().contexts.lock();
    if let Ok(current) = contexts.current() {
        ret = unsafe { (*current.heap.get()).next_mem() };

        // TODO: Make this smarter, currently it attempt to resize the entire data segment
        if let Some(mut mem) = unsafe { (*current.heap.get()).memory.last_mut() } {
            if mem.writeable && mem.allocated {
                if addr >= mem.virtual_address {
                    unsafe { mem.unmap() };

                    let size = addr - mem.virtual_address;
                    let physical_address = unsafe { memory::realloc_aligned(mem.physical_address, size, 4096) };
                    if physical_address > 0 {
                        mem.physical_address = physical_address;
                        mem.virtual_size = size;
                        ret = mem.virtual_address + mem.virtual_size;
                    } else {
                        mem.virtual_size = 0;
                        debugln!("BRK: Realloc failed {:X}, {}\n", mem.virtual_address, size);
                    }

                    unsafe { mem.map() };
                }
            } else {
                debugln!("{}: {}", current.pid, current.name);
                debugln!("BRK: End segment not writeable or allocated");
            }
        } else if addr >= ret {
            let size = addr - ret;
            let physical_address = unsafe { memory::alloc_aligned(size, 4096) };
            if physical_address > 0 {
                let mut mem = ContextMemory {
                    physical_address: physical_address,
                    virtual_address: ret,
                    virtual_size: size,
                    writeable: true,
                    allocated: true
                };
                ret = mem.virtual_address + mem.virtual_size;

                unsafe {
                    mem.map();
                    (*current.heap.get()).memory.push(mem);
                }
            } else {
                debugln!("BRK: Alloc failed {}\n", size);
            }
        }
    } else {
        debugln!("BRK: Context not found");
    }

    Ok(ret)
}
<commit_msg>Keep heap if brk fails<commit_after>use arch::context::ContextMemory;
use arch::memory;

use system::error::Result;

//TODO: Refactor file to propogate results

pub fn do_sys_brk(addr: usize) -> Result<usize> {
    let mut ret = 0;

    let contexts = ::env().contexts.lock();
    if let Ok(current) = contexts.current() {
        ret = unsafe { (*current.heap.get()).next_mem() };

        // TODO: Make this smarter, currently it attempt to resize the entire data segment
        if let Some(mut mem) = unsafe { (*current.heap.get()).memory.last_mut() } {
            if mem.writeable && mem.allocated {
                if addr >= mem.virtual_address {
                    unsafe { mem.unmap() };

                    let size = addr - mem.virtual_address;
                    let physical_address = unsafe { memory::realloc_aligned(mem.physical_address, size, 4096) };
                    if physical_address > 0 {
                        mem.physical_address = physical_address;
                        mem.virtual_size = size;
                        ret = mem.virtual_address + mem.virtual_size;
                    } else {
                        debugln!("BRK: Realloc failed {:X}, {}\n", mem.virtual_address, size);
                    }

                    unsafe { mem.map() };
                }
            } else {
                debugln!("{}: {}", current.pid, current.name);
                debugln!("BRK: End segment not writeable or allocated");
            }
        } else if addr >= ret {
            let size = addr - ret;
            let physical_address = unsafe { memory::alloc_aligned(size, 4096) };
            if physical_address > 0 {
                let mut mem = ContextMemory {
                    physical_address: physical_address,
                    virtual_address: ret,
                    virtual_size: size,
                    writeable: true,
                    allocated: true
                };
                ret = mem.virtual_address + mem.virtual_size;

                unsafe {
                    mem.map();
                    (*current.heap.get()).memory.push(mem);
                }
            } else {
                debugln!("BRK: Alloc failed {}\n", size);
            }
        }
    } else {
        debugln!("BRK: Context not found");
    }

    Ok(ret)
}
<|endoftext|>


<commit_before>use std::any::Any;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicUsize, Ordering};

use once_cell::sync::OnceCell;

use crate::context::Context;
use crate::lifecycle::GlobalCell;
use crate::result::NeonResult;

static COUNTER: AtomicUsize = AtomicUsize::new(0);

fn next_id() -> usize {
    COUNTER.fetch_add(1, Ordering::SeqCst)
}

/// A cell that can be used to allocate data that is global to an instance
/// of a Neon addon.
#[derive(Default)]
pub struct Global<T> {
    _type: PhantomData<T>,
    id: OnceCell<usize>,
}

impl<T> Global<T> {
    /// Creates a new global value. This method is `const`, so it can be assigned to
    /// static variables.
    pub const fn new() -> Self {
        Self {
            _type: PhantomData,
            id: OnceCell::new(),
        }
    }

    fn id(&self) -> usize {
        *self.id.get_or_init(next_id)
    }
}

impl<T: Any + Send + 'static> Global<T> {
    /// Gets the current value of the global. Returns `None` if the global has not
    /// yet been initialized.
    pub fn get<'cx, 'a, C>(&self, cx: &'a mut C) -> Option<&'cx T>
    where
        C: Context<'cx>,
    {
        // Safety: The type bound Global<T> and the fact that every Global has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: Option<&T> =
            GlobalCell::get(cx, self.id()).map(|value| value.downcast_ref().unwrap());

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<Option<&'a T>, Option<&'cx T>>(r) }
    }

    /// Gets the current value of the global, initializing it with `value` if it has
    /// not yet been initialized.
    pub fn get_or_init<'cx, 'a, C>(&self, cx: &'a mut C, value: T) -> &'cx T
    where
        C: Context<'cx>,
    {
        // Safety: The type bound Global<T> and the fact that every Global has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = GlobalCell::get_or_init(cx, self.id(), Box::new(value))
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<&'a T, &'cx T>(r) }
    }

    /// Gets the current value of the global, initializing it with the result of
    /// calling `f` if it has not yet been initialized.
    pub fn get_or_init_with<'cx, 'a, C, F>(&self, cx: &'a mut C, f: F) -> &'cx T
    where
        C: Context<'cx>,
        F: FnOnce() -> T,
    {
        // Safety: The type bound Global<T> and the fact that every Global has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = GlobalCell::get_or_init_with(cx, self.id(), || Box::new(f()))
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<&'a T, &'cx T>(r) }
    }

    /// Gets the current value of the global, initializing it with the result of
    /// calling `f` if it has not yet been initialized. Returns `Err` if the
    /// callback triggers a JavaScript exception.
    ///
    /// During the execution of `f`, calling any methods on this `Global` that
    /// attempt to initialize it will panic.
    pub fn get_or_try_init<'cx, 'a, C, E, F>(&self, cx: &'a mut C, f: F) -> Result<&'cx T, E>
    where
        C: Context<'cx>,
        F: FnOnce(&mut C) -> Result<T, E>,
    {
        // Safety: The type bound Global<T> and the fact that every Global has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = GlobalCell::get_or_try_init(cx, self.id(), |cx| Ok(Box::new(f(cx)?)))?
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        Ok(unsafe { std::mem::transmute::<&'a T, &'cx T>(r) })
    }
}

impl<T: Any + Send + Default + 'static> Global<T> {
    /// Gets the current value of the global, initializing it with the default value
    /// if it has not yet been initialized.
    pub fn get_or_init_default<'cx, 'a, C>(&self, cx: &'a mut C) -> &'cx T
    where
        C: Context<'cx>,
    {
        self.get_or_init_with(cx, Default::default)
    }
}
<commit_msg>Change "safety" to "unwrap safety" for the `.unwrap()` comment.<commit_after>use std::any::Any;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicUsize, Ordering};

use once_cell::sync::OnceCell;

use crate::context::Context;
use crate::lifecycle::GlobalCell;
use crate::result::NeonResult;

static COUNTER: AtomicUsize = AtomicUsize::new(0);

fn next_id() -> usize {
    COUNTER.fetch_add(1, Ordering::SeqCst)
}

/// A cell that can be used to allocate data that is global to an instance
/// of a Neon addon.
#[derive(Default)]
pub struct Global<T> {
    _type: PhantomData<T>,
    id: OnceCell<usize>,
}

impl<T> Global<T> {
    /// Creates a new global value. This method is `const`, so it can be assigned to
    /// static variables.
    pub const fn new() -> Self {
        Self {
            _type: PhantomData,
            id: OnceCell::new(),
        }
    }

    fn id(&self) -> usize {
        *self.id.get_or_init(next_id)
    }
}

impl<T: Any + Send + 'static> Global<T> {
    /// Gets the current value of the global. Returns `None` if the global has not
    /// yet been initialized.
    pub fn get<'cx, 'a, C>(&self, cx: &'a mut C) -> Option<&'cx T>
    where
        C: Context<'cx>,
    {
        // Unwrap safety: The type bound Global<T> and the fact that every Global has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: Option<&T> =
            GlobalCell::get(cx, self.id()).map(|value| value.downcast_ref().unwrap());

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<Option<&'a T>, Option<&'cx T>>(r) }
    }

    /// Gets the current value of the global, initializing it with `value` if it has
    /// not yet been initialized.
    pub fn get_or_init<'cx, 'a, C>(&self, cx: &'a mut C, value: T) -> &'cx T
    where
        C: Context<'cx>,
    {
        // Unwrap safety: The type bound Global<T> and the fact that every Global has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = GlobalCell::get_or_init(cx, self.id(), Box::new(value))
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<&'a T, &'cx T>(r) }
    }

    /// Gets the current value of the global, initializing it with the result of
    /// calling `f` if it has not yet been initialized.
    pub fn get_or_init_with<'cx, 'a, C, F>(&self, cx: &'a mut C, f: F) -> &'cx T
    where
        C: Context<'cx>,
        F: FnOnce() -> T,
    {
        // Unwrap safety: The type bound Global<T> and the fact that every Global has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = GlobalCell::get_or_init_with(cx, self.id(), || Box::new(f()))
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<&'a T, &'cx T>(r) }
    }

    /// Gets the current value of the global, initializing it with the result of
    /// calling `f` if it has not yet been initialized. Returns `Err` if the
    /// callback triggers a JavaScript exception.
    ///
    /// During the execution of `f`, calling any methods on this `Global` that
    /// attempt to initialize it will panic.
    pub fn get_or_try_init<'cx, 'a, C, E, F>(&self, cx: &'a mut C, f: F) -> Result<&'cx T, E>
    where
        C: Context<'cx>,
        F: FnOnce(&mut C) -> Result<T, E>,
    {
        // Unwrap safety: The type bound Global<T> and the fact that every Global has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = GlobalCell::get_or_try_init(cx, self.id(), |cx| Ok(Box::new(f(cx)?)))?
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        Ok(unsafe { std::mem::transmute::<&'a T, &'cx T>(r) })
    }
}

impl<T: Any + Send + Default + 'static> Global<T> {
    /// Gets the current value of the global, initializing it with the default value
    /// if it has not yet been initialized.
    pub fn get_or_init_default<'cx, 'a, C>(&self, cx: &'a mut C) -> &'cx T
    where
        C: Context<'cx>,
    {
        self.get_or_init_with(cx, Default::default)
    }
}
<|endoftext|>


<commit_before>extern crate piston_window;
extern crate gfx_device_gl;
extern crate gfx_graphics;
extern crate find_folder;

use piston_window::Transformed;

use piston_window as pw;

mod object;
use object::Object;

struct Game {
    player: Object,
    up: bool,
    down: bool,
    left: bool,
    right: bool,
}

impl Game {
    fn new(sprite: piston_window::Texture<gfx_device_gl::Resources>) -> Game {
        Game { player: Object::new(sprite), up: false, down: false, left: false, right: false }
    }

    fn on_update(&mut self, args: &pw::UpdateArgs) {
        if self.up   { self.player.mov(0.0, -150.0 * args.dt); }
        if self.down { self.player.mov(0.0, 150.0 * args.dt); }
        if self.left { self.player.mov(-150.0 * args.dt, 0.0); }
        if self.right { self.player.mov(150.0 * args.dt, 0.0); }
    }

    fn on_draw(&mut self, args: &pw::RenderArgs, window: &pw::PistonWindow) {
        window.draw_2d(|context, graphics| {
            pw::clear([0.0, 0.0, 0.0, 1.0], graphics);

            let center = context.transform.trans((args.width / 2) as f64, (args.height / 2) as f64);
            self.player.render(graphics, &center);
        });
    }

    fn on_input(&mut self, input: &pw::Input) {
        use piston_window::{Input, Button, Key};

        match input {
            &Input::Press(button) => {
                match button {
                    Button::Keyboard(Key::Up) => { self.up = true; }
                    Button::Keyboard(Key::Down) => { self.down = true; }
                    Button::Keyboard(Key::Left) => { self.left = true; }
                    Button::Keyboard(Key::Right) => { self.right = true; }
                    _ => {}
                }
            }
            &Input::Release(button) => {
                match button {
                    Button::Keyboard(Key::Up) => { self.up = false; }
                    Button::Keyboard(Key::Down) => { self.down = false; }
                    Button::Keyboard(Key::Left) => { self.left = false; }
                    Button::Keyboard(Key::Right) => { self.right = false; }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

fn load_sprite(window: &pw::PistonWindow, name: &str) -> piston_window::Texture<gfx_device_gl::Resources> {
    let assets = find_folder::Search::ParentsThenKids(3, 3).for_folder("assets").unwrap();
    let sprite = assets.join(name);
    pw::Texture::from_path(&mut *window.factory.borrow_mut(), &sprite, pw::Flip::None, &pw::TextureSettings::new()).unwrap()
}

fn main() {
    use piston_window::Event;

    let window: pw::PistonWindow = pw::WindowSettings::new("rrthozopsi", [600, 600])
        .exit_on_esc(true)
        .build()
        .unwrap();

    let mut game = Game::new(load_sprite(&window, "skeleton.png"));

    for w in window {
        match w.event {
            Some(Event::Update(args)) => { game.on_update(&args); }
            Some(Event::Render(args)) => { game.on_draw(&args, &w); }
            Some(Event::Input(input)) => { game.on_input(&input); }
            _ => {}
        }
    }
}
<commit_msg>TODO note<commit_after>extern crate piston_window;
extern crate gfx_device_gl;
extern crate gfx_graphics;
extern crate find_folder;

use piston_window::Transformed;

use piston_window as pw;

mod object;
use object::Object;

struct Game {
    player: Object,
    up: bool,
    down: bool,
    left: bool,
    right: bool,
}

impl Game {
    fn new(sprite: piston_window::Texture<gfx_device_gl::Resources>) -> Game {
        Game { player: Object::new(sprite), up: false, down: false, left: false, right: false }
    }

    fn on_update(&mut self, args: &pw::UpdateArgs) {
        if self.up   { self.player.mov(0.0, -150.0 * args.dt); }
        if self.down { self.player.mov(0.0, 150.0 * args.dt); }
        if self.left { self.player.mov(-150.0 * args.dt, 0.0); }
        if self.right { self.player.mov(150.0 * args.dt, 0.0); }
    }

    fn on_draw(&mut self, args: &pw::RenderArgs, window: &pw::PistonWindow) {
        window.draw_2d(|context, graphics| {
            pw::clear([0.0, 0.0, 0.0, 1.0], graphics);

            let center = context.transform.trans((args.width / 2) as f64, (args.height / 2) as f64);
            self.player.render(graphics, &center);
        });
    }

    fn on_input(&mut self, input: &pw::Input) {
        use piston_window::{Input, Button, Key};

        match input {
            &Input::Press(button) => {
                match button {
                    Button::Keyboard(Key::Up) => { self.up = true; }
                    Button::Keyboard(Key::Down) => { self.down = true; }
                    Button::Keyboard(Key::Left) => { self.left = true; }
                    Button::Keyboard(Key::Right) => { self.right = true; }
                    _ => {}
                }
            }
            &Input::Release(button) => {
                match button {
                    Button::Keyboard(Key::Up) => { self.up = false; }
                    Button::Keyboard(Key::Down) => { self.down = false; }
                    Button::Keyboard(Key::Left) => { self.left = false; }
                    Button::Keyboard(Key::Right) => { self.right = false; }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}

fn load_sprite(window: &pw::PistonWindow, name: &str) -> piston_window::Texture<gfx_device_gl::Resources> {
    // TODO: Create and use default sprite in case of failure during loading?
    let assets = find_folder::Search::ParentsThenKids(3, 3).for_folder("assets").unwrap();
    let sprite = assets.join(name);
    pw::Texture::from_path(&mut *window.factory.borrow_mut(), &sprite, pw::Flip::None, &pw::TextureSettings::new()).unwrap()
}

fn main() {
    use piston_window::Event;

    let window: pw::PistonWindow = pw::WindowSettings::new("rrthozopsi", [600, 600])
        .exit_on_esc(true)
        .build()
        .unwrap();

    let mut game = Game::new(load_sprite(&window, "skeleton.png"));

    for w in window {
        match w.event {
            Some(Event::Update(args)) => { game.on_update(&args); }
            Some(Event::Render(args)) => { game.on_draw(&args, &w); }
            Some(Event::Input(input)) => { game.on_input(&input); }
            _ => {}
        }
    }
}
<|endoftext|>


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

use crate::{constants, layout::Layout, storage_helper::StorageHelper};
use config_builder::BuildSwarm;
use libra_config::config::{
    Identity, NodeConfig, OnDiskStorageConfig, SafetyRulesService, SecureBackend, SeedAddresses,
    WaypointConfig, HANDSHAKE_VERSION,
};
use libra_crypto::ed25519::Ed25519PrivateKey;
use libra_secure_storage::{CryptoStorage, KVStorage, Value};
use libra_temppath::TempPath;
use std::path::{Path, PathBuf};

const ASSOCIATION_NS: &str = "association";
const ASSOCIATION_SHARED_NS: &str = "association_shared";
const OPERATOR_NS: &str = "_operator";
const OPERATOR_SHARED_NS: &str = "_operator_shared";
const OWNER_NS: &str = "_owner";
const OWNER_SHARED_NS: &str = "_owner_shared";

pub struct ValidatorBuilder<T: AsRef<Path>> {
    storage_helper: StorageHelper,
    num_validators: usize,
    template: NodeConfig,
    swarm_path: T,
}

impl<T: AsRef<Path>> ValidatorBuilder<T> {
    pub fn new(num_validators: usize, template: NodeConfig, swarm_path: T) -> Self {
        Self {
            storage_helper: StorageHelper::new(),
            num_validators,
            template,
            swarm_path,
        }
    }

    fn secure_backend(&self, ns: &str, usage: &str) -> SecureBackend {
        let original = self.storage_helper.path();
        let dst_base = self.swarm_path.as_ref();
        let mut dst = dst_base.to_path_buf();
        dst.push(format!("{}_{}", usage, ns));
        std::fs::copy(original, &dst).unwrap();

        let mut storage_config = OnDiskStorageConfig::default();
        storage_config.path = dst;
        storage_config.set_data_dir(PathBuf::from(""));
        storage_config.namespace = Some(ns.into());
        SecureBackend::OnDiskStorage(storage_config)
    }

    /// Association uploads the validator layout to shared storage.
    fn create_layout(&self) {
        let mut layout = Layout::default();
        layout.association = vec![ASSOCIATION_SHARED_NS.into()];
        layout.owners = (0..self.num_validators)
            .map(|i| (i.to_string() + OWNER_SHARED_NS))
            .collect();
        layout.operators = (0..self.num_validators)
            .map(|i| (i.to_string() + OPERATOR_SHARED_NS))
            .collect();

        let mut common_storage = self
            .storage_helper
            .storage(crate::constants::COMMON_NS.into());
        let layout_value = Value::String(layout.to_toml().unwrap());
        common_storage
            .set(crate::constants::LAYOUT, layout_value)
            .unwrap();
    }

    /// Association initializes its account and key.
    fn create_association(&self) {
        self.storage_helper.initialize(ASSOCIATION_NS.into());
        self.storage_helper
            .association_key(ASSOCIATION_NS, ASSOCIATION_SHARED_NS)
            .unwrap();
    }

    /// Generate owner key locally and upload to shared storage.
    fn initialize_validator_owner(&self, index: usize) {
        let local_ns = index.to_string() + OWNER_NS;
        let remote_ns = index.to_string() + OWNER_SHARED_NS;

        self.storage_helper.initialize(local_ns.clone());
        let _ = self
            .storage_helper
            .owner_key(&local_ns, &remote_ns)
            .unwrap();
    }

    /// Generate operator key locally and upload to shared storage.
    fn initialize_validator_operator(&self, index: usize) {
        let local_ns = index.to_string() + OPERATOR_NS;
        let remote_ns = index.to_string() + OPERATOR_SHARED_NS;

        self.storage_helper.initialize(local_ns.clone());
        let _ = self
            .storage_helper
            .operator_key(&local_ns, &remote_ns)
            .unwrap();
    }

    /// Sets the operator for the owner by uploading a set-operator transaction to shared storage.
    /// Note, we assume that owner i chooses operator i to operate the validator.
    fn set_validator_operator(&self, index: usize) {
        let local_ns = index.to_string() + OWNER_NS;
        let remote_ns = index.to_string() + OWNER_SHARED_NS;

        let operator_name = index.to_string() + OPERATOR_SHARED_NS;
        let _ = self
            .storage_helper
            .set_operator(&operator_name, &local_ns, &remote_ns);
    }

    /// Operators upload their validator_config to shared storage.
    fn initialize_validator_config(&self, index: usize) -> NodeConfig {
        let local_ns = index.to_string() + OPERATOR_NS;
        let remote_ns = index.to_string() + OPERATOR_SHARED_NS;

        let mut config = self.template.clone_for_template();
        config.randomize_ports();

        let validator_network = config.validator_network.as_mut().unwrap();
        let validator_network_address = validator_network.listen_address.clone();
        let fullnode_network = &mut config.full_node_networks[0];
        let fullnode_network_address = fullnode_network.listen_address.clone();

        self.storage_helper
            .validator_config(
                &(index.to_string() + OWNER_SHARED_NS),
                validator_network_address,
                fullnode_network_address,
                self.template.base.chain_id,
                &local_ns,
                &remote_ns,
            )
            .unwrap();

        validator_network.identity = Identity::from_storage(
            libra_global_constants::VALIDATOR_NETWORK_KEY.into(),
            libra_global_constants::OWNER_ACCOUNT.into(),
            self.secure_backend(&local_ns, "validator"),
        );
        fullnode_network.identity = Identity::from_storage(
            libra_global_constants::FULLNODE_NETWORK_KEY.into(),
            libra_global_constants::OWNER_ACCOUNT.into(),
            self.secure_backend(&local_ns, "full_node"),
        );

        config
    }

    /// Operators generate genesis from shared storage and verify against waypoint.
    /// Insert the genesis/waypoint into local config.
    fn finish_validator_config(&self, index: usize, config: &mut NodeConfig) {
        let local_ns = index.to_string() + OPERATOR_NS;

        let genesis_path = TempPath::new();
        genesis_path.create_as_file().unwrap();
        let genesis = self.storage_helper.genesis(genesis_path.path()).unwrap();

        let _ = self
            .storage_helper
            .insert_waypoint(&local_ns, constants::COMMON_NS)
            .unwrap();
        let output = self
            .storage_helper
            .verify_genesis(&local_ns, genesis_path.path())
            .unwrap();
        assert_eq!(output.split("match").count(), 5);

        config.consensus.safety_rules.service = SafetyRulesService::Thread;
        config.consensus.safety_rules.backend = self.secure_backend(&local_ns, "safety-rules");
        config.execution.backend = self.secure_backend(&local_ns, "execution");

        let backend = self.secure_backend(&local_ns, "waypoint");
        config.base.waypoint = WaypointConfig::FromStorage(backend);
        config.execution.genesis = Some(genesis);
        config.execution.genesis_file_location = PathBuf::from("");
    }
}

impl<T: AsRef<Path>> BuildSwarm for ValidatorBuilder<T> {
    fn build_swarm(&self) -> anyhow::Result<(Vec<NodeConfig>, Ed25519PrivateKey)> {
        self.create_layout();
        self.create_association();
        let association_key = self
            .storage_helper
            .storage(ASSOCIATION_NS.into())
            .export_private_key(libra_global_constants::LIBRA_ROOT_KEY)
            .unwrap();

        // Upload both owner and operator keys to shared storage
        for index in 0..self.num_validators {
            self.initialize_validator_owner(index);
            self.initialize_validator_operator(index);
        }

        // Set the operator for each owner and the validator config for each operator
        let mut configs = vec![];
        for index in 0..self.num_validators {
            let _ = self.set_validator_operator(index);
            let config = self.initialize_validator_config(index);
            configs.push(config);
        }

        // Create genesis and waypoint
        let _ = self
            .storage_helper
            .create_waypoint(constants::COMMON_NS)
            .unwrap();
        for (i, config) in configs.iter_mut().enumerate() {
            self.finish_validator_config(i, config);
        }

        Ok((configs, association_key))
    }
}

#[derive(Debug)]
pub enum FullnodeType {
    ValidatorFullnode,
    PublicFullnode(usize),
}

pub struct FullnodeBuilder {
    validator_config_path: Vec<PathBuf>,
    libra_root_key_path: PathBuf,
    template: NodeConfig,
    build_type: FullnodeType,
}

impl FullnodeBuilder {
    pub fn new(
        validator_config_path: Vec<PathBuf>,
        libra_root_key_path: PathBuf,
        template: NodeConfig,
        build_type: FullnodeType,
    ) -> Self {
        Self {
            validator_config_path,
            libra_root_key_path,
            template,
            build_type,
        }
    }

    fn attach_validator_full_node(&self, validator_config: &mut NodeConfig) -> NodeConfig {
        // Create two vfns, we'll pass one to the validator later
        let mut full_node_config = self.template.clone_for_template();
        full_node_config.randomize_ports();

        // The FN's first network is the external, public network, it needs to swap listen addresses
        // with the validator's VFN and to copy it's key access:
        let pfn = &mut full_node_config.full_node_networks[0];
        let v_vfn = &mut validator_config.full_node_networks[0];
        pfn.identity = v_vfn.identity.clone();
        let temp_listen = v_vfn.listen_address.clone();
        v_vfn.listen_address = pfn.listen_address.clone();
        pfn.listen_address = temp_listen;

        // Now let's prepare the full nodes internal network to communicate with the validators
        // internal network

        let v_vfn_network_address = v_vfn.listen_address.clone();
        let v_vfn_pub_key = v_vfn.identity_key().public_key();
        let v_vfn_network_address =
            v_vfn_network_address.append_prod_protos(v_vfn_pub_key, HANDSHAKE_VERSION);
        let v_vfn_id = v_vfn.peer_id();
        let mut seed_addrs = SeedAddresses::default();
        seed_addrs.insert(v_vfn_id, vec![v_vfn_network_address]);

        let fn_vfn = &mut full_node_config.full_node_networks[1];
        fn_vfn.seed_addrs = seed_addrs;

        Self::insert_waypoint_and_genesis(&mut full_node_config, &validator_config);
        full_node_config
    }

    fn insert_waypoint_and_genesis(config: &mut NodeConfig, upstream: &NodeConfig) {
        config.base.waypoint = upstream.base.waypoint.clone();
        config.execution.genesis = upstream.execution.genesis.clone();
        config.execution.genesis_file_location = PathBuf::from("");
    }

    fn build_vfn(&self) -> anyhow::Result<Vec<NodeConfig>> {
        let mut configs = vec![];
        for path in &self.validator_config_path {
            let mut validator_config = NodeConfig::load(path)?;
            let fullnode_config = self.attach_validator_full_node(&mut validator_config);
            validator_config.save(path)?;
            configs.push(fullnode_config);
        }
        Ok(configs)
    }

    fn build_public_fn(&self, num_nodes: usize) -> anyhow::Result<Vec<NodeConfig>> {
        let mut configs = vec![];
        let validator_config = NodeConfig::load(
            self.validator_config_path
                .first()
                .ok_or_else(|| anyhow::format_err!("No validator config path"))?,
        )?;
        for _ in 0..num_nodes {
            let mut fullnode_config = self.template.clone_for_template();
            fullnode_config.randomize_ports();
            Self::insert_waypoint_and_genesis(&mut fullnode_config, &validator_config);
            configs.push(fullnode_config);
        }
        Ok(configs)
    }
}

impl BuildSwarm for FullnodeBuilder {
    fn build_swarm(&self) -> anyhow::Result<(Vec<NodeConfig>, Ed25519PrivateKey)> {
        let configs = match self.build_type {
            FullnodeType::ValidatorFullnode => self.build_vfn(),
            FullnodeType::PublicFullnode(num_nodes) => self.build_public_fn(num_nodes),
        }?;
        let libra_root_key_path = generate_key::load_key(&self.libra_root_key_path);
        Ok((configs, libra_root_key_path))
    }
}
<commit_msg>[management] make attach_validator_full_node logic less dependent on FN network config ordering<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{constants, layout::Layout, storage_helper::StorageHelper};
use config_builder::BuildSwarm;
use libra_config::{
    config::{
        DiscoveryMethod, Identity, NodeConfig, OnDiskStorageConfig, SafetyRulesService,
        SecureBackend, SeedAddresses, WaypointConfig, HANDSHAKE_VERSION,
    },
    network_id::NetworkId,
};
use libra_crypto::ed25519::Ed25519PrivateKey;
use libra_secure_storage::{CryptoStorage, KVStorage, Value};
use libra_temppath::TempPath;
use std::path::{Path, PathBuf};

const ASSOCIATION_NS: &str = "association";
const ASSOCIATION_SHARED_NS: &str = "association_shared";
const OPERATOR_NS: &str = "_operator";
const OPERATOR_SHARED_NS: &str = "_operator_shared";
const OWNER_NS: &str = "_owner";
const OWNER_SHARED_NS: &str = "_owner_shared";

pub struct ValidatorBuilder<T: AsRef<Path>> {
    storage_helper: StorageHelper,
    num_validators: usize,
    template: NodeConfig,
    swarm_path: T,
}

impl<T: AsRef<Path>> ValidatorBuilder<T> {
    pub fn new(num_validators: usize, template: NodeConfig, swarm_path: T) -> Self {
        Self {
            storage_helper: StorageHelper::new(),
            num_validators,
            template,
            swarm_path,
        }
    }

    fn secure_backend(&self, ns: &str, usage: &str) -> SecureBackend {
        let original = self.storage_helper.path();
        let dst_base = self.swarm_path.as_ref();
        let mut dst = dst_base.to_path_buf();
        dst.push(format!("{}_{}", usage, ns));
        std::fs::copy(original, &dst).unwrap();

        let mut storage_config = OnDiskStorageConfig::default();
        storage_config.path = dst;
        storage_config.set_data_dir(PathBuf::from(""));
        storage_config.namespace = Some(ns.into());
        SecureBackend::OnDiskStorage(storage_config)
    }

    /// Association uploads the validator layout to shared storage.
    fn create_layout(&self) {
        let mut layout = Layout::default();
        layout.association = vec![ASSOCIATION_SHARED_NS.into()];
        layout.owners = (0..self.num_validators)
            .map(|i| (i.to_string() + OWNER_SHARED_NS))
            .collect();
        layout.operators = (0..self.num_validators)
            .map(|i| (i.to_string() + OPERATOR_SHARED_NS))
            .collect();

        let mut common_storage = self
            .storage_helper
            .storage(crate::constants::COMMON_NS.into());
        let layout_value = Value::String(layout.to_toml().unwrap());
        common_storage
            .set(crate::constants::LAYOUT, layout_value)
            .unwrap();
    }

    /// Association initializes its account and key.
    fn create_association(&self) {
        self.storage_helper.initialize(ASSOCIATION_NS.into());
        self.storage_helper
            .association_key(ASSOCIATION_NS, ASSOCIATION_SHARED_NS)
            .unwrap();
    }

    /// Generate owner key locally and upload to shared storage.
    fn initialize_validator_owner(&self, index: usize) {
        let local_ns = index.to_string() + OWNER_NS;
        let remote_ns = index.to_string() + OWNER_SHARED_NS;

        self.storage_helper.initialize(local_ns.clone());
        let _ = self
            .storage_helper
            .owner_key(&local_ns, &remote_ns)
            .unwrap();
    }

    /// Generate operator key locally and upload to shared storage.
    fn initialize_validator_operator(&self, index: usize) {
        let local_ns = index.to_string() + OPERATOR_NS;
        let remote_ns = index.to_string() + OPERATOR_SHARED_NS;

        self.storage_helper.initialize(local_ns.clone());
        let _ = self
            .storage_helper
            .operator_key(&local_ns, &remote_ns)
            .unwrap();
    }

    /// Sets the operator for the owner by uploading a set-operator transaction to shared storage.
    /// Note, we assume that owner i chooses operator i to operate the validator.
    fn set_validator_operator(&self, index: usize) {
        let local_ns = index.to_string() + OWNER_NS;
        let remote_ns = index.to_string() + OWNER_SHARED_NS;

        let operator_name = index.to_string() + OPERATOR_SHARED_NS;
        let _ = self
            .storage_helper
            .set_operator(&operator_name, &local_ns, &remote_ns);
    }

    /// Operators upload their validator_config to shared storage.
    fn initialize_validator_config(&self, index: usize) -> NodeConfig {
        let local_ns = index.to_string() + OPERATOR_NS;
        let remote_ns = index.to_string() + OPERATOR_SHARED_NS;

        let mut config = self.template.clone_for_template();
        config.randomize_ports();

        let validator_network = config.validator_network.as_mut().unwrap();
        let validator_network_address = validator_network.listen_address.clone();
        let fullnode_network = &mut config.full_node_networks[0];
        let fullnode_network_address = fullnode_network.listen_address.clone();

        self.storage_helper
            .validator_config(
                &(index.to_string() + OWNER_SHARED_NS),
                validator_network_address,
                fullnode_network_address,
                self.template.base.chain_id,
                &local_ns,
                &remote_ns,
            )
            .unwrap();

        validator_network.identity = Identity::from_storage(
            libra_global_constants::VALIDATOR_NETWORK_KEY.into(),
            libra_global_constants::OWNER_ACCOUNT.into(),
            self.secure_backend(&local_ns, "validator"),
        );
        fullnode_network.identity = Identity::from_storage(
            libra_global_constants::FULLNODE_NETWORK_KEY.into(),
            libra_global_constants::OWNER_ACCOUNT.into(),
            self.secure_backend(&local_ns, "full_node"),
        );

        config
    }

    /// Operators generate genesis from shared storage and verify against waypoint.
    /// Insert the genesis/waypoint into local config.
    fn finish_validator_config(&self, index: usize, config: &mut NodeConfig) {
        let local_ns = index.to_string() + OPERATOR_NS;

        let genesis_path = TempPath::new();
        genesis_path.create_as_file().unwrap();
        let genesis = self.storage_helper.genesis(genesis_path.path()).unwrap();

        let _ = self
            .storage_helper
            .insert_waypoint(&local_ns, constants::COMMON_NS)
            .unwrap();
        let output = self
            .storage_helper
            .verify_genesis(&local_ns, genesis_path.path())
            .unwrap();
        assert_eq!(output.split("match").count(), 5);

        config.consensus.safety_rules.service = SafetyRulesService::Thread;
        config.consensus.safety_rules.backend = self.secure_backend(&local_ns, "safety-rules");
        config.execution.backend = self.secure_backend(&local_ns, "execution");

        let backend = self.secure_backend(&local_ns, "waypoint");
        config.base.waypoint = WaypointConfig::FromStorage(backend);
        config.execution.genesis = Some(genesis);
        config.execution.genesis_file_location = PathBuf::from("");
    }
}

impl<T: AsRef<Path>> BuildSwarm for ValidatorBuilder<T> {
    fn build_swarm(&self) -> anyhow::Result<(Vec<NodeConfig>, Ed25519PrivateKey)> {
        self.create_layout();
        self.create_association();
        let association_key = self
            .storage_helper
            .storage(ASSOCIATION_NS.into())
            .export_private_key(libra_global_constants::LIBRA_ROOT_KEY)
            .unwrap();

        // Upload both owner and operator keys to shared storage
        for index in 0..self.num_validators {
            self.initialize_validator_owner(index);
            self.initialize_validator_operator(index);
        }

        // Set the operator for each owner and the validator config for each operator
        let mut configs = vec![];
        for index in 0..self.num_validators {
            let _ = self.set_validator_operator(index);
            let config = self.initialize_validator_config(index);
            configs.push(config);
        }

        // Create genesis and waypoint
        let _ = self
            .storage_helper
            .create_waypoint(constants::COMMON_NS)
            .unwrap();
        for (i, config) in configs.iter_mut().enumerate() {
            self.finish_validator_config(i, config);
        }

        Ok((configs, association_key))
    }
}

#[derive(Debug)]
pub enum FullnodeType {
    ValidatorFullnode,
    PublicFullnode(usize),
}

pub struct FullnodeBuilder {
    validator_config_path: Vec<PathBuf>,
    libra_root_key_path: PathBuf,
    template: NodeConfig,
    build_type: FullnodeType,
}

impl FullnodeBuilder {
    pub fn new(
        validator_config_path: Vec<PathBuf>,
        libra_root_key_path: PathBuf,
        template: NodeConfig,
        build_type: FullnodeType,
    ) -> Self {
        Self {
            validator_config_path,
            libra_root_key_path,
            template,
            build_type,
        }
    }

    fn attach_validator_full_node(&self, validator_config: &mut NodeConfig) -> NodeConfig {
        // Create two vfns, we'll pass one to the validator later
        let mut full_node_config = self.template.clone_for_template();
        full_node_config.randomize_ports();

        // The FN's external, public network needs to swap listen addresses
        // with the validator's VFN and to copy it's key access:
        let pfn = &mut full_node_config
            .full_node_networks
            .iter_mut()
            .find(|n| {
                n.network_id == NetworkId::Public && n.discovery_method != DiscoveryMethod::Onchain
            })
            .expect("vfn missing external public network in config");
        let v_vfn = &mut validator_config.full_node_networks[0];
        pfn.identity = v_vfn.identity.clone();
        let temp_listen = v_vfn.listen_address.clone();
        v_vfn.listen_address = pfn.listen_address.clone();
        pfn.listen_address = temp_listen;

        // Now let's prepare the full nodes internal network to communicate with the validators
        // internal network

        let v_vfn_network_address = v_vfn.listen_address.clone();
        let v_vfn_pub_key = v_vfn.identity_key().public_key();
        let v_vfn_network_address =
            v_vfn_network_address.append_prod_protos(v_vfn_pub_key, HANDSHAKE_VERSION);
        let v_vfn_id = v_vfn.peer_id();
        let mut seed_addrs = SeedAddresses::default();
        seed_addrs.insert(v_vfn_id, vec![v_vfn_network_address]);

        let fn_vfn = &mut full_node_config
            .full_node_networks
            .iter_mut()
            .find(|n| matches!(n.network_id, NetworkId::Private(_)))
            .expect("vfn missing vfn full node network in config");
        fn_vfn.seed_addrs = seed_addrs;

        Self::insert_waypoint_and_genesis(&mut full_node_config, &validator_config);
        full_node_config
    }

    fn insert_waypoint_and_genesis(config: &mut NodeConfig, upstream: &NodeConfig) {
        config.base.waypoint = upstream.base.waypoint.clone();
        config.execution.genesis = upstream.execution.genesis.clone();
        config.execution.genesis_file_location = PathBuf::from("");
    }

    fn build_vfn(&self) -> anyhow::Result<Vec<NodeConfig>> {
        let mut configs = vec![];
        for path in &self.validator_config_path {
            let mut validator_config = NodeConfig::load(path)?;
            let fullnode_config = self.attach_validator_full_node(&mut validator_config);
            validator_config.save(path)?;
            configs.push(fullnode_config);
        }
        Ok(configs)
    }

    fn build_public_fn(&self, num_nodes: usize) -> anyhow::Result<Vec<NodeConfig>> {
        let mut configs = vec![];
        let validator_config = NodeConfig::load(
            self.validator_config_path
                .first()
                .ok_or_else(|| anyhow::format_err!("No validator config path"))?,
        )?;
        for _ in 0..num_nodes {
            let mut fullnode_config = self.template.clone_for_template();
            fullnode_config.randomize_ports();
            Self::insert_waypoint_and_genesis(&mut fullnode_config, &validator_config);
            configs.push(fullnode_config);
        }
        Ok(configs)
    }
}

impl BuildSwarm for FullnodeBuilder {
    fn build_swarm(&self) -> anyhow::Result<(Vec<NodeConfig>, Ed25519PrivateKey)> {
        let configs = match self.build_type {
            FullnodeType::ValidatorFullnode => self.build_vfn(),
            FullnodeType::PublicFullnode(num_nodes) => self.build_public_fn(num_nodes),
        }?;
        let libra_root_key_path = generate_key::load_key(&self.libra_root_key_path);
        Ok((configs, libra_root_key_path))
    }
}
<|endoftext|>


<commit_before>#[deriving(Clone, Eq)]
pub struct Point {
    x: f64,
    y: f64,
}

#[deriving(Clone, Eq)]
pub struct Size {
    width: f64,
    height: f64,
}

#[deriving(Clone, Eq)]
pub struct Rect {
    origin: Point,
    size: Size,
}

impl Point {
    pub fn new(x: f64, y: f64) -> Point {
        Point { x: x, y: y }
    }

    pub fn add(&self, addPoint: Point) -> Point {
        Point::new(self.x + addPoint.x, self.y + addPoint.y)
    }

    pub fn subtract(&self, offsetPoint: Point) -> Point {
        Point::new(self.x - offsetPoint.x, self.y - offsetPoint.y)
    }
}

impl Size {
    pub fn new(width: f64, height: f64) -> Size {
        Size { width: width, height: height }
    }
}

impl Rect {
    pub fn new(origin: Point, size: Size) -> Rect {
        Rect { origin: origin, size: size }
    }

    /// Find which the rect has an origin farther to the left.
    pub fn minXRect<'a>(rect1: &'a Rect, rect2: &'a Rect) -> (&'a Rect, &'a Rect) {
        if rect1.minX() <= rect2.minX() {
            (rect1, rect2)
        } else {
            (rect2, rect1)
        }
    }

    /// Find which the rect has an origin with a lower y value.
    pub fn minYRect<'a>(rect1: &'a Rect, rect2: &'a Rect) -> (&'a Rect, &'a Rect) {
        if rect1.minY() <= rect2.minY() {
            (rect1, rect2)
        } else {
            (rect2, rect1)
        }
    }

    /**
     Check if this rect entirely contains another rect.
     */
    pub fn contains(&self, rect: &Rect) -> bool {
        // Find which the rect has an origin farther to the left.
        let (minXRect, otherRect) = Rect::minXRect(self, rect);

        // If the rectangles don't intersect, one cannot be contained in the other.
        self.intersects(rect)
        && (minXRect.maxX() >= otherRect.maxX() && minXRect.maxY() >= otherRect.maxY())
    }

    /**
     Check if this rect and another rect intersect.
     */
    pub fn intersects(&self, rect: &Rect) -> bool {
        let (minXRect, otherRect) = Rect::minXRect(self, rect);

        let intersects: bool = (minXRect.maxX() >= otherRect.minX())
            && ((minXRect.minY() >= otherRect.minY() && minXRect.minY() <= otherRect.maxY())
                || (minXRect.minY() <= otherRect.minY() && minXRect.maxY() >= otherRect.minY()));

        intersects
    }

    /**
     Get the intersection with another rect.
     */
    pub fn intersect(&self, rect: &Rect) -> Option<Rect> {
        if !self.intersects(rect) {
            return None;
        }

        let (minXRect, otherXRect) = Rect::minXRect(self, rect);
        let (minYRect, otherYRect) = Rect::minYRect(self, rect);
        let commonXStart = otherXRect.minX();
        let commonYStart = otherYRect.minY();

        let commonXEnd = minXRect.maxX().min(otherXRect.maxX());
        let commonYEnd = minYRect.maxY().min(otherYRect.maxY());

        let width = commonXEnd - commonXStart;
        let height = commonYEnd - commonYStart;

        Some(Rect::new(Point::new(commonXStart, commonYStart), Size::new(width, height)))
    }

    pub fn maxX(&self) -> f64 {
        self.origin.x + self.size.width
    }

    pub fn maxY(&self) -> f64 {
        self.origin.y + self.size.height
    }

    pub fn minX(&self) -> f64 {
        self.origin.x
    }

    pub fn minY(&self) -> f64 {
        self.origin.y
    }

    pub fn height(&self) -> f64 {
        self.size.height
    }

    pub fn width(&self) -> f64 {
        self.size.width
    }
}
<commit_msg>Geometry now derives Show.<commit_after>#[deriving(Clone, Eq, Show)]
pub struct Point {
    x: f64,
    y: f64,
}

#[deriving(Clone, Eq, Show)]
pub struct Size {
    width: f64,
    height: f64,
}

#[deriving(Clone, Eq, Show)]
pub struct Rect {
    origin: Point,
    size: Size,
}

impl Point {
    pub fn new(x: f64, y: f64) -> Point {
        Point { x: x, y: y }
    }

    pub fn add(&self, addPoint: Point) -> Point {
        Point::new(self.x + addPoint.x, self.y + addPoint.y)
    }

    pub fn subtract(&self, offsetPoint: Point) -> Point {
        Point::new(self.x - offsetPoint.x, self.y - offsetPoint.y)
    }
}

impl Size {
    pub fn new(width: f64, height: f64) -> Size {
        Size { width: width, height: height }
    }
}

impl Rect {
    pub fn new(origin: Point, size: Size) -> Rect {
        Rect { origin: origin, size: size }
    }

    /// Find which the rect has an origin farther to the left.
    pub fn minXRect<'a>(rect1: &'a Rect, rect2: &'a Rect) -> (&'a Rect, &'a Rect) {
        if rect1.minX() <= rect2.minX() {
            (rect1, rect2)
        } else {
            (rect2, rect1)
        }
    }

    /// Find which the rect has an origin with a lower y value.
    pub fn minYRect<'a>(rect1: &'a Rect, rect2: &'a Rect) -> (&'a Rect, &'a Rect) {
        if rect1.minY() <= rect2.minY() {
            (rect1, rect2)
        } else {
            (rect2, rect1)
        }
    }

    /**
     Check if this rect entirely contains another rect.
     */
    pub fn contains(&self, rect: &Rect) -> bool {
        // Find which the rect has an origin farther to the left.
        let (minXRect, otherRect) = Rect::minXRect(self, rect);

        // If the rectangles don't intersect, one cannot be contained in the other.
        self.intersects(rect)
        && (minXRect.maxX() >= otherRect.maxX() && minXRect.maxY() >= otherRect.maxY())
    }

    /**
     Check if this rect and another rect intersect.
     */
    pub fn intersects(&self, rect: &Rect) -> bool {
        let (minXRect, otherRect) = Rect::minXRect(self, rect);

        let intersects: bool = (minXRect.maxX() >= otherRect.minX())
            && ((minXRect.minY() >= otherRect.minY() && minXRect.minY() <= otherRect.maxY())
                || (minXRect.minY() <= otherRect.minY() && minXRect.maxY() >= otherRect.minY()));

        intersects
    }

    /**
     Get the intersection with another rect.
     */
    pub fn intersect(&self, rect: &Rect) -> Option<Rect> {
        if !self.intersects(rect) {
            return None;
        }

        let (minXRect, otherXRect) = Rect::minXRect(self, rect);
        let (minYRect, otherYRect) = Rect::minYRect(self, rect);
        let commonXStart = otherXRect.minX();
        let commonYStart = otherYRect.minY();

        let commonXEnd = minXRect.maxX().min(otherXRect.maxX());
        let commonYEnd = minYRect.maxY().min(otherYRect.maxY());

        let width = commonXEnd - commonXStart;
        let height = commonYEnd - commonYStart;

        Some(Rect::new(Point::new(commonXStart, commonYStart), Size::new(width, height)))
    }

    pub fn maxX(&self) -> f64 {
        self.origin.x + self.size.width
    }

    pub fn maxY(&self) -> f64 {
        self.origin.y + self.size.height
    }

    pub fn minX(&self) -> f64 {
        self.origin.x
    }

    pub fn minY(&self) -> f64 {
        self.origin.y
    }

    pub fn height(&self) -> f64 {
        self.size.height
    }

    pub fn width(&self) -> f64 {
        self.size.width
    }
}
<|endoftext|>


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

use analysis;
use analysis::functions::Visibility;
use analysis::upcasts::Upcasts;
use chunk::{ffi_function_todo, Chunk};
use env::Env;
use super::function_body_chunk;
use super::general::{cfg_condition, version_condition};
use super::parameter::ToParameter;
use super::return_value::{out_parameters_as_return, ToReturnValue};
use writer::primitives::tabs;
use writer::ToCode;

pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::functions::Info,
    in_trait: bool, only_declaration: bool, indent: usize) -> Result<()> {
    let mut commented = false;
    let mut comment_prefix = "";
    let mut pub_prefix = if in_trait { "" } else { "pub " };
    try!(writeln!(w, ""));
    match analysis.visibility {
        Visibility::Public => {}
        Visibility::Comment => {
            commented = true;
            comment_prefix = "//";
        }
        Visibility::Private => {
            if in_trait {
                warn!("Generating trait method for private function {}", analysis.glib_name);
            }
            else {
                pub_prefix = "";
            }
        }
        Visibility::Hidden => return Ok(()),
    }
    let declaration = declaration(env, analysis);
    let suffix = if only_declaration { ";" } else { " {" };

    try!(cfg_condition(w, &analysis.cfg_condition, commented, indent));
    try!(version_condition(w, &env.config.library_name,
        env.config.min_cfg_version, analysis.version, commented, indent));
    try!(writeln!(w, "{}{}{}{}{}", tabs(indent),
        comment_prefix, pub_prefix, declaration, suffix));

    if !only_declaration {
        let body = body_chunk(env, analysis).to_code(env);
        for s in body {
            try!(writeln!(w, "{}{}", tabs(indent), s));
        }
    }

    Ok(())
}

pub fn declaration(env: &Env, analysis: &analysis::functions::Info) -> String {
    let outs_as_return = !analysis.outs.is_empty();
    let return_str = if outs_as_return {
        out_parameters_as_return(env, analysis)
    } else {
        analysis.ret.to_return_value(env)
    };
    let mut param_str = String::with_capacity(100);

    let upcasts = upcasts(&analysis.upcasts);

    for (pos, par) in analysis.parameters.iter().enumerate() {
        if outs_as_return && analysis.outs.iter().any(|p| p.name==par.name) {
            continue;
        }
        if pos > 0 { param_str.push_str(", ") }
        let s = par.to_parameter(env, &analysis.upcasts);
        param_str.push_str(&s);
    }

    format!("fn {}{}({}){}", analysis.name, upcasts, param_str, return_str)
}

fn upcasts(upcasts: &Upcasts) -> String {
    if upcasts.is_empty() { return String::new() }
    let strs: Vec<String> = upcasts.iter()
        .map(|upcast| { format!("{}: IsA<{}>", upcast.1, upcast.2)})
        .collect();
    format!("<{}>", strs.join(", "))
}

pub fn body_chunk(env: &Env, analysis: &analysis::functions::Info) -> Chunk {
    if analysis.visibility == Visibility::Comment {
        return ffi_function_todo(&analysis.glib_name);
    }

    let outs_as_return = !analysis.outs.is_empty();
    let mut builder = function_body_chunk::Builder::new();
    builder.glib_name(&analysis.glib_name)
        .assertion(analysis.assertion)
        .ret(&analysis.ret)
        .outs_mode(analysis.outs.mode);

    for par in &analysis.parameters {
        if outs_as_return && analysis.outs.iter().any(|p| p.name==par.name) {
            builder.out_parameter(&env.library, par);
        } else {
            builder.parameter(par);
        }
    }

    builder.generate()
}
<commit_msg>Remove empty line on hidden functions<commit_after>use std::io::{Result, Write};

use analysis;
use analysis::functions::Visibility;
use analysis::upcasts::Upcasts;
use chunk::{ffi_function_todo, Chunk};
use env::Env;
use super::function_body_chunk;
use super::general::{cfg_condition, version_condition};
use super::parameter::ToParameter;
use super::return_value::{out_parameters_as_return, ToReturnValue};
use writer::primitives::tabs;
use writer::ToCode;

pub fn generate(w: &mut Write, env: &Env, analysis: &analysis::functions::Info,
    in_trait: bool, only_declaration: bool, indent: usize) -> Result<()> {
    let mut commented = false;
    let mut comment_prefix = "";
    let mut pub_prefix = if in_trait { "" } else { "pub " };
    match analysis.visibility {
        Visibility::Public => {}
        Visibility::Comment => {
            commented = true;
            comment_prefix = "//";
        }
        Visibility::Private => {
            if in_trait {
                warn!("Generating trait method for private function {}", analysis.glib_name);
            }
            else {
                pub_prefix = "";
            }
        }
        Visibility::Hidden => return Ok(()),
    }
    let declaration = declaration(env, analysis);
    let suffix = if only_declaration { ";" } else { " {" };

    try!(writeln!(w, ""));
    try!(cfg_condition(w, &analysis.cfg_condition, commented, indent));
    try!(version_condition(w, &env.config.library_name,
        env.config.min_cfg_version, analysis.version, commented, indent));
    try!(writeln!(w, "{}{}{}{}{}", tabs(indent),
        comment_prefix, pub_prefix, declaration, suffix));

    if !only_declaration {
        let body = body_chunk(env, analysis).to_code(env);
        for s in body {
            try!(writeln!(w, "{}{}", tabs(indent), s));
        }
    }

    Ok(())
}

pub fn declaration(env: &Env, analysis: &analysis::functions::Info) -> String {
    let outs_as_return = !analysis.outs.is_empty();
    let return_str = if outs_as_return {
        out_parameters_as_return(env, analysis)
    } else {
        analysis.ret.to_return_value(env)
    };
    let mut param_str = String::with_capacity(100);

    let upcasts = upcasts(&analysis.upcasts);

    for (pos, par) in analysis.parameters.iter().enumerate() {
        if outs_as_return && analysis.outs.iter().any(|p| p.name==par.name) {
            continue;
        }
        if pos > 0 { param_str.push_str(", ") }
        let s = par.to_parameter(env, &analysis.upcasts);
        param_str.push_str(&s);
    }

    format!("fn {}{}({}){}", analysis.name, upcasts, param_str, return_str)
}

fn upcasts(upcasts: &Upcasts) -> String {
    if upcasts.is_empty() { return String::new() }
    let strs: Vec<String> = upcasts.iter()
        .map(|upcast| { format!("{}: IsA<{}>", upcast.1, upcast.2)})
        .collect();
    format!("<{}>", strs.join(", "))
}

pub fn body_chunk(env: &Env, analysis: &analysis::functions::Info) -> Chunk {
    if analysis.visibility == Visibility::Comment {
        return ffi_function_todo(&analysis.glib_name);
    }

    let outs_as_return = !analysis.outs.is_empty();
    let mut builder = function_body_chunk::Builder::new();
    builder.glib_name(&analysis.glib_name)
        .assertion(analysis.assertion)
        .ret(&analysis.ret)
        .outs_mode(analysis.outs.mode);

    for par in &analysis.parameters {
        if outs_as_return && analysis.outs.iter().any(|p| p.name==par.name) {
            builder.out_parameter(&env.library, par);
        } else {
            builder.parameter(par);
        }
    }

    builder.generate()
}
<|endoftext|>


<commit_before>use std::str;
use std::fmt;
use std::io::{Write,Cursor};
use super::{Serializer, Serialized};
use super::binary::Slice;
use gen::GenError;

pub trait StrSr {
  fn raw<'a>(&'a self) -> Slice<'a>;
}

impl<S: AsRef<str>> StrSr for S {
  #[inline(always)]
  fn raw<'a>(&'a self) -> Slice<'a> {
    Slice::new(self.as_ref().as_bytes())
  }
}

pub struct Print<'a, T> {
  value: &'a T,
}

impl<'a, T: fmt::Display> Serializer for Print<'a, T> {
  fn serialize<'b, 'c>(&'b mut self, output: &'c mut [u8]) -> Result<(usize, Serialized), GenError> {
    let mut c = Cursor::new(output);
    match write!(&mut c, "{}", self.value) {
      //FIXME: maybe return an error here instead of assuming the buffer is too small?
      Err(_) => Ok((0, Serialized::Continue)),
      Ok(_) => Ok((c.position() as usize, Serialized::Done))
    }
  }
}

pub trait PrintSr<'a>: Sized {
  fn print(&'a self) -> Print<'a, Self>;
}

impl<'a, T: fmt::Display> PrintSr<'a> for T {
  #[inline(always)]
  fn print(&'a self) -> Print<'a, T> {
    Print { value: self }
  }
}

pub struct PrintUpperHex<'a, T> {
  value: &'a T,
}

impl<'a, T: fmt::Display + fmt::UpperHex> Serializer for PrintUpperHex<'a, T> {
  fn serialize<'b, 'c>(&'b mut self, output: &'c mut [u8]) -> Result<(usize, Serialized), GenError> {
    let mut c = Cursor::new(output);
    match write!(&mut c, "{:X}", self.value) {
      //FIXME: maybe return an error here instead of assuming the buffer is too small?
      Err(_) => Ok((0, Serialized::Continue)),
      Ok(_) => Ok((c.position() as usize, Serialized::Done))
    }
  }
}

pub trait PrintUpperHexSr<'a>: Sized {
  fn hex(&'a self) -> PrintUpperHex<'a, Self>;
}

impl<'a, T: fmt::Display + fmt::UpperHex> PrintUpperHexSr<'a> for T {
  #[inline(always)]
  fn hex(&'a self) -> PrintUpperHex<'a, T> {
    PrintUpperHex { value: self }
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use super::super::{Serializer, Serialized};
  use std::str::from_utf8;

  #[test]
  fn str_serializer() {
    let s = String::from("hello world!");
    let mut sr = Slice::new(s.as_str().as_bytes());

    let mut mem: [u8; 6] = [0; 6];
    let s = &mut mem[..];

    assert_eq!(sr.serialize(s), Ok((6, Serialized::Continue)));
    assert_eq!(&s[..], b"hello ");

    assert_eq!(sr.serialize(s), Ok((6, Serialized::Done)));
    assert_eq!(&s[..], b"world!");
  }

  #[test]
  fn print_serializer() {
    let mut mem: [u8; 100] = [0; 100];
    let s = &mut mem[..];

    let string = "hello";
    assert_eq!(string.print().serialize(s), Ok((5, Serialized::Done)));
    assert_eq!(from_utf8(&s[..5]).unwrap(), "hello");

    let num = 1234;
    assert_eq!(num.print().serialize(s), Ok((4, Serialized::Done)));
    assert_eq!(from_utf8(&s[..4]).unwrap(), "1234");

    let f = -1.2e14f32;
    assert_eq!(f.print().serialize(s), Ok((16, Serialized::Done)));
    assert_eq!(from_utf8(&s[..16]).unwrap(), "-120000000000000");

    let f2 = 1234.56e-2f64;
    assert_eq!(f2.print().serialize(s), Ok((7, Serialized::Done)));
    assert_eq!(from_utf8(&s[..7]).unwrap(), "12.3456");
  }

  #[test]
  fn print_hex_serializer() {
    let mut mem: [u8; 100] = [0; 100];
    let s = &mut mem[..];

    let num = 257;
    assert_eq!(num.hex().serialize(s), Ok((3, Serialized::Done)));
    assert_eq!(from_utf8(&s[..3]).unwrap(), "101");
  }
}
<commit_msg>require Copy for PrintUpperHex<commit_after>use std::str;
use std::fmt;
use std::io::{Write,Cursor};
use super::{Serializer, Serialized};
use super::binary::Slice;
use gen::GenError;

pub trait StrSr {
  fn raw<'a>(&'a self) -> Slice<'a>;
}

impl<S: AsRef<str>> StrSr for S {
  #[inline(always)]
  fn raw<'a>(&'a self) -> Slice<'a> {
    Slice::new(self.as_ref().as_bytes())
  }
}

pub struct Print<'a, T> {
  value: &'a T,
}

impl<'a, T: fmt::Display> Serializer for Print<'a, T> {
  fn serialize<'b, 'c>(&'b mut self, output: &'c mut [u8]) -> Result<(usize, Serialized), GenError> {
    let mut c = Cursor::new(output);
    match write!(&mut c, "{}", self.value) {
      //FIXME: maybe return an error here instead of assuming the buffer is too small?
      Err(_) => Ok((0, Serialized::Continue)),
      Ok(_) => Ok((c.position() as usize, Serialized::Done))
    }
  }
}

pub trait PrintSr<'a>: Sized {
  fn print(&'a self) -> Print<'a, Self>;
}

impl<'a, T: fmt::Display> PrintSr<'a> for T {
  #[inline(always)]
  fn print(&'a self) -> Print<'a, T> {
    Print { value: self }
  }
}

pub struct PrintUpperHex<T> {
  value: T,
}

impl<T: fmt::Display + fmt::UpperHex> Serializer for PrintUpperHex<T> {
  fn serialize<'b, 'c>(&'b mut self, output: &'c mut [u8]) -> Result<(usize, Serialized), GenError> {
    let mut c = Cursor::new(output);
    match write!(&mut c, "{:X}", self.value) {
      //FIXME: maybe return an error here instead of assuming the buffer is too small?
      Err(_) => Ok((0, Serialized::Continue)),
      Ok(_) => Ok((c.position() as usize, Serialized::Done))
    }
  }
}

pub trait PrintUpperHexSr: Sized + Copy {
  fn hex(self) -> PrintUpperHex<Self>;
}

impl<T: fmt::Display + fmt::UpperHex + Copy> PrintUpperHexSr for T {
  #[inline(always)]
  fn hex(self) -> PrintUpperHex<T> {
    PrintUpperHex { value: self }
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use super::super::{Serializer, Serialized};
  use std::str::from_utf8;

  #[test]
  fn str_serializer() {
    let s = String::from("hello world!");
    let mut sr = Slice::new(s.as_str().as_bytes());

    let mut mem: [u8; 6] = [0; 6];
    let s = &mut mem[..];

    assert_eq!(sr.serialize(s), Ok((6, Serialized::Continue)));
    assert_eq!(&s[..], b"hello ");

    assert_eq!(sr.serialize(s), Ok((6, Serialized::Done)));
    assert_eq!(&s[..], b"world!");
  }

  #[test]
  fn print_serializer() {
    let mut mem: [u8; 100] = [0; 100];
    let s = &mut mem[..];

    let string = "hello";
    assert_eq!(string.print().serialize(s), Ok((5, Serialized::Done)));
    assert_eq!(from_utf8(&s[..5]).unwrap(), "hello");

    let num = 1234;
    assert_eq!(num.print().serialize(s), Ok((4, Serialized::Done)));
    assert_eq!(from_utf8(&s[..4]).unwrap(), "1234");

    let f = -1.2e14f32;
    assert_eq!(f.print().serialize(s), Ok((16, Serialized::Done)));
    assert_eq!(from_utf8(&s[..16]).unwrap(), "-120000000000000");

    let f2 = 1234.56e-2f64;
    assert_eq!(f2.print().serialize(s), Ok((7, Serialized::Done)));
    assert_eq!(from_utf8(&s[..7]).unwrap(), "12.3456");
  }

  #[test]
  fn print_hex_serializer() {
    let mut mem: [u8; 100] = [0; 100];
    let s = &mut mem[..];

    let num = 257;
    assert_eq!(num.hex().serialize(s), Ok((3, Serialized::Done)));
    assert_eq!(from_utf8(&s[..3]).unwrap(), "101");
  }
}
<|endoftext|>


<commit_before>#[doc(
    brief = "The attribute parsing pass",
    desc =
    "Traverses the document tree, pulling relevant documention out of the \
     corresponding AST nodes. The information gathered here is the basis \
     of the natural-language documentation for a crate."
)];

import rustc::syntax::ast;
import rustc::middle::ast_map;

export mk_pass;

fn mk_pass() -> pass {
    run
}

fn run(
    srv: astsrv::srv,
    doc: doc::cratedoc
) -> doc::cratedoc {
    let fold = fold::fold({
        fold_crate: fold_crate,
        fold_item: fold_item,
        fold_fn: fold_fn,
        fold_enum: fold_enum,
        fold_res: fold_res,
        fold_iface: fold_iface,
        fold_impl: fold_impl
        with *fold::default_any_fold(srv)
    });
    fold.fold_crate(fold, doc)
}

fn fold_crate(
    fold: fold::fold<astsrv::srv>,
    doc: doc::cratedoc
) -> doc::cratedoc {

    let srv = fold.ctxt;
    let doc = fold::default_seq_fold_crate(fold, doc);

    let attrs = astsrv::exec(srv) {|ctxt|
        let attrs = ctxt.ast.node.attrs;
        attr_parser::parse_crate(attrs)
    };

    {
        topmod: {
            item: {
                name: option::from_maybe(doc.topmod.name(), attrs.name)
                with doc.topmod.item
            }
            with doc.topmod
        }
    }
}

#[test]
fn should_replace_top_module_name_with_crate_name() {
    let doc = test::mk_doc("#[link(name = \"bond\")];");
    assert doc.topmod.name() == "bond";
}

fn fold_item(
    fold: fold::fold<astsrv::srv>,
    doc: doc::itemdoc
) -> doc::itemdoc {

    let srv = fold.ctxt;
    let doc = fold::default_seq_fold_item(fold, doc);

    let attrs = if doc.id == ast::crate_node_id {
        // This is the top-level mod, use the crate attributes
        astsrv::exec(srv) {|ctxt|
            attr_parser::parse_basic(ctxt.ast.node.attrs)
        }
    } else {
        parse_item_attrs(srv, doc.id, attr_parser::parse_basic)
    };

    {
        brief: attrs.brief,
        desc: attrs.desc
        with doc
    }
}

fn parse_item_attrs<T:send>(
    srv: astsrv::srv,
    id: doc::ast_id,
    parse_attrs: fn~([ast::attribute]) -> T) -> T {
    astsrv::exec(srv) {|ctxt|
        let attrs = alt ctxt.ast_map.get(id) {
          ast_map::node_item(item, _) { item.attrs }
          _ {
            fail "parse_item_attrs: not an item";
          }
        };
        parse_attrs(attrs)
    }
}

#[test]
fn should_should_extract_mod_attributes() {
    let doc = test::mk_doc("#[doc = \"test\"] mod a { }");
    assert doc.topmod.mods()[0].desc() == some("test");
}

#[test]
fn should_extract_top_mod_attributes() {
    let doc = test::mk_doc("#[doc = \"test\"];");
    assert doc.topmod.desc() == some("test");
}

fn fold_fn(
    fold: fold::fold<astsrv::srv>,
    doc: doc::fndoc
) -> doc::fndoc {

    let srv = fold.ctxt;

    let doc = fold::default_seq_fold_fn(fold, doc);
    let attrs = parse_item_attrs(srv, doc.id(), attr_parser::parse_fn);
    ret merge_fn_attrs(doc, attrs);

    fn merge_fn_attrs(
        doc: doc::fndoc,
        attrs: attr_parser::fn_attrs
    ) -> doc::fndoc {
        ret {
            args: merge_arg_attrs(doc.args, attrs.args),
            return: merge_ret_attrs(doc.return, attrs.return),
            failure: attrs.failure
            with doc
        };
    }
}

fn merge_arg_attrs(
    docs: [doc::argdoc],
    attrs: [attr_parser::arg_attrs]
) -> [doc::argdoc] {
    vec::map(docs) {|doc|
        alt vec::find(attrs) {|attr|
            attr.name == doc.name
        } {
            some(attr) {
                {
                    desc: some(attr.desc)
                    with doc
                }
            }
            none { doc }
        }
    }
    // FIXME: Warning when documenting a non-existent arg
}

fn merge_ret_attrs(
    doc: doc::retdoc,
    attrs: option<str>
) -> doc::retdoc {
    {
        desc: attrs
        with doc
    }
}

#[test]
fn should_extract_fn_attributes() {
    let doc = test::mk_doc("#[doc = \"test\"] fn a() -> int { }");
    assert doc.topmod.fns()[0].desc() == some("test");
}

#[test]
fn should_extract_fn_arg_attributes() {
    let doc = test::mk_doc("#[doc(args(a = \"b\"))] fn c(a: bool) { }");
    assert doc.topmod.fns()[0].args[0].desc == some("b");
}

#[test]
fn should_extract_fn_return_attributes() {
    let source = "#[doc(return = \"what\")] fn a() -> int { }";
    astsrv::from_str(source) {|srv|
        let doc = extract::from_srv(srv, "");
        let doc = tystr_pass::mk_pass()(srv, doc);
        let fold = fold::default_seq_fold(srv);
        let doc = fold_fn(fold, doc.topmod.fns()[0]);
        assert doc.return.desc == some("what");
    }
}

#[test]
fn should_preserve_fn_sig() {
    let source = "fn a() -> int { }";
    astsrv::from_str(source) {|srv|
        let doc = extract::from_srv(srv, "");
        let doc = tystr_pass::mk_pass()(srv, doc);
        let fold = fold::default_seq_fold(srv);
        let doc = fold_fn(fold, doc.topmod.fns()[0]);
        assert doc.sig == some("fn a() -> int");
    }
}

#[test]
fn should_extract_fn_failure_conditions() {
    let doc = test::mk_doc("#[doc(failure = \"what\")] fn a() { }");
    assert doc.topmod.fns()[0].failure == some("what");
}

#[test]
fn should_extract_const_docs() {
    let doc = test::mk_doc("#[doc(brief = \"foo\", desc = \"bar\")]\
                            const a: bool = true;");
    assert doc.topmod.consts()[0].brief() == some("foo");
    assert doc.topmod.consts()[0].desc() == some("bar");
}

fn fold_enum(
    fold: fold::fold<astsrv::srv>,
    doc: doc::enumdoc
) -> doc::enumdoc {
    let srv = fold.ctxt;
    let doc = fold::default_seq_fold_enum(fold, doc);

    {
        variants: vec::map(doc.variants) {|variant|
            let attrs = astsrv::exec(srv) {|ctxt|
                alt check ctxt.ast_map.get(doc.id()) {
                  ast_map::node_item(@{
                    node: ast::item_enum(ast_variants, _), _
                  }, _) {
                    let ast_variant = option::get(
                        vec::find(ast_variants) {|v|
                            v.node.name == variant.name
                        });

                    attr_parser::parse_variant(ast_variant.node.attrs)
                  }
                }
            };

            {
                desc: attrs.desc
                with variant
            }
        }
        with doc
    }
}

#[test]
fn should_extract_enum_docs() {
    let doc = test::mk_doc("#[doc(brief = \"a\", desc = \"b\")]\
                            enum a { v }");
    assert doc.topmod.enums()[0].brief() == some("a");
    assert doc.topmod.enums()[0].desc() == some("b");
}

#[test]
fn should_extract_variant_docs() {
    let doc = test::mk_doc("enum a { #[doc = \"c\"] v }");
    assert doc.topmod.enums()[0].variants[0].desc == some("c");
}

fn fold_res(
    fold: fold::fold<astsrv::srv>,
    doc: doc::resdoc
) -> doc::resdoc {

    let srv = fold.ctxt;
    let doc = fold::default_seq_fold_res(fold, doc);
    let attrs = parse_item_attrs(srv, doc.id(), attr_parser::parse_res);

    {
        args: vec::map(doc.args) {|doc|
            alt vec::find(attrs.args) {|attr|
                attr.name == doc.name
            } {
                some(attr) {
                    {
                        desc: some(attr.desc)
                        with doc
                    }
                }
                none { doc }
            }
        }
        with doc
    }
}

#[test]
fn should_extract_res_docs() {
    let doc = test::mk_doc("#[doc(brief = \"a\", desc = \"b\")]\
                            resource r(b: bool) { }");
    assert doc.topmod.resources()[0].brief() == some("a");
    assert doc.topmod.resources()[0].desc() == some("b");
}

#[test]
fn should_extract_res_arg_docs() {
    let doc = test::mk_doc("#[doc(args(a = \"b\"))]\
                            resource r(a: bool) { }");
    assert doc.topmod.resources()[0].args[0].name == "a";
    assert doc.topmod.resources()[0].args[0].desc == some("b");
}

fn fold_iface(
    fold: fold::fold<astsrv::srv>,
    doc: doc::ifacedoc
) -> doc::ifacedoc {
    let srv = fold.ctxt;
    let doc = fold::default_seq_fold_iface(fold, doc);

    {
        methods: merge_method_attrs(srv, doc.id(), doc.methods)
        with doc
    }
}

fn merge_method_attrs(
    srv: astsrv::srv,
    item_id: doc::ast_id,
    docs: [doc::methoddoc]
) -> [doc::methoddoc] {

    type method_attrs = (attr_parser::basic_attrs,
                         attr_parser::method_attrs);

    // Create an assoc list from method name to attributes
    let attrs: [(str, method_attrs)] = astsrv::exec(srv) {|ctxt|
        alt ctxt.ast_map.get(item_id) {
          ast_map::node_item(@{
            node: ast::item_iface(_, methods), _
          }, _) {
            vec::map(methods) {|method|
                (method.ident,
                 (attr_parser::parse_basic(method.attrs),
                  attr_parser::parse_method(method.attrs)
                 ))
            }
          }
          ast_map::node_item(@{
            node: ast::item_impl(_, _, _, methods), _
          }, _) {
            vec::map(methods) {|method|
                (method.ident,
                 (attr_parser::parse_basic(method.attrs),
                  attr_parser::parse_method(method.attrs)
                  ))
            }
          }
          _ { fail "unexpected item" }
        }
    };

    vec::map2(docs, attrs) {|doc, attrs|
        assert doc.name == tuple::first(attrs);
        let basic_attrs = tuple::first(tuple::second(attrs));
        let method_attrs = tuple::second(tuple::second(attrs));

        {
            brief: basic_attrs.brief,
            desc: basic_attrs.desc,
            args: merge_arg_attrs(doc.args, method_attrs.args),
            return: merge_ret_attrs(doc.return, method_attrs.return),
            failure: method_attrs.failure
            with doc
        }
    }
}

#[test]
fn should_extract_iface_docs() {
    let doc = test::mk_doc("#[doc = \"whatever\"] iface i { fn a(); }");
    assert doc.topmod.ifaces()[0].desc() == some("whatever");
}

#[test]
fn should_extract_iface_method_docs() {
    let doc = test::mk_doc(
        "iface i {\
         #[doc(\
         brief = \"brief\",\
         desc = \"desc\",\
         args(a = \"a\"),\
         return = \"return\",\
         failure = \"failure\")]\
         fn f(a: bool) -> bool;\
         }");
    assert doc.topmod.ifaces()[0].methods[0].brief == some("brief");
    assert doc.topmod.ifaces()[0].methods[0].desc == some("desc");
    assert doc.topmod.ifaces()[0].methods[0].args[0].desc == some("a");
    assert doc.topmod.ifaces()[0].methods[0].return.desc == some("return");
    assert doc.topmod.ifaces()[0].methods[0].failure == some("failure");
}

fn fold_impl(
    fold: fold::fold<astsrv::srv>,
    doc: doc::impldoc
) -> doc::impldoc {
    let srv = fold.ctxt;
    let doc = fold::default_seq_fold_impl(fold, doc);

    {
        methods: merge_method_attrs(srv, doc.id(), doc.methods)
        with doc
    }
}

#[test]
fn should_extract_impl_docs() {
    let doc = test::mk_doc(
        "#[doc = \"whatever\"] impl i for int { fn a() { } }");
    assert doc.topmod.impls()[0].desc() == some("whatever");
}

#[test]
fn should_extract_impl_method_docs() {
    let doc = test::mk_doc(
        "impl i for int {\
         #[doc(\
         brief = \"brief\",\
         desc = \"desc\",\
         args(a = \"a\"),\
         return = \"return\",\
         failure = \"failure\")]\
         fn f(a: bool) -> bool { }\
         }");
    assert doc.topmod.impls()[0].methods[0].brief == some("brief");
    assert doc.topmod.impls()[0].methods[0].desc == some("desc");
    assert doc.topmod.impls()[0].methods[0].args[0].desc == some("a");
    assert doc.topmod.impls()[0].methods[0].return.desc == some("return");
    assert doc.topmod.impls()[0].methods[0].failure == some("failure");
}

#[test]
fn should_extract_type_docs() {
    let doc = test::mk_doc(
        "#[doc(brief = \"brief\", desc = \"desc\")]\
         type t = int;");
    assert doc.topmod.types()[0].brief() == some("brief");
    assert doc.topmod.types()[0].desc() == some("desc");
}

#[cfg(test)]
mod test {
    fn mk_doc(source: str) -> doc::cratedoc {
        astsrv::from_str(source) {|srv|
            let doc = extract::from_srv(srv, "");
            run(srv, doc)
        }
    }
}<commit_msg>rustdoc: Extract attribute docs from native stuffs<commit_after>#[doc(
    brief = "The attribute parsing pass",
    desc =
    "Traverses the document tree, pulling relevant documention out of the \
     corresponding AST nodes. The information gathered here is the basis \
     of the natural-language documentation for a crate."
)];

import rustc::syntax::ast;
import rustc::middle::ast_map;

export mk_pass;

fn mk_pass() -> pass {
    run
}

fn run(
    srv: astsrv::srv,
    doc: doc::cratedoc
) -> doc::cratedoc {
    let fold = fold::fold({
        fold_crate: fold_crate,
        fold_item: fold_item,
        fold_fn: fold_fn,
        fold_enum: fold_enum,
        fold_res: fold_res,
        fold_iface: fold_iface,
        fold_impl: fold_impl
        with *fold::default_any_fold(srv)
    });
    fold.fold_crate(fold, doc)
}

fn fold_crate(
    fold: fold::fold<astsrv::srv>,
    doc: doc::cratedoc
) -> doc::cratedoc {

    let srv = fold.ctxt;
    let doc = fold::default_seq_fold_crate(fold, doc);

    let attrs = astsrv::exec(srv) {|ctxt|
        let attrs = ctxt.ast.node.attrs;
        attr_parser::parse_crate(attrs)
    };

    {
        topmod: {
            item: {
                name: option::from_maybe(doc.topmod.name(), attrs.name)
                with doc.topmod.item
            }
            with doc.topmod
        }
    }
}

#[test]
fn should_replace_top_module_name_with_crate_name() {
    let doc = test::mk_doc("#[link(name = \"bond\")];");
    assert doc.topmod.name() == "bond";
}

fn fold_item(
    fold: fold::fold<astsrv::srv>,
    doc: doc::itemdoc
) -> doc::itemdoc {

    let srv = fold.ctxt;
    let doc = fold::default_seq_fold_item(fold, doc);

    let attrs = if doc.id == ast::crate_node_id {
        // This is the top-level mod, use the crate attributes
        astsrv::exec(srv) {|ctxt|
            attr_parser::parse_basic(ctxt.ast.node.attrs)
        }
    } else {
        parse_item_attrs(srv, doc.id, attr_parser::parse_basic)
    };

    {
        brief: attrs.brief,
        desc: attrs.desc
        with doc
    }
}

fn parse_item_attrs<T:send>(
    srv: astsrv::srv,
    id: doc::ast_id,
    parse_attrs: fn~([ast::attribute]) -> T) -> T {
    astsrv::exec(srv) {|ctxt|
        let attrs = alt ctxt.ast_map.get(id) {
          ast_map::node_item(item, _) { item.attrs }
          ast_map::node_native_item(item, _) { item.attrs }
          _ {
            fail "parse_item_attrs: not an item";
          }
        };
        parse_attrs(attrs)
    }
}

#[test]
fn should_should_extract_mod_attributes() {
    let doc = test::mk_doc("#[doc = \"test\"] mod a { }");
    assert doc.topmod.mods()[0].desc() == some("test");
}

#[test]
fn should_extract_top_mod_attributes() {
    let doc = test::mk_doc("#[doc = \"test\"];");
    assert doc.topmod.desc() == some("test");
}

#[test]
fn should_extract_native_mod_attributes() {
    let doc = test::mk_doc("#[doc = \"test\"] native mod a { }");
    assert doc.topmod.nmods()[0].desc() == some("test");
}

#[test]
fn should_extract_native_fn_attributes() {
    let doc = test::mk_doc("native mod a { #[doc = \"test\"] fn a(); }");
    assert doc.topmod.nmods()[0].fns[0].desc() == some("test");
}

fn fold_fn(
    fold: fold::fold<astsrv::srv>,
    doc: doc::fndoc
) -> doc::fndoc {

    let srv = fold.ctxt;

    let doc = fold::default_seq_fold_fn(fold, doc);
    let attrs = parse_item_attrs(srv, doc.id(), attr_parser::parse_fn);
    ret merge_fn_attrs(doc, attrs);

    fn merge_fn_attrs(
        doc: doc::fndoc,
        attrs: attr_parser::fn_attrs
    ) -> doc::fndoc {
        ret {
            args: merge_arg_attrs(doc.args, attrs.args),
            return: merge_ret_attrs(doc.return, attrs.return),
            failure: attrs.failure
            with doc
        };
    }
}

fn merge_arg_attrs(
    docs: [doc::argdoc],
    attrs: [attr_parser::arg_attrs]
) -> [doc::argdoc] {
    vec::map(docs) {|doc|
        alt vec::find(attrs) {|attr|
            attr.name == doc.name
        } {
            some(attr) {
                {
                    desc: some(attr.desc)
                    with doc
                }
            }
            none { doc }
        }
    }
    // FIXME: Warning when documenting a non-existent arg
}

fn merge_ret_attrs(
    doc: doc::retdoc,
    attrs: option<str>
) -> doc::retdoc {
    {
        desc: attrs
        with doc
    }
}

#[test]
fn should_extract_fn_attributes() {
    let doc = test::mk_doc("#[doc = \"test\"] fn a() -> int { }");
    assert doc.topmod.fns()[0].desc() == some("test");
}

#[test]
fn should_extract_fn_arg_attributes() {
    let doc = test::mk_doc("#[doc(args(a = \"b\"))] fn c(a: bool) { }");
    assert doc.topmod.fns()[0].args[0].desc == some("b");
}

#[test]
fn should_extract_fn_return_attributes() {
    let source = "#[doc(return = \"what\")] fn a() -> int { }";
    astsrv::from_str(source) {|srv|
        let doc = extract::from_srv(srv, "");
        let doc = tystr_pass::mk_pass()(srv, doc);
        let fold = fold::default_seq_fold(srv);
        let doc = fold_fn(fold, doc.topmod.fns()[0]);
        assert doc.return.desc == some("what");
    }
}

#[test]
fn should_preserve_fn_sig() {
    let source = "fn a() -> int { }";
    astsrv::from_str(source) {|srv|
        let doc = extract::from_srv(srv, "");
        let doc = tystr_pass::mk_pass()(srv, doc);
        let fold = fold::default_seq_fold(srv);
        let doc = fold_fn(fold, doc.topmod.fns()[0]);
        assert doc.sig == some("fn a() -> int");
    }
}

#[test]
fn should_extract_fn_failure_conditions() {
    let doc = test::mk_doc("#[doc(failure = \"what\")] fn a() { }");
    assert doc.topmod.fns()[0].failure == some("what");
}

#[test]
fn should_extract_const_docs() {
    let doc = test::mk_doc("#[doc(brief = \"foo\", desc = \"bar\")]\
                            const a: bool = true;");
    assert doc.topmod.consts()[0].brief() == some("foo");
    assert doc.topmod.consts()[0].desc() == some("bar");
}

fn fold_enum(
    fold: fold::fold<astsrv::srv>,
    doc: doc::enumdoc
) -> doc::enumdoc {
    let srv = fold.ctxt;
    let doc = fold::default_seq_fold_enum(fold, doc);

    {
        variants: vec::map(doc.variants) {|variant|
            let attrs = astsrv::exec(srv) {|ctxt|
                alt check ctxt.ast_map.get(doc.id()) {
                  ast_map::node_item(@{
                    node: ast::item_enum(ast_variants, _), _
                  }, _) {
                    let ast_variant = option::get(
                        vec::find(ast_variants) {|v|
                            v.node.name == variant.name
                        });

                    attr_parser::parse_variant(ast_variant.node.attrs)
                  }
                }
            };

            {
                desc: attrs.desc
                with variant
            }
        }
        with doc
    }
}

#[test]
fn should_extract_enum_docs() {
    let doc = test::mk_doc("#[doc(brief = \"a\", desc = \"b\")]\
                            enum a { v }");
    assert doc.topmod.enums()[0].brief() == some("a");
    assert doc.topmod.enums()[0].desc() == some("b");
}

#[test]
fn should_extract_variant_docs() {
    let doc = test::mk_doc("enum a { #[doc = \"c\"] v }");
    assert doc.topmod.enums()[0].variants[0].desc == some("c");
}

fn fold_res(
    fold: fold::fold<astsrv::srv>,
    doc: doc::resdoc
) -> doc::resdoc {

    let srv = fold.ctxt;
    let doc = fold::default_seq_fold_res(fold, doc);
    let attrs = parse_item_attrs(srv, doc.id(), attr_parser::parse_res);

    {
        args: vec::map(doc.args) {|doc|
            alt vec::find(attrs.args) {|attr|
                attr.name == doc.name
            } {
                some(attr) {
                    {
                        desc: some(attr.desc)
                        with doc
                    }
                }
                none { doc }
            }
        }
        with doc
    }
}

#[test]
fn should_extract_res_docs() {
    let doc = test::mk_doc("#[doc(brief = \"a\", desc = \"b\")]\
                            resource r(b: bool) { }");
    assert doc.topmod.resources()[0].brief() == some("a");
    assert doc.topmod.resources()[0].desc() == some("b");
}

#[test]
fn should_extract_res_arg_docs() {
    let doc = test::mk_doc("#[doc(args(a = \"b\"))]\
                            resource r(a: bool) { }");
    assert doc.topmod.resources()[0].args[0].name == "a";
    assert doc.topmod.resources()[0].args[0].desc == some("b");
}

fn fold_iface(
    fold: fold::fold<astsrv::srv>,
    doc: doc::ifacedoc
) -> doc::ifacedoc {
    let srv = fold.ctxt;
    let doc = fold::default_seq_fold_iface(fold, doc);

    {
        methods: merge_method_attrs(srv, doc.id(), doc.methods)
        with doc
    }
}

fn merge_method_attrs(
    srv: astsrv::srv,
    item_id: doc::ast_id,
    docs: [doc::methoddoc]
) -> [doc::methoddoc] {

    type method_attrs = (attr_parser::basic_attrs,
                         attr_parser::method_attrs);

    // Create an assoc list from method name to attributes
    let attrs: [(str, method_attrs)] = astsrv::exec(srv) {|ctxt|
        alt ctxt.ast_map.get(item_id) {
          ast_map::node_item(@{
            node: ast::item_iface(_, methods), _
          }, _) {
            vec::map(methods) {|method|
                (method.ident,
                 (attr_parser::parse_basic(method.attrs),
                  attr_parser::parse_method(method.attrs)
                 ))
            }
          }
          ast_map::node_item(@{
            node: ast::item_impl(_, _, _, methods), _
          }, _) {
            vec::map(methods) {|method|
                (method.ident,
                 (attr_parser::parse_basic(method.attrs),
                  attr_parser::parse_method(method.attrs)
                  ))
            }
          }
          _ { fail "unexpected item" }
        }
    };

    vec::map2(docs, attrs) {|doc, attrs|
        assert doc.name == tuple::first(attrs);
        let basic_attrs = tuple::first(tuple::second(attrs));
        let method_attrs = tuple::second(tuple::second(attrs));

        {
            brief: basic_attrs.brief,
            desc: basic_attrs.desc,
            args: merge_arg_attrs(doc.args, method_attrs.args),
            return: merge_ret_attrs(doc.return, method_attrs.return),
            failure: method_attrs.failure
            with doc
        }
    }
}

#[test]
fn should_extract_iface_docs() {
    let doc = test::mk_doc("#[doc = \"whatever\"] iface i { fn a(); }");
    assert doc.topmod.ifaces()[0].desc() == some("whatever");
}

#[test]
fn should_extract_iface_method_docs() {
    let doc = test::mk_doc(
        "iface i {\
         #[doc(\
         brief = \"brief\",\
         desc = \"desc\",\
         args(a = \"a\"),\
         return = \"return\",\
         failure = \"failure\")]\
         fn f(a: bool) -> bool;\
         }");
    assert doc.topmod.ifaces()[0].methods[0].brief == some("brief");
    assert doc.topmod.ifaces()[0].methods[0].desc == some("desc");
    assert doc.topmod.ifaces()[0].methods[0].args[0].desc == some("a");
    assert doc.topmod.ifaces()[0].methods[0].return.desc == some("return");
    assert doc.topmod.ifaces()[0].methods[0].failure == some("failure");
}

fn fold_impl(
    fold: fold::fold<astsrv::srv>,
    doc: doc::impldoc
) -> doc::impldoc {
    let srv = fold.ctxt;
    let doc = fold::default_seq_fold_impl(fold, doc);

    {
        methods: merge_method_attrs(srv, doc.id(), doc.methods)
        with doc
    }
}

#[test]
fn should_extract_impl_docs() {
    let doc = test::mk_doc(
        "#[doc = \"whatever\"] impl i for int { fn a() { } }");
    assert doc.topmod.impls()[0].desc() == some("whatever");
}

#[test]
fn should_extract_impl_method_docs() {
    let doc = test::mk_doc(
        "impl i for int {\
         #[doc(\
         brief = \"brief\",\
         desc = \"desc\",\
         args(a = \"a\"),\
         return = \"return\",\
         failure = \"failure\")]\
         fn f(a: bool) -> bool { }\
         }");
    assert doc.topmod.impls()[0].methods[0].brief == some("brief");
    assert doc.topmod.impls()[0].methods[0].desc == some("desc");
    assert doc.topmod.impls()[0].methods[0].args[0].desc == some("a");
    assert doc.topmod.impls()[0].methods[0].return.desc == some("return");
    assert doc.topmod.impls()[0].methods[0].failure == some("failure");
}

#[test]
fn should_extract_type_docs() {
    let doc = test::mk_doc(
        "#[doc(brief = \"brief\", desc = \"desc\")]\
         type t = int;");
    assert doc.topmod.types()[0].brief() == some("brief");
    assert doc.topmod.types()[0].desc() == some("desc");
}

#[cfg(test)]
mod test {
    fn mk_doc(source: str) -> doc::cratedoc {
        astsrv::from_str(source) {|srv|
            let doc = extract::from_srv(srv, "");
            run(srv, doc)
        }
    }
}<|endoftext|>