<commit_before>use bifrost::rpc::*;
use client::AsyncClient;
use index::lsmtree::service::inner::LSMTreeIns;
use index::lsmtree::tree::LSMTree;
use index::{EntryKey, Ordering};
use parking_lot::RwLock;
use smallvec::SmallVec;
use std::collections::HashMap;
use std::path::Component::CurDir;
use std::sync::atomic;
use std::sync::atomic::AtomicU64;

#[derive(Serialize, Deserialize)]
enum LSMTreeSvrError {
    TreeNotFound,
}

#[derive(Serialize, Deserialize)]
struct LSMTreeSummary {
    id: u64,
    count: u64,
    range: (Vec<u8>, Vec<u8>),
}

service! {
    rpc seek(tree_id: u64, key: Vec<u8>, ordering: Ordering) -> u64 | LSMTreeSvrError;
    rpc next(tree_id: u64, id: u64) -> Option<bool> | LSMTreeSvrError;
    rpc current(tree_id: u64, id: u64) -> Option<Option<Vec<u8>>> | LSMTreeSvrError;
    rpc complete(tree_id: u64, id: u64) -> bool | LSMTreeSvrError;
    rpc new_tree(start: Vec<u8>, end: Vec<u8>) -> u64;
    rpc summary() -> Vec<LSMTreeSummary>;
}

pub struct LSMTreeService {
    neb_client: Arc<AsyncClient>,
    counter: AtomicU64,
    trees: RwLock<HashMap<u64, LSMTreeIns>>,
}

dispatch_rpc_service_functions!(LSMTreeService);

impl Service for LSMTreeService {
    fn seek(
        &self,
        tree_id: u64,
        key: Vec<u8>,
        ordering: Ordering,
    ) -> Box<Future<Item = u64, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| tree.seek(SmallVec::from(key), ordering)),
        )
    }

    fn next(
        &self,
        tree_id: u64,
        id: u64,
    ) -> Box<Future<Item = Option<bool>, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| tree.next(&id)),
        )
    }

    fn current(
        &self,
        tree_id: u64,
        id: u64,
    ) -> Box<Future<Item = Option<Option<Vec<u8>>>, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| tree.current(&id)),
        )
    }

    fn complete(&self, tree_id: u64, id: u64) -> Box<Future<Item = bool, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| tree.complete(&id)),
        )
    }

    fn new_tree(&self, start: Vec<u8>, end: Vec<u8>) -> Box<Future<Item = u64, Error = ()>> {
        let mut trees = self.trees.write();
        let tree_id = self.counter.fetch_add(1, atomic::Ordering::Relaxed);
        trees.insert(
            tree_id,
            LSMTreeIns::new(
                &self.neb_client,
                (EntryKey::from(start), EntryKey::from(end)),
            ),
        );
        box future::ok(tree_id)
    }

    fn summary(&self) -> Box<Future<Item = Vec<LSMTreeSummary>, Error = ()>> {
        let trees = self.trees.read();
        box future::ok(
            trees
                .iter()
                .map(|(id, tree)| LSMTreeSummary {
                    id: *id,
                    count: tree.count(),
                    range: tree.range(),
                })
                .collect(),
        )
    }
}

impl LSMTreeService {
    pub fn new(neb_client: &Arc<AsyncClient>) -> Arc<Self> {
        Arc::new(Self {
            neb_client: neb_client.clone(),
            counter: AtomicU64::new(0),
            trees: RwLock::new(HashMap::new()),
        })
    }
}
<commit_msg>sort summary result<commit_after>use bifrost::rpc::*;
use client::AsyncClient;
use index::lsmtree::service::inner::LSMTreeIns;
use index::lsmtree::tree::LSMTree;
use index::{EntryKey, Ordering};
use parking_lot::RwLock;
use smallvec::SmallVec;
use std::collections::HashMap;
use std::path::Component::CurDir;
use std::sync::atomic;
use std::sync::atomic::AtomicU64;
use itertools::Itertools;

#[derive(Serialize, Deserialize)]
enum LSMTreeSvrError {
    TreeNotFound,
}

#[derive(Serialize, Deserialize)]
struct LSMTreeSummary {
    id: u64,
    count: u64,
    range: (Vec<u8>, Vec<u8>),
}

service! {
    rpc seek(tree_id: u64, key: Vec<u8>, ordering: Ordering) -> u64 | LSMTreeSvrError;
    rpc next(tree_id: u64, id: u64) -> Option<bool> | LSMTreeSvrError;
    rpc current(tree_id: u64, id: u64) -> Option<Option<Vec<u8>>> | LSMTreeSvrError;
    rpc complete(tree_id: u64, id: u64) -> bool | LSMTreeSvrError;
    rpc new_tree(start: Vec<u8>, end: Vec<u8>) -> u64;
    rpc summary() -> Vec<LSMTreeSummary>;
}

pub struct LSMTreeService {
    neb_client: Arc<AsyncClient>,
    counter: AtomicU64,
    trees: RwLock<HashMap<u64, LSMTreeIns>>,
}

dispatch_rpc_service_functions!(LSMTreeService);

impl Service for LSMTreeService {
    fn seek(
        &self,
        tree_id: u64,
        key: Vec<u8>,
        ordering: Ordering,
    ) -> Box<Future<Item = u64, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| tree.seek(SmallVec::from(key), ordering)),
        )
    }

    fn next(
        &self,
        tree_id: u64,
        id: u64,
    ) -> Box<Future<Item = Option<bool>, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| tree.next(&id)),
        )
    }

    fn current(
        &self,
        tree_id: u64,
        id: u64,
    ) -> Box<Future<Item = Option<Option<Vec<u8>>>, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| tree.current(&id)),
        )
    }

    fn complete(&self, tree_id: u64, id: u64) -> Box<Future<Item = bool, Error = LSMTreeSvrError>> {
        let trees = self.trees.read();
        box future::result(
            trees
                .get(&tree_id)
                .ok_or(LSMTreeSvrError::TreeNotFound)
                .map(|tree| tree.complete(&id)),
        )
    }

    fn new_tree(&self, start: Vec<u8>, end: Vec<u8>) -> Box<Future<Item = u64, Error = ()>> {
        let mut trees = self.trees.write();
        let tree_id = self.counter.fetch_add(1, atomic::Ordering::Relaxed);
        trees.insert(
            tree_id,
            LSMTreeIns::new(
                &self.neb_client,
                (EntryKey::from(start), EntryKey::from(end)),
            ),
        );
        box future::ok(tree_id)
    }

    fn summary(&self) -> Box<Future<Item = Vec<LSMTreeSummary>, Error = ()>> {
        let trees = self.trees.read();
        box future::ok(
            trees
                .iter()
                .map(|(id, tree)| LSMTreeSummary {
                    id: *id,
                    count: tree.count(),
                    range: tree.range(),
                })
                .sorted_by_key(|tree| tree.range.0.clone())
                .collect(),
        )
    }
}

impl LSMTreeService {
    pub fn new(neb_client: &Arc<AsyncClient>) -> Arc<Self> {
        Arc::new(Self {
            neb_client: neb_client.clone(),
            counter: AtomicU64::new(0),
            trees: RwLock::new(HashMap::new()),
        })
    }
}
<|endoftext|>


<commit_before>extern crate rustty;

use rustty::{
    Terminal,
    Cell,
    Event,
    Style,
    Color,
    Attr,
};

struct Cursor {
    pos: Position,
    lpos: Position,
    style: Style,
}

#[derive(Copy, Clone)]
struct Position {
    x: usize,
    y: usize,
}

fn main() {
    let mut cursor = Cursor {
        pos: Position { x: 0, y: 0 },
        lpos: Position { x: 0, y: 0 },
        style: Style::with_color(Color::Red),
    };
    let mut term = Terminal::new().unwrap();
    term[cursor.pos.x][cursor.pos.y].set_bg(cursor.style);
    term.swap_buffers().unwrap();
    loop {
        let evt = term.get_event(100).unwrap();
        if let Some(Event::Key(ch)) = evt {
            match ch {
                '`' => {
                    break;
                },
                '\x7f' => {
                    cursor.lpos = cursor.pos;
                    if cursor.pos.x == 0 {
                        cursor.pos.y = cursor.pos.y.saturating_sub(1);
                    } else {
                        cursor.pos.x -= 1;
                    }
                    term[cursor.pos.x][cursor.pos.y].set_ch(' ');
                },
                '\r' => {
                    cursor.lpos = cursor.pos;
                    cursor.pos.x = 0;
                    cursor.pos.y += 1;
                },
                c @ _ => {
                    term[cursor.pos.x][cursor.pos.y].set_ch(c);
                    cursor.lpos = cursor.pos;
                    cursor.pos.x += 1;
                },
            }
            if cursor.pos.x >= term.cols()-1 {
                cursor.lpos = cursor.pos;
                cursor.pos.x = 0;
                cursor.pos.y += 1;
            }
            if cursor.pos.y >= term.rows()-1 {
                cursor.lpos = cursor.pos;
                cursor.pos.x = 0;
                cursor.pos.y = 0;
            }
            term[cursor.lpos.x][cursor.lpos.y].set_bg(Style::default());
            term[cursor.pos.x][cursor.pos.y].set_bg(cursor.style);
            term.swap_buffers().unwrap();
        }
    }
}

<commit_msg>better example<commit_after>extern crate rustty;

use rustty::{
    Terminal,
    Cell,
    Event,
    Style,
    Color,
    Attr,
};

struct Cursor {
    pos: Position,
    lpos: Position,
    style: Style,
}

#[derive(Copy, Clone)]
struct Position {
    x: usize,
    y: usize,
}

fn main() {
    let mut cursor = Cursor {
        pos: Position { x: 0, y: 0 },
        lpos: Position { x: 0, y: 0 },
        style: Style::with_color(Color::Red),
    };
    let mut term = Terminal::new().unwrap();
    term[cursor.pos.x][cursor.pos.y].set_bg(cursor.style);
    term.swap_buffers().unwrap();
    loop {
        let evt = term.get_event(100).unwrap();
        if let Some(Event::Key(ch)) = evt {
            match ch {
                '`' => {
                    break;
                },
                '\x7f' => {
                    cursor.lpos = cursor.pos;
                    if cursor.pos.x == 0 {
                        cursor.pos.y = cursor.pos.y.saturating_sub(1);
                    } else {
                        cursor.pos.x -= 1;
                    }
                    term[cursor.pos.x][cursor.pos.y].set_ch(' ');
                },
                '\r' => {
                    cursor.lpos = cursor.pos;
                    cursor.pos.x = 0;
                    cursor.pos.y += 1;
                },
                c @ _ => {
                    term[cursor.pos.x][cursor.pos.y].set_ch(c);
                    cursor.lpos = cursor.pos;
                    cursor.pos.x += 1;
                },
            }
            if cursor.pos.x >= term.cols()-1 {
                term[cursor.lpos.x][cursor.lpos.y].set_bg(Style::default());
                cursor.lpos = cursor.pos;
                cursor.pos.x = 0;
                cursor.pos.y += 1;
            }
            if cursor.pos.y >= term.rows()-1 {
                term[cursor.lpos.x][cursor.lpos.y].set_bg(Style::default());
                cursor.lpos = cursor.pos;
                cursor.pos.x = 0;
                cursor.pos.y = 0;
            }
            term[cursor.lpos.x][cursor.lpos.y].set_bg(Style::default());
            term[cursor.pos.x][cursor.pos.y].set_bg(cursor.style);
            term.swap_buffers().unwrap();
        }
    }
}

<|endoftext|>


<commit_before>//! Asynchronous notifications.

use std::fmt;
use std::time::Duration;

use {desynchronized, Result, Connection, NotificationsNew};
use message::BackendMessage::NotificationResponse;
use error::Error;

/// An asynchronous notification.
#[derive(Clone, Debug)]
pub struct Notification {
    /// The process ID of the notifying backend process.
    pub pid: u32,
    /// The name of the channel that the notify has been raised on.
    pub channel: String,
    /// The "payload" string passed from the notifying process.
    pub payload: String,
}

/// An iterator over asynchronous notifications.
pub struct Notifications<'conn> {
    conn: &'conn Connection
}

impl<'a> fmt::Debug for Notifications<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("Notifications")
            .field("pending", &self.len())
            .finish()
    }
}

impl<'conn> Notifications<'conn> {
    /// Returns the number of pending notifications.
    pub fn len(&self) -> usize {
        self.conn.conn.borrow().notifications.len()
    }

    /// Returns an iterator over pending notifications.
    ///
    /// # Note
    ///
    /// This iterator may start returning `Some` after previously returning
    /// `None` if more notifications are received.
    pub fn iter<'a>(&'a self) -> Iter<'a> {
        Iter {
            conn: self.conn,
        }
    }

    /// Returns an iterator over notifications that blocks until one is
    /// received if none are pending.
    ///
    /// The iterator will never return `None`.
    pub fn blocking_iter<'a>(&'a self) -> BlockingIter<'a> {
        BlockingIter {
            conn: self.conn,
        }
    }

    /// Returns an iterator over notifications that blocks for a limited time
    /// waiting to receive one if none are pending.
    ///
    /// # Note
    ///
    /// THis iterator may start returning `Some` after previously returning
    /// `None` if more notifications are received.
    pub fn timeout_iter<'a>(&'a self, timeout: Duration) -> TimeoutIter<'a> {
        TimeoutIter {
            conn: self.conn,
            timeout: timeout,
        }
    }
}

impl<'a, 'conn> IntoIterator for &'a Notifications<'conn> {
    type Item = Notification;
    type IntoIter = Iter<'a>;

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

impl<'conn> NotificationsNew<'conn> for Notifications<'conn> {
    fn new(conn: &'conn Connection) -> Notifications<'conn> {
        Notifications {
            conn: conn,
        }
    }
}

/// An iterator over pending notifications.
pub struct Iter<'a> {
    conn: &'a Connection,
}

impl<'a> Iterator for Iter<'a> {
    type Item = Notification;

    fn next(&mut self) -> Option<Notification> {
        self.conn.conn.borrow_mut().notifications.pop_front()
    }
}

/// An iterator over notifications which will block if none are pending.
pub struct BlockingIter<'a> {
    conn: &'a Connection,
}

impl<'a> Iterator for BlockingIter<'a> {
    type Item = Result<Notification>;

    fn next(&mut self) -> Option<Result<Notification>> {
        let mut conn = self.conn.conn.borrow_mut();

        if let Some(notification) = conn.notifications.pop_front() {
            return Some(Ok(notification));
        }

        if conn.is_desynchronized() {
            return Some(Err(Error::IoError(desynchronized())));
        }

        match conn.read_message_with_notification() {
            Ok(NotificationResponse { pid, channel, payload }) => {
                Some(Ok(Notification {
                    pid: pid,
                    channel: channel,
                    payload: payload
                }))
            }
            Err(err) => Some(Err(Error::IoError(err))),
            _ => unreachable!()
        }
    }
}

/// An iterator over notifications which will block for a period of time if
/// none are pending.
pub struct TimeoutIter<'a> {
    conn: &'a Connection,
    timeout: Duration,
}

impl<'a> Iterator for TimeoutIter<'a> {
    type Item = Result<Notification>;

    fn next(&mut self) -> Option<Result<Notification>> {
        let mut conn = self.conn.conn.borrow_mut();

        if let Some(notification) = conn.notifications.pop_front() {
            return Some(Ok(notification));
        }

        if conn.is_desynchronized() {
            return Some(Err(Error::IoError(desynchronized())));
        }

        match conn.read_message_with_notification_timeout(self.timeout) {
            Ok(Some(NotificationResponse { pid, channel, payload })) => {
                Some(Ok(Notification {
                    pid: pid,
                    channel: channel,
                    payload: payload
                }))
            }
            Ok(None) => None,
            Err(err) => Some(Err(Error::IoError(err))),
            _ => unreachable!()
        }
    }
}
<commit_msg>Note notification pickup caveat for nonblocking iterator<commit_after>//! Asynchronous notifications.

use std::fmt;
use std::time::Duration;

use {desynchronized, Result, Connection, NotificationsNew};
use message::BackendMessage::NotificationResponse;
use error::Error;

/// An asynchronous notification.
#[derive(Clone, Debug)]
pub struct Notification {
    /// The process ID of the notifying backend process.
    pub pid: u32,
    /// The name of the channel that the notify has been raised on.
    pub channel: String,
    /// The "payload" string passed from the notifying process.
    pub payload: String,
}

/// An iterator over asynchronous notifications.
pub struct Notifications<'conn> {
    conn: &'conn Connection
}

impl<'a> fmt::Debug for Notifications<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("Notifications")
            .field("pending", &self.len())
            .finish()
    }
}

impl<'conn> Notifications<'conn> {
    /// Returns the number of pending notifications.
    pub fn len(&self) -> usize {
        self.conn.conn.borrow().notifications.len()
    }

    /// Returns an iterator over pending notifications.
    ///
    /// # Note
    ///
    /// This iterator may start returning `Some` after previously returning
    /// `None` if more notifications are received. However, those notifications
    /// will not be registered until the connection is used in some way.
    pub fn iter<'a>(&'a self) -> Iter<'a> {
        Iter {
            conn: self.conn,
        }
    }

    /// Returns an iterator over notifications that blocks until one is
    /// received if none are pending.
    ///
    /// The iterator will never return `None`.
    pub fn blocking_iter<'a>(&'a self) -> BlockingIter<'a> {
        BlockingIter {
            conn: self.conn,
        }
    }

    /// Returns an iterator over notifications that blocks for a limited time
    /// waiting to receive one if none are pending.
    ///
    /// # Note
    ///
    /// THis iterator may start returning `Some` after previously returning
    /// `None` if more notifications are received.
    pub fn timeout_iter<'a>(&'a self, timeout: Duration) -> TimeoutIter<'a> {
        TimeoutIter {
            conn: self.conn,
            timeout: timeout,
        }
    }
}

impl<'a, 'conn> IntoIterator for &'a Notifications<'conn> {
    type Item = Notification;
    type IntoIter = Iter<'a>;

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

impl<'conn> NotificationsNew<'conn> for Notifications<'conn> {
    fn new(conn: &'conn Connection) -> Notifications<'conn> {
        Notifications {
            conn: conn,
        }
    }
}

/// An iterator over pending notifications.
pub struct Iter<'a> {
    conn: &'a Connection,
}

impl<'a> Iterator for Iter<'a> {
    type Item = Notification;

    fn next(&mut self) -> Option<Notification> {
        self.conn.conn.borrow_mut().notifications.pop_front()
    }
}

/// An iterator over notifications which will block if none are pending.
pub struct BlockingIter<'a> {
    conn: &'a Connection,
}

impl<'a> Iterator for BlockingIter<'a> {
    type Item = Result<Notification>;

    fn next(&mut self) -> Option<Result<Notification>> {
        let mut conn = self.conn.conn.borrow_mut();

        if let Some(notification) = conn.notifications.pop_front() {
            return Some(Ok(notification));
        }

        if conn.is_desynchronized() {
            return Some(Err(Error::IoError(desynchronized())));
        }

        match conn.read_message_with_notification() {
            Ok(NotificationResponse { pid, channel, payload }) => {
                Some(Ok(Notification {
                    pid: pid,
                    channel: channel,
                    payload: payload
                }))
            }
            Err(err) => Some(Err(Error::IoError(err))),
            _ => unreachable!()
        }
    }
}

/// An iterator over notifications which will block for a period of time if
/// none are pending.
pub struct TimeoutIter<'a> {
    conn: &'a Connection,
    timeout: Duration,
}

impl<'a> Iterator for TimeoutIter<'a> {
    type Item = Result<Notification>;

    fn next(&mut self) -> Option<Result<Notification>> {
        let mut conn = self.conn.conn.borrow_mut();

        if let Some(notification) = conn.notifications.pop_front() {
            return Some(Ok(notification));
        }

        if conn.is_desynchronized() {
            return Some(Err(Error::IoError(desynchronized())));
        }

        match conn.read_message_with_notification_timeout(self.timeout) {
            Ok(Some(NotificationResponse { pid, channel, payload })) => {
                Some(Ok(Notification {
                    pid: pid,
                    channel: channel,
                    payload: payload
                }))
            }
            Ok(None) => None,
            Err(err) => Some(Err(Error::IoError(err))),
            _ => unreachable!()
        }
    }
}
<|endoftext|>


<commit_before>//! `ra_lsp_server` binary

use lsp_server::Connection;
use ra_lsp_server::{show_message, Result, ServerConfig};
use ra_prof;

fn main() -> Result<()> {
    setup_logging()?;
    match Args::parse()? {
        Args::Version => println!("rust-analyzer {}", env!("REV")),
        Args::Run => run_server()?,
    }
    Ok(())
}

fn setup_logging() -> Result<()> {
    std::env::set_var("RUST_BACKTRACE", "short");

    env_logger::try_init()?;

    ra_prof::set_filter(match std::env::var("RA_PROFILE") {
        Ok(spec) => ra_prof::Filter::from_spec(&spec),
        Err(_) => ra_prof::Filter::disabled(),
    });
    Ok(())
}

enum Args {
    Version,
    Run,
}

impl Args {
    fn parse() -> Result<Args> {
        let res =
            if std::env::args().any(|it| it == "--version") { Args::Version } else { Args::Run };
        Ok(res)
    }
}

fn run_server() -> Result<()> {
    log::info!("lifecycle: server started");

    let (connection, io_threads) = Connection::stdio();
    let server_capabilities = serde_json::to_value(ra_lsp_server::server_capabilities()).unwrap();

    let initialize_params = connection.initialize(server_capabilities)?;
    let initialize_params: lsp_types::InitializeParams = serde_json::from_value(initialize_params)?;

    let cwd = std::env::current_dir()?;
    let root = initialize_params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd);

    let workspace_roots = initialize_params
        .workspace_folders
        .map(|workspaces| {
            workspaces.into_iter().filter_map(|it| it.uri.to_file_path().ok()).collect::<Vec<_>>()
        })
        .filter(|workspaces| !workspaces.is_empty())
        .unwrap_or_else(|| vec![root]);

    let server_config: ServerConfig = initialize_params
        .initialization_options
        .and_then(|v| {
            serde_json::from_value(v)
                .map_err(|e| {
                    log::error!("failed to deserialize config: {}", e);
                    show_message(
                        lsp_types::MessageType::Error,
                        format!("failed to deserialize config: {}", e),
                        &connection.sender,
                    );
                })
                .ok()
        })
        .unwrap_or_default();

    ra_lsp_server::main_loop(
        workspace_roots,
        initialize_params.capabilities,
        server_config,
        connection,
    )?;

    log::info!("shutting down IO...");
    io_threads.join()?;
    log::info!("... IO is down");
    Ok(())
}
<commit_msg>Log client info if present<commit_after>//! `ra_lsp_server` binary

use lsp_server::Connection;
use ra_lsp_server::{show_message, Result, ServerConfig};
use ra_prof;

fn main() -> Result<()> {
    setup_logging()?;
    match Args::parse()? {
        Args::Version => println!("rust-analyzer {}", env!("REV")),
        Args::Run => run_server()?,
    }
    Ok(())
}

fn setup_logging() -> Result<()> {
    std::env::set_var("RUST_BACKTRACE", "short");

    env_logger::try_init()?;

    ra_prof::set_filter(match std::env::var("RA_PROFILE") {
        Ok(spec) => ra_prof::Filter::from_spec(&spec),
        Err(_) => ra_prof::Filter::disabled(),
    });
    Ok(())
}

enum Args {
    Version,
    Run,
}

impl Args {
    fn parse() -> Result<Args> {
        let res =
            if std::env::args().any(|it| it == "--version") { Args::Version } else { Args::Run };
        Ok(res)
    }
}

fn run_server() -> Result<()> {
    log::info!("lifecycle: server started");

    let (connection, io_threads) = Connection::stdio();
    let server_capabilities = serde_json::to_value(ra_lsp_server::server_capabilities()).unwrap();

    let initialize_params = connection.initialize(server_capabilities)?;
    let initialize_params: lsp_types::InitializeParams = serde_json::from_value(initialize_params)?;

    if let Some(client_info) = initialize_params.client_info {
        log::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default());
    }

    let cwd = std::env::current_dir()?;
    let root = initialize_params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd);

    let workspace_roots = initialize_params
        .workspace_folders
        .map(|workspaces| {
            workspaces.into_iter().filter_map(|it| it.uri.to_file_path().ok()).collect::<Vec<_>>()
        })
        .filter(|workspaces| !workspaces.is_empty())
        .unwrap_or_else(|| vec![root]);

    let server_config: ServerConfig = initialize_params
        .initialization_options
        .and_then(|v| {
            serde_json::from_value(v)
                .map_err(|e| {
                    log::error!("failed to deserialize config: {}", e);
                    show_message(
                        lsp_types::MessageType::Error,
                        format!("failed to deserialize config: {}", e),
                        &connection.sender,
                    );
                })
                .ok()
        })
        .unwrap_or_default();

    ra_lsp_server::main_loop(
        workspace_roots,
        initialize_params.capabilities,
        server_config,
        connection,
    )?;

    log::info!("shutting down IO...");
    io_threads.join()?;
    log::info!("... IO is down");
    Ok(())
}
<|endoftext|>


<commit_before>//! List projects
//!
//! https://docs.gitlab.com/ce/api/projects.html
//!
//! # List projects
//!
//! Get a list of projects for which the authenticated user is a member.
//!
//! ```text
//! GET /projects
//! ```
//!
//! Parameters:
//!
//! | Attribute | Type | Required | Description |
//! | --------- | ---- | -------- | ----------- |
//! | `archived` | boolean | no | Limit by archived status |
//! | `visibility` | string | no | Limit by visibility `public`, `internal`, or `private` |
//! | `order_by` | string | no | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at` |
//! | `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
//! | `search` | string | no | Return list of authorized projects matching the search criteria |
//! | `simple` | boolean | no | Return only the ID, URL, name, and path of each project |
//!

use BuildQuery;

use serde_json;

use gitlab::GitLab;
use Projects;

pub mod all;
pub mod id_branches;
pub mod id_branch;
pub mod id_events;
pub mod id_hooks_id;
pub mod id_hooks;
pub mod id;
pub mod owned;
pub mod search;
pub mod starred;
pub mod visible;

// TODO:
//
// Creates a new project owned by the authenticated user.
// POST /projects
//
// Creates a new project owned by the specified user. Available only for admins.
// POST /projects/user/:user_id
//
// Updates an existing project
// PUT /projects/:id
//
// Forks a project into the user namespace of the authenticated user or the one provided.
// POST /projects/fork/:id
//
// Stars a given project. Returns status code `201` and the project on success and `304` if the
// project is already starred.
// POST /projects/:id/star
//
// Unstars a given project. Returns status code `200` and the project on success and `304` if the
// project is not starred.
// DELETE /projects/:id/star
//
// Archives the project if the user is either admin or the project owner of this project. This
// action is idempotent, thus archiving an already archived project will not change the project.
//
// Status code `201` with the project as body is given when successful, in case the user doesn't
// have the proper access rights, code `403` is returned. Status `404` is returned if the project
// doesn't exist, or is hidden to the user.
// POST /projects/:id/archive
//
//
// Unarchives the project if the user is either admin or the project owner of this project. This
// action is idempotent, thus unarchiving an non-archived project will not change the project.
//
// Status code `201` with the project as body is given when successful, in case the user doesn't
// have the proper access rights, code `403` is returned. Status `404` is returned if the project
// doesn't exist, or is hidden to the user.
// POST /projects/:id/unarchive
//
//
// Removes a project including all associated resources (issues, merge requests etc.)
// DELETE /projects/:id
//
//
// Uploads a file to the specified project to be used in an issue or merge request description, or
// a comment.
// POST /projects/:id/uploads
//
//
// Allow to share project with group.
// POST /projects/:id/share
//
//
// Adds a hook to a specified project.
// POST /projects/:id/hooks
//
//
// Edits a hook for a specified project.
// PUT /projects/:id/hooks/:hook_id
//
//
// Removes a hook from a project. This is an idempotent method and can be called multiple times.
// Either the hook is available or not.
// DELETE /projects/:id/hooks/:hook_id
//
//
// Protects a single branch of a project.
// PUT /projects/:id/repository/branches/:branch/protect
//
//
// Unprotects a single branch of a project.
// PUT /projects/:id/repository/branches/:branch/unprotect
//
//
// Create a forked from/to relation between existing projects.
// POST /projects/:id/fork/:forked_from_id
//
//
// Delete an existing forked from relationship
// DELETE /projects/:id/fork
//

impl GitLab {
    pub fn projects(&self, listing: Listing) -> Result<Projects, serde_json::Error> {
        let query = listing.build_query();
        self.get(&query)
    }
}

// https://docs.gitlab.com/ce/api/projects.html#list-projects

#[derive(Debug, Copy, Clone)]
pub enum ListingOrderBy {
    Id,
    Name,
    Path,
    CreatedAt,
    UpdatedAt,
    LastActivityAt,
}

#[derive(Default, Debug, Clone)]
pub struct Listing {
    /// Limit by archived status
    archived: Option<bool>,
    /// Limit by visibility.
    visibility: Option<::ListingVisibility>,
    /// Return requests ordered by. Default is `ListingOrderBy::CreatedAt`.
    order_by: Option<ListingOrderBy>,
    /// Return requests sorted. Default is `::ListingSort::Desc`.
    sort: Option<::ListingSort>,
    /// Return list of authorized projects matching the search criteria.
    search: String,
    /// Return only the ID, URL, name, and path of each project
    simple: Option<bool>,
}

#[allow(dead_code)]
impl Listing {
    pub fn new() -> Listing {
        Default::default()
    }
    pub fn archived(&mut self, archived: bool) -> &mut Listing {
        self.archived = Some(archived);
        self
    }
    pub fn visibility(&mut self, visibility: ::ListingVisibility) -> &mut Listing {
        self.visibility = Some(visibility);
        self
    }
    pub fn order_by(&mut self, order_by: ListingOrderBy) -> &mut Listing {
        self.order_by = Some(order_by);
        self
    }
    fn sort(&mut self, sort: ::ListingSort) -> &mut Listing {
        self.sort = Some(sort);
        self
    }
    pub fn search(&mut self, search: String) -> &mut Listing {
        self.search = search;
        self
    }
    pub fn simple(&mut self, simple: bool) -> &mut Listing {
        self.simple = Some(simple);
        self
    }
}

impl BuildQuery for Listing {
    fn build_query(&self) -> String {

        let mut query = String::from("projects");

        let amp_char = "&";
        let none_char = "";
        let mut split_char = &none_char;

        // Append a "?" only if at least one of the `Option` is `Some(_)` or if
        // strings contain something.
        query.push_str(match (&self.archived,
                              &self.visibility,
                              &self.order_by,
                              &self.sort,
                              self.search.is_empty(),
                              &self.simple) {
            (&None, &None, &None, &None, true, &None) => "",
            _ => "?",
        });

        self.archived.map(|archived| {
            query.push_str(split_char);
            split_char = &amp_char;

            if archived {
                query.push_str("archived=true")
            } else {
                query.push_str("archived=false")
            }
        });

        self.visibility.map(|visibility| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("visibility=");
            query.push_str(match visibility {
                ::ListingVisibility::Public => "public",
                ::ListingVisibility::Internal => "internal",
                ::ListingVisibility::Private => "private",
            });
        });

        self.order_by.map(|order_by| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("order_by=");
            query.push_str(match order_by {
                ListingOrderBy::Id => "id",
                ListingOrderBy::Name => "name",
                ListingOrderBy::Path => "path",
                ListingOrderBy::CreatedAt => "created_at",
                ListingOrderBy::UpdatedAt => "updated_at",
                ListingOrderBy::LastActivityAt => "last_activity_at",
            });
        });

        self.sort.map(|sort| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("sort=");
            query.push_str(match sort {
                ::ListingSort::Asc => "asc",
                ::ListingSort::Desc => "desc",
            });
        });

        if !self.search.is_empty() {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("search=");
            query.push_str(&self.search);
        }

        self.simple.map(|simple| {
            query.push_str(split_char);
            split_char = &amp_char;

            if simple {
                query.push_str("simple=true")
            } else {
                query.push_str("simple=false")
            }
        });

        query
    }
}

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

    #[test]
    fn build_query_default() {
        let expected_string = "projects";
        let listing: Listing = Default::default();
        let query = listing.build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects";
        let listing = Listing::new();
        let query = listing.build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_archived() {
        let expected_string = "projects?archived=true";
        let query = Listing::new().archived(true).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?archived=false";
        let query = Listing::new().archived(false).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_visibility() {
        let expected_string = "projects?visibility=public";
        let query = Listing::new().visibility(::ListingVisibility::Public).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?visibility=internal";
        let query = Listing::new().visibility(::ListingVisibility::Internal).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?visibility=private";
        let query = Listing::new().visibility(::ListingVisibility::Private).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_order_by() {
        let expected_string = "projects?order_by=id";
        let query = Listing::new().order_by(ListingOrderBy::Id).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=name";
        let query = Listing::new().order_by(ListingOrderBy::Name).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=path";
        let query = Listing::new().order_by(ListingOrderBy::Path).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=created_at";
        let query = Listing::new().order_by(ListingOrderBy::CreatedAt).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=updated_at";
        let query = Listing::new().order_by(ListingOrderBy::UpdatedAt).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=last_activity_at";
        let query = Listing::new().order_by(ListingOrderBy::LastActivityAt).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_sort() {
        let expected_string = "projects?sort=asc";
        let query = Listing::new().sort(::ListingSort::Asc).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?sort=desc";
        let query = Listing::new().sort(::ListingSort::Desc).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_search() {
        let expected_string = "projects?search=SearchPattern";
        let query = Listing::new().search(String::from("SearchPattern")).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_simple() {
        let expected_string = "projects?simple=true";
        let query = Listing::new().simple(true).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?simple=false";
        let query = Listing::new().simple(false).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn groups_build_query_multiple() {
        let expected_string = "projects?archived=true&simple=true";
        let query = Listing::new().archived(true).simple(true).build_query();
        assert_eq!(query, expected_string);
    }
}
<commit_msg>Rename `projects::projects()` to `projects_list()`<commit_after>//! List projects
//!
//! https://docs.gitlab.com/ce/api/projects.html
//!
//! # List projects
//!
//! Get a list of projects for which the authenticated user is a member.
//!
//! ```text
//! GET /projects
//! ```
//!
//! Parameters:
//!
//! | Attribute | Type | Required | Description |
//! | --------- | ---- | -------- | ----------- |
//! | `archived` | boolean | no | Limit by archived status |
//! | `visibility` | string | no | Limit by visibility `public`, `internal`, or `private` |
//! | `order_by` | string | no | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at` |
//! | `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
//! | `search` | string | no | Return list of authorized projects matching the search criteria |
//! | `simple` | boolean | no | Return only the ID, URL, name, and path of each project |
//!

use BuildQuery;

use serde_json;

use gitlab::GitLab;
use Projects;

pub mod all;
pub mod id_branches;
pub mod id_branch;
pub mod id_events;
pub mod id_hooks_id;
pub mod id_hooks;
pub mod id;
pub mod owned;
pub mod search;
pub mod starred;
pub mod visible;

// TODO:
//
// Creates a new project owned by the authenticated user.
// POST /projects
//
// Creates a new project owned by the specified user. Available only for admins.
// POST /projects/user/:user_id
//
// Updates an existing project
// PUT /projects/:id
//
// Forks a project into the user namespace of the authenticated user or the one provided.
// POST /projects/fork/:id
//
// Stars a given project. Returns status code `201` and the project on success and `304` if the
// project is already starred.
// POST /projects/:id/star
//
// Unstars a given project. Returns status code `200` and the project on success and `304` if the
// project is not starred.
// DELETE /projects/:id/star
//
// Archives the project if the user is either admin or the project owner of this project. This
// action is idempotent, thus archiving an already archived project will not change the project.
//
// Status code `201` with the project as body is given when successful, in case the user doesn't
// have the proper access rights, code `403` is returned. Status `404` is returned if the project
// doesn't exist, or is hidden to the user.
// POST /projects/:id/archive
//
//
// Unarchives the project if the user is either admin or the project owner of this project. This
// action is idempotent, thus unarchiving an non-archived project will not change the project.
//
// Status code `201` with the project as body is given when successful, in case the user doesn't
// have the proper access rights, code `403` is returned. Status `404` is returned if the project
// doesn't exist, or is hidden to the user.
// POST /projects/:id/unarchive
//
//
// Removes a project including all associated resources (issues, merge requests etc.)
// DELETE /projects/:id
//
//
// Uploads a file to the specified project to be used in an issue or merge request description, or
// a comment.
// POST /projects/:id/uploads
//
//
// Allow to share project with group.
// POST /projects/:id/share
//
//
// Adds a hook to a specified project.
// POST /projects/:id/hooks
//
//
// Edits a hook for a specified project.
// PUT /projects/:id/hooks/:hook_id
//
//
// Removes a hook from a project. This is an idempotent method and can be called multiple times.
// Either the hook is available or not.
// DELETE /projects/:id/hooks/:hook_id
//
//
// Protects a single branch of a project.
// PUT /projects/:id/repository/branches/:branch/protect
//
//
// Unprotects a single branch of a project.
// PUT /projects/:id/repository/branches/:branch/unprotect
//
//
// Create a forked from/to relation between existing projects.
// POST /projects/:id/fork/:forked_from_id
//
//
// Delete an existing forked from relationship
// DELETE /projects/:id/fork
//

impl GitLab {
    pub fn projects_list(&self, listing: Listing) -> Result<Projects, serde_json::Error> {
        let query = listing.build_query();
        self.get(&query)
    }
}

// https://docs.gitlab.com/ce/api/projects.html#list-projects

#[derive(Debug, Copy, Clone)]
pub enum ListingOrderBy {
    Id,
    Name,
    Path,
    CreatedAt,
    UpdatedAt,
    LastActivityAt,
}

#[derive(Default, Debug, Clone)]
pub struct Listing {
    /// Limit by archived status
    archived: Option<bool>,
    /// Limit by visibility.
    visibility: Option<::ListingVisibility>,
    /// Return requests ordered by. Default is `ListingOrderBy::CreatedAt`.
    order_by: Option<ListingOrderBy>,
    /// Return requests sorted. Default is `::ListingSort::Desc`.
    sort: Option<::ListingSort>,
    /// Return list of authorized projects matching the search criteria.
    search: String,
    /// Return only the ID, URL, name, and path of each project
    simple: Option<bool>,
}

#[allow(dead_code)]
impl Listing {
    pub fn new() -> Listing {
        Default::default()
    }
    pub fn archived(&mut self, archived: bool) -> &mut Listing {
        self.archived = Some(archived);
        self
    }
    pub fn visibility(&mut self, visibility: ::ListingVisibility) -> &mut Listing {
        self.visibility = Some(visibility);
        self
    }
    pub fn order_by(&mut self, order_by: ListingOrderBy) -> &mut Listing {
        self.order_by = Some(order_by);
        self
    }
    fn sort(&mut self, sort: ::ListingSort) -> &mut Listing {
        self.sort = Some(sort);
        self
    }
    pub fn search(&mut self, search: String) -> &mut Listing {
        self.search = search;
        self
    }
    pub fn simple(&mut self, simple: bool) -> &mut Listing {
        self.simple = Some(simple);
        self
    }
}

impl BuildQuery for Listing {
    fn build_query(&self) -> String {

        let mut query = String::from("projects");

        let amp_char = "&";
        let none_char = "";
        let mut split_char = &none_char;

        // Append a "?" only if at least one of the `Option` is `Some(_)` or if
        // strings contain something.
        query.push_str(match (&self.archived,
                              &self.visibility,
                              &self.order_by,
                              &self.sort,
                              self.search.is_empty(),
                              &self.simple) {
            (&None, &None, &None, &None, true, &None) => "",
            _ => "?",
        });

        self.archived.map(|archived| {
            query.push_str(split_char);
            split_char = &amp_char;

            if archived {
                query.push_str("archived=true")
            } else {
                query.push_str("archived=false")
            }
        });

        self.visibility.map(|visibility| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("visibility=");
            query.push_str(match visibility {
                ::ListingVisibility::Public => "public",
                ::ListingVisibility::Internal => "internal",
                ::ListingVisibility::Private => "private",
            });
        });

        self.order_by.map(|order_by| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("order_by=");
            query.push_str(match order_by {
                ListingOrderBy::Id => "id",
                ListingOrderBy::Name => "name",
                ListingOrderBy::Path => "path",
                ListingOrderBy::CreatedAt => "created_at",
                ListingOrderBy::UpdatedAt => "updated_at",
                ListingOrderBy::LastActivityAt => "last_activity_at",
            });
        });

        self.sort.map(|sort| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("sort=");
            query.push_str(match sort {
                ::ListingSort::Asc => "asc",
                ::ListingSort::Desc => "desc",
            });
        });

        if !self.search.is_empty() {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("search=");
            query.push_str(&self.search);
        }

        self.simple.map(|simple| {
            query.push_str(split_char);
            split_char = &amp_char;

            if simple {
                query.push_str("simple=true")
            } else {
                query.push_str("simple=false")
            }
        });

        query
    }
}

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

    #[test]
    fn build_query_default() {
        let expected_string = "projects";
        let listing: Listing = Default::default();
        let query = listing.build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects";
        let listing = Listing::new();
        let query = listing.build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_archived() {
        let expected_string = "projects?archived=true";
        let query = Listing::new().archived(true).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?archived=false";
        let query = Listing::new().archived(false).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_visibility() {
        let expected_string = "projects?visibility=public";
        let query = Listing::new().visibility(::ListingVisibility::Public).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?visibility=internal";
        let query = Listing::new().visibility(::ListingVisibility::Internal).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?visibility=private";
        let query = Listing::new().visibility(::ListingVisibility::Private).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_order_by() {
        let expected_string = "projects?order_by=id";
        let query = Listing::new().order_by(ListingOrderBy::Id).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=name";
        let query = Listing::new().order_by(ListingOrderBy::Name).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=path";
        let query = Listing::new().order_by(ListingOrderBy::Path).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=created_at";
        let query = Listing::new().order_by(ListingOrderBy::CreatedAt).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=updated_at";
        let query = Listing::new().order_by(ListingOrderBy::UpdatedAt).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=last_activity_at";
        let query = Listing::new().order_by(ListingOrderBy::LastActivityAt).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_sort() {
        let expected_string = "projects?sort=asc";
        let query = Listing::new().sort(::ListingSort::Asc).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?sort=desc";
        let query = Listing::new().sort(::ListingSort::Desc).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_search() {
        let expected_string = "projects?search=SearchPattern";
        let query = Listing::new().search(String::from("SearchPattern")).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_simple() {
        let expected_string = "projects?simple=true";
        let query = Listing::new().simple(true).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?simple=false";
        let query = Listing::new().simple(false).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn groups_build_query_multiple() {
        let expected_string = "projects?archived=true&simple=true";
        let query = Listing::new().archived(true).simple(true).build_query();
        assert_eq!(query, expected_string);
    }
}
<|endoftext|>


<commit_before>/// This function is where the kernel sets up IRQ handlers
/// It is increcibly unsafe, and should be minimal in nature
/// It must create the IDT with the correct entries, those entries are
/// defined in other files inside of the `arch` module

use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};

use acpi;
use allocator::{HEAP_START, HEAP_SIZE};
use externs::memset;
use gdt;
use idt;
use memory;
use paging::{self, entry, Page, VirtualAddress};

/// Test of zero values in BSS.
static BSS_TEST_ZERO: usize = 0;
/// Test of non-zero values in BSS.
static BSS_TEST_NONZERO: usize = 0xFFFFFFFFFFFFFFFF;

static BSP_READY: AtomicBool = ATOMIC_BOOL_INIT;

extern {
    /// Kernel main function
    fn kmain() -> !;
}

/// The entry to Rust, all things must be initialized
#[no_mangle]
pub unsafe extern fn kstart() -> ! {
    {
        extern {
            /// The starting byte of the _.bss_ (uninitialized data) segment.
            static mut __bss_start: u8;
            /// The ending byte of the _.bss_ (uninitialized data) segment.
            static mut __bss_end: u8;
        }

        // Zero BSS, this initializes statics that are set to 0
        {
            let start_ptr = &mut __bss_start as *mut u8;
            let end_ptr = & __bss_end as *const u8 as usize;

            if start_ptr as usize <= end_ptr {
                let size = end_ptr - start_ptr as usize;
                memset(start_ptr, 0, size);
            }

            debug_assert_eq!(BSS_TEST_ZERO, 0);
            debug_assert_eq!(BSS_TEST_NONZERO, 0xFFFFFFFFFFFFFFFF);
        }

        BSP_READY.store(false, Ordering::SeqCst);

        // Set up GDT
        gdt::init();

        // Set up IDT
        idt::init();

        // Initialize memory management
        memory::init(0, &__bss_end as *const u8 as usize);

        // TODO: allocate a stack
        let stack_start = 0x00080000;
        let stack_end = 0x0009F000;

        // Initialize paging
        let mut active_table = paging::init(stack_start, stack_end);

        // Read ACPI tables
        acpi::init(&mut active_table);

        // Map heap
        let heap_start_page = Page::containing_address(VirtualAddress::new(HEAP_START));
        let heap_end_page = Page::containing_address(VirtualAddress::new(HEAP_START + HEAP_SIZE-1));

        for page in Page::range_inclusive(heap_start_page, heap_end_page) {
            active_table.map(page, entry::WRITABLE | entry::NO_EXECUTE);
        }

        BSP_READY.store(true, Ordering::SeqCst);
    }

    for _i in 0..10 {
        print!("BSP\n");
    }

    kmain();
}

/// Entry to rust for an AP
pub unsafe extern fn kstart_ap(stack_start: usize, stack_end: usize) -> ! {
    {
        // Set up GDT for AP
        gdt::init_ap();

        // Set up IDT for aP
        idt::init_ap();

        // Initialize paging
        let mut active_table = paging::init(stack_start, stack_end);

        // Map heap
        let heap_start_page = Page::containing_address(VirtualAddress::new(HEAP_START));
        let heap_end_page = Page::containing_address(VirtualAddress::new(HEAP_START + HEAP_SIZE-1));

        for page in Page::range_inclusive(heap_start_page, heap_end_page) {
            active_table.map(page, entry::WRITABLE | entry::NO_EXECUTE);
        }
    }

    while ! BSP_READY.load(Ordering::SeqCst) {
        asm!("pause" : : : : "intel", "volatile");
    }

    for _i in 0..10 {
        print!("AP\n");
    }

    loop {
        asm!("hlt");
    }
}
<commit_msg>Remove debugging<commit_after>/// This function is where the kernel sets up IRQ handlers
/// It is increcibly unsafe, and should be minimal in nature
/// It must create the IDT with the correct entries, those entries are
/// defined in other files inside of the `arch` module

use core::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};

use acpi;
use allocator::{HEAP_START, HEAP_SIZE};
use externs::memset;
use gdt;
use idt;
use memory;
use paging::{self, entry, Page, VirtualAddress};

/// Test of zero values in BSS.
static BSS_TEST_ZERO: usize = 0;
/// Test of non-zero values in BSS.
static BSS_TEST_NONZERO: usize = 0xFFFFFFFFFFFFFFFF;

static BSP_READY: AtomicBool = ATOMIC_BOOL_INIT;

extern {
    /// Kernel main function
    fn kmain() -> !;
}

/// The entry to Rust, all things must be initialized
#[no_mangle]
pub unsafe extern fn kstart() -> ! {
    {
        extern {
            /// The starting byte of the _.bss_ (uninitialized data) segment.
            static mut __bss_start: u8;
            /// The ending byte of the _.bss_ (uninitialized data) segment.
            static mut __bss_end: u8;
        }

        // Zero BSS, this initializes statics that are set to 0
        {
            let start_ptr = &mut __bss_start as *mut u8;
            let end_ptr = & __bss_end as *const u8 as usize;

            if start_ptr as usize <= end_ptr {
                let size = end_ptr - start_ptr as usize;
                memset(start_ptr, 0, size);
            }

            debug_assert_eq!(BSS_TEST_ZERO, 0);
            debug_assert_eq!(BSS_TEST_NONZERO, 0xFFFFFFFFFFFFFFFF);
        }

        BSP_READY.store(false, Ordering::SeqCst);

        // Set up GDT
        gdt::init();

        // Set up IDT
        idt::init();

        // Initialize memory management
        memory::init(0, &__bss_end as *const u8 as usize);

        // TODO: allocate a stack
        let stack_start = 0x00080000;
        let stack_end = 0x0009F000;

        // Initialize paging
        let mut active_table = paging::init(stack_start, stack_end);

        // Read ACPI tables
        acpi::init(&mut active_table);

        // Map heap
        let heap_start_page = Page::containing_address(VirtualAddress::new(HEAP_START));
        let heap_end_page = Page::containing_address(VirtualAddress::new(HEAP_START + HEAP_SIZE-1));

        for page in Page::range_inclusive(heap_start_page, heap_end_page) {
            active_table.map(page, entry::WRITABLE | entry::NO_EXECUTE);
        }

        BSP_READY.store(true, Ordering::SeqCst);
    }

    kmain();
}

/// Entry to rust for an AP
pub unsafe extern fn kstart_ap(stack_start: usize, stack_end: usize) -> ! {
    {
        // Set up GDT for AP
        gdt::init_ap();

        // Set up IDT for aP
        idt::init_ap();

        // Initialize paging
        let mut active_table = paging::init(stack_start, stack_end);

        // Map heap
        let heap_start_page = Page::containing_address(VirtualAddress::new(HEAP_START));
        let heap_end_page = Page::containing_address(VirtualAddress::new(HEAP_START + HEAP_SIZE-1));

        for page in Page::range_inclusive(heap_start_page, heap_end_page) {
            active_table.map(page, entry::WRITABLE | entry::NO_EXECUTE);
        }
    }

    while ! BSP_READY.load(Ordering::SeqCst) {
        asm!("pause" : : : : "intel", "volatile");
    }

    loop {
        asm!("hlt");
    }
}
<|endoftext|>


<commit_before>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::utils::paths;
use crate::utils::sugg::DiagnosticBuilderExt;
use crate::utils::{get_trait_def_id, implements_trait, return_ty, same_tys, span_lint_node_and_then};
use if_chain::if_chain;
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty::{self, Ty};
use rustc::util::nodemap::NodeSet;
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;
use syntax::source_map::Span;

/// **What it does:** Checks for types with a `fn new() -> Self` method and no
/// implementation of
/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html).
///
/// It detects both the case when a manual
/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html)
/// implementation is required and also when it can be created with
/// `#[derive(Default)]
///
/// **Why is this bad?** The user might expect to be able to use
/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the
/// type can be constructed without arguments.
///
/// **Known problems:** Hopefully none.
///
/// **Example:**
///
/// ```rust
/// struct Foo(Bar);
///
/// impl Foo {
///     fn new() -> Self {
///         Foo(Bar::new())
///     }
/// }
/// ```
///
/// Instead, use:
///
/// ```rust
/// struct Foo(Bar);
///
/// impl Default for Foo {
///     fn default() -> Self {
///         Foo(Bar::new())
///     }
/// }
/// ```
///
/// Or, if
/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html)
/// can be derived by `#[derive(Default)]`:
///
/// ```rust
/// struct Foo;
///
/// impl Foo {
///     fn new() -> Self {
///         Foo
///     }
/// }
/// ```
///
/// Instead, use:
///
/// ```rust
/// #[derive(Default)]
/// struct Foo;
///
/// impl Foo {
///     fn new() -> Self {
///         Foo
///     }
/// }
/// ```
///
/// You can also have `new()` call `Default::default()`.
declare_clippy_lint! {
    pub NEW_WITHOUT_DEFAULT,
    style,
    "`fn new() -> Self` method without `Default` implementation"
}

#[derive(Clone, Default)]
pub struct NewWithoutDefault {
    impling_types: Option<NodeSet>,
}

impl LintPass for NewWithoutDefault {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEW_WITHOUT_DEFAULT)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
        if let hir::ItemKind::Impl(_, _, _, _, None, _, ref items) = item.node {
            for assoc_item in items {
                if let hir::AssociatedItemKind::Method { has_self: false } = assoc_item.kind {
                    let impl_item = cx.tcx.hir().impl_item(assoc_item.id);
                    if in_external_macro(cx.sess(), impl_item.span) {
                        return;
                    }
                    if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
                        let name = impl_item.ident.name;
                        let id = impl_item.id;
                        if sig.header.constness == hir::Constness::Const {
                            // can't be implemented by default
                            return;
                        }
                        if sig.header.unsafety == hir::Unsafety::Unsafe {
                            // can't be implemented for unsafe new
                            return;
                        }
                        if impl_item.generics.params.iter().any(|gen| match gen.kind {
                            hir::GenericParamKind::Type { .. } => true,
                            _ => false,
                        }) {
                            // when the result of `new()` depends on a type parameter we should not require
                            // an
                            // impl of `Default`
                            return;
                        }
                        if sig.decl.inputs.is_empty() && name == "new" && cx.access_levels.is_reachable(id) {
                            let self_did = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent(id));
                            let self_ty = cx.tcx.type_of(self_did);
                            if_chain! {
                                if same_tys(cx, self_ty, return_ty(cx, id));
                                if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
                                then {
                                    if self.impling_types.is_none() {
                                        let mut impls = NodeSet::default();
                                        cx.tcx.for_each_impl(default_trait_id, |d| {
                                            if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
                                                if let Some(node_id) = cx.tcx.hir().as_local_node_id(ty_def.did) {
                                                    impls.insert(node_id);
                                                }
                                            }
                                        });
                                        self.impling_types = Some(impls);
                                    }

                                    // Check if a Default implementation exists for the Self type, regardless of
                                    // generics
                                    if_chain! {
                                        if let Some(ref impling_types) = self.impling_types;
                                        if let Some(self_def) = cx.tcx.type_of(self_did).ty_adt_def();
                                        if self_def.did.is_local();
                                        then {
                                            let self_id = cx.tcx.hir().local_def_id_to_node_id(self_def.did.to_local());
                                            if impling_types.contains(&self_id) {
                                                return;
                                            }
                                        }
                                    }

                                    if let Some(sp) = can_derive_default(self_ty, cx, default_trait_id) {
                                        span_lint_node_and_then(
                                            cx,
                                            NEW_WITHOUT_DEFAULT,
                                            id,
                                            impl_item.span,
                                            &format!(
                                                "you should consider deriving a `Default` implementation for `{}`",
                                                self_ty
                                            ),
                                            |db| {
                                                db.suggest_item_with_attr(
                                                    cx,
                                                    sp,
                                                    "try this",
                                                    "#[derive(Default)]",
                                                    Applicability::MaybeIncorrect,
                                                );
                                            });
                                    } else {
                                        span_lint_node_and_then(
                                            cx,
                                            NEW_WITHOUT_DEFAULT,
                                            id,
                                            impl_item.span,
                                            &format!(
                                                "you should consider adding a `Default` implementation for `{}`",
                                                self_ty
                                            ),
                                            |db| {
                                                db.suggest_prepend_item(
                                                    cx,
                                                    item.span,
                                                    "try this",
                                                    &create_new_without_default_suggest_msg(self_ty),
                                                    Applicability::MaybeIncorrect,
                                                );
                                            },
                                        );
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

fn create_new_without_default_suggest_msg(ty: Ty<'_>) -> String {
    #[rustfmt::skip]
    format!(
"impl Default for {} {{
    fn default() -> Self {{
        Self::new()
    }}
}}", ty)
}

fn can_derive_default<'t, 'c>(ty: Ty<'t>, cx: &LateContext<'c, 't>, default_trait_id: DefId) -> Option<Span> {
    match ty.sty {
        ty::Adt(adt_def, substs) if adt_def.is_struct() => {
            for field in adt_def.all_fields() {
                let f_ty = field.ty(cx.tcx, substs);
                if !implements_trait(cx, f_ty, default_trait_id, &[]) {
                    return None;
                }
            }
            Some(cx.tcx.def_span(adt_def.did))
        },
        _ => None,
    }
}
<commit_msg>Add missing ` in default lint<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::utils::paths;
use crate::utils::sugg::DiagnosticBuilderExt;
use crate::utils::{get_trait_def_id, implements_trait, return_ty, same_tys, span_lint_node_and_then};
use if_chain::if_chain;
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty::{self, Ty};
use rustc::util::nodemap::NodeSet;
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;
use syntax::source_map::Span;

/// **What it does:** Checks for types with a `fn new() -> Self` method and no
/// implementation of
/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html).
///
/// It detects both the case when a manual
/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html)
/// implementation is required and also when it can be created with
/// `#[derive(Default)]`
///
/// **Why is this bad?** The user might expect to be able to use
/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the
/// type can be constructed without arguments.
///
/// **Known problems:** Hopefully none.
///
/// **Example:**
///
/// ```rust
/// struct Foo(Bar);
///
/// impl Foo {
///     fn new() -> Self {
///         Foo(Bar::new())
///     }
/// }
/// ```
///
/// Instead, use:
///
/// ```rust
/// struct Foo(Bar);
///
/// impl Default for Foo {
///     fn default() -> Self {
///         Foo(Bar::new())
///     }
/// }
/// ```
///
/// Or, if
/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html)
/// can be derived by `#[derive(Default)]`:
///
/// ```rust
/// struct Foo;
///
/// impl Foo {
///     fn new() -> Self {
///         Foo
///     }
/// }
/// ```
///
/// Instead, use:
///
/// ```rust
/// #[derive(Default)]
/// struct Foo;
///
/// impl Foo {
///     fn new() -> Self {
///         Foo
///     }
/// }
/// ```
///
/// You can also have `new()` call `Default::default()`.
declare_clippy_lint! {
    pub NEW_WITHOUT_DEFAULT,
    style,
    "`fn new() -> Self` method without `Default` implementation"
}

#[derive(Clone, Default)]
pub struct NewWithoutDefault {
    impling_types: Option<NodeSet>,
}

impl LintPass for NewWithoutDefault {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEW_WITHOUT_DEFAULT)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
        if let hir::ItemKind::Impl(_, _, _, _, None, _, ref items) = item.node {
            for assoc_item in items {
                if let hir::AssociatedItemKind::Method { has_self: false } = assoc_item.kind {
                    let impl_item = cx.tcx.hir().impl_item(assoc_item.id);
                    if in_external_macro(cx.sess(), impl_item.span) {
                        return;
                    }
                    if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
                        let name = impl_item.ident.name;
                        let id = impl_item.id;
                        if sig.header.constness == hir::Constness::Const {
                            // can't be implemented by default
                            return;
                        }
                        if sig.header.unsafety == hir::Unsafety::Unsafe {
                            // can't be implemented for unsafe new
                            return;
                        }
                        if impl_item.generics.params.iter().any(|gen| match gen.kind {
                            hir::GenericParamKind::Type { .. } => true,
                            _ => false,
                        }) {
                            // when the result of `new()` depends on a type parameter we should not require
                            // an
                            // impl of `Default`
                            return;
                        }
                        if sig.decl.inputs.is_empty() && name == "new" && cx.access_levels.is_reachable(id) {
                            let self_did = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent(id));
                            let self_ty = cx.tcx.type_of(self_did);
                            if_chain! {
                                if same_tys(cx, self_ty, return_ty(cx, id));
                                if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
                                then {
                                    if self.impling_types.is_none() {
                                        let mut impls = NodeSet::default();
                                        cx.tcx.for_each_impl(default_trait_id, |d| {
                                            if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
                                                if let Some(node_id) = cx.tcx.hir().as_local_node_id(ty_def.did) {
                                                    impls.insert(node_id);
                                                }
                                            }
                                        });
                                        self.impling_types = Some(impls);
                                    }

                                    // Check if a Default implementation exists for the Self type, regardless of
                                    // generics
                                    if_chain! {
                                        if let Some(ref impling_types) = self.impling_types;
                                        if let Some(self_def) = cx.tcx.type_of(self_did).ty_adt_def();
                                        if self_def.did.is_local();
                                        then {
                                            let self_id = cx.tcx.hir().local_def_id_to_node_id(self_def.did.to_local());
                                            if impling_types.contains(&self_id) {
                                                return;
                                            }
                                        }
                                    }

                                    if let Some(sp) = can_derive_default(self_ty, cx, default_trait_id) {
                                        span_lint_node_and_then(
                                            cx,
                                            NEW_WITHOUT_DEFAULT,
                                            id,
                                            impl_item.span,
                                            &format!(
                                                "you should consider deriving a `Default` implementation for `{}`",
                                                self_ty
                                            ),
                                            |db| {
                                                db.suggest_item_with_attr(
                                                    cx,
                                                    sp,
                                                    "try this",
                                                    "#[derive(Default)]",
                                                    Applicability::MaybeIncorrect,
                                                );
                                            });
                                    } else {
                                        span_lint_node_and_then(
                                            cx,
                                            NEW_WITHOUT_DEFAULT,
                                            id,
                                            impl_item.span,
                                            &format!(
                                                "you should consider adding a `Default` implementation for `{}`",
                                                self_ty
                                            ),
                                            |db| {
                                                db.suggest_prepend_item(
                                                    cx,
                                                    item.span,
                                                    "try this",
                                                    &create_new_without_default_suggest_msg(self_ty),
                                                    Applicability::MaybeIncorrect,
                                                );
                                            },
                                        );
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

fn create_new_without_default_suggest_msg(ty: Ty<'_>) -> String {
    #[rustfmt::skip]
    format!(
"impl Default for {} {{
    fn default() -> Self {{
        Self::new()
    }}
}}", ty)
}

fn can_derive_default<'t, 'c>(ty: Ty<'t>, cx: &LateContext<'c, 't>, default_trait_id: DefId) -> Option<Span> {
    match ty.sty {
        ty::Adt(adt_def, substs) if adt_def.is_struct() => {
            for field in adt_def.all_fields() {
                let f_ty = field.ty(cx.tcx, substs);
                if !implements_trait(cx, f_ty, default_trait_id, &[]) {
                    return None;
                }
            }
            Some(cx.tcx.def_span(adt_def.did))
        },
        _ => None,
    }
}
<|endoftext|>


<commit_before>//! The CXX code generator for constructing and compiling C++ code.
//!
//! This is intended to be used from Cargo build scripts to execute CXX's
//! C++ code generator, set up any additional compiler flags depending on
//! the use case, and make the C++ compiler invocation.
//!
//!

//!
//! # Example
//!
//! Example of a canonical Cargo build script that builds a CXX bridge:
//!
//! ```no_run
//! // build.rs
//!
//! fn main() {
//!     cxx_build::bridge("src/main.rs")
//!         .file("src/demo.cc")
//!         .flag_if_supported("-std=c++11")
//!         .compile("cxxbridge-demo");
//!
//!     println!("cargo:rerun-if-changed=src/main.rs");
//!     println!("cargo:rerun-if-changed=src/demo.cc");
//!     println!("cargo:rerun-if-changed=include/demo.h");
//! }
//! ```
//!
//! A runnable working setup with this build script is shown in the *demo*
//! directory of [https://github.com/dtolnay/cxx].
//!
//! [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
//!
//!

//!
//! # Alternatives
//!
//! For use in non-Cargo builds like Bazel or Buck, CXX provides an
//! alternate way of invoking the C++ code generator as a standalone command
//! line tool. The tool is packaged as the `cxxbridge-cmd` crate.
//!
//! ```bash
//! $ cargo install cxxbridge-cmd  # or build it from the repo
//!
//! $ cxxbridge src/main.rs --header > path/to/mybridge.h
//! $ cxxbridge src/main.rs > path/to/mybridge.cc
//! ```

#![allow(
    clippy::drop_copy,
    clippy::inherent_to_string,
    clippy::needless_doctest_main,
    clippy::new_without_default,
    clippy::or_fun_call,
    clippy::toplevel_ref_arg
)]

mod cfg;
mod deps;
mod error;
mod gen;
mod intern;
mod out;
mod paths;
mod syntax;
mod target;
mod vec;

use crate::deps::{Crate, HeaderDir};
use crate::error::{Error, Result};
use crate::gen::error::report;
use crate::gen::Opt;
use crate::paths::PathExt;
use crate::target::TargetDir;
use cc::Build;
use std::env;
use std::ffi::{OsStr, OsString};
use std::io::{self, Write};
use std::iter;
use std::path::{Path, PathBuf};
use std::process;

pub use crate::cfg::{Cfg, CFG};

/// This returns a [`cc::Build`] on which you should continue to set up any
/// additional source files or compiler flags, and lastly call its [`compile`]
/// method to execute the C++ build.
///
/// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
#[must_use]
pub fn bridge(rust_source_file: impl AsRef<Path>) -> Build {
    bridges(iter::once(rust_source_file))
}

/// `cxx_build::bridge` but for when more than one file contains a
/// #\[cxx::bridge\] module.
///
/// ```no_run
/// let source_files = vec!["src/main.rs", "src/path/to/other.rs"];
/// cxx_build::bridges(source_files)
///     .file("src/demo.cc")
///     .flag_if_supported("-std=c++11")
///     .compile("cxxbridge-demo");
/// ```
#[must_use]
pub fn bridges(rust_source_files: impl IntoIterator<Item = impl AsRef<Path>>) -> Build {
    let ref mut rust_source_files = rust_source_files.into_iter();
    build(rust_source_files).unwrap_or_else(|err| {
        let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {}\n\n", report(err));
        process::exit(1);
    })
}

struct Project {
    include_prefix: PathBuf,
    manifest_dir: PathBuf,
    // Output directory as received from Cargo.
    out_dir: PathBuf,
    // Directory into which to symlink all generated code.
    //
    // This is *not* used for an #include path, only as a debugging convenience.
    // Normally available at target/cxxbridge/ if we are able to know where the
    // target dir is, otherwise under a common scratch dir.
    //
    // The reason this isn't the #include dir is that we do not want builds to
    // have access to headers from arbitrary other parts of the dependency
    // graph. Using a global directory for all builds would be both a race
    // condition depending on what order Cargo randomly executes the build
    // scripts, as well as semantically undesirable for builds not to have to
    // declare their real dependencies.
    shared_dir: PathBuf,
}

impl Project {
    fn init() -> Result<Self> {
        let include_prefix = Path::new(CFG.include_prefix);
        assert!(include_prefix.is_relative());
        let include_prefix = include_prefix.components().collect();

        let manifest_dir = paths::manifest_dir()?;
        let out_dir = paths::out_dir()?;

        let shared_dir = match target::find_target_dir(&out_dir) {
            TargetDir::Path(target_dir) => target_dir.join("cxxbridge"),
            TargetDir::Unknown => scratch::path("cxxbridge"),
        };

        Ok(Project {
            include_prefix,
            manifest_dir,
            out_dir,
            shared_dir,
        })
    }
}

// We lay out the OUT_DIR as follows. Everything is namespaced under a cxxbridge
// subdirectory to avoid stomping on other things that the caller's build script
// might be doing inside OUT_DIR.
//
//     $OUT_DIR/
//        cxxbridge/
//           crate/
//              $CARGO_PKG_NAME -> $CARGO_MANIFEST_DIR
//           include/
//              rust/
//                 cxx.h
//              $CARGO_PKG_NAME/
//                 .../
//                    lib.rs.h
//           sources/
//              $CARGO_PKG_NAME/
//                 .../
//                    lib.rs.cc
//
// The crate/ and include/ directories are placed on the #include path for the
// current build as well as for downstream builds that have a direct dependency
// on the current crate.
fn build(rust_source_files: &mut dyn Iterator<Item = impl AsRef<Path>>) -> Result<Build> {
    let ref prj = Project::init()?;
    let this_crate = make_this_crate(prj)?;
    this_crate.print_to_cargo();

    let mut build = Build::new();
    build.cpp(true);
    build.cpp_link_stdlib(None); // linked via link-cplusplus crate

    for path in rust_source_files {
        generate_bridge(prj, &mut build, path.as_ref())?;
    }

    let mut crates = deps::direct_dependencies();
    crates.insert(0, this_crate);

    eprintln!("\nCXX include path:");
    for krate in crates {
        for header_dir in &krate.header_dirs {
            build.include(&header_dir.path);
            if header_dir.exported {
                eprintln!("  {}", header_dir.path.display());
            } else {
                eprintln!("  {} (private)", header_dir.path.display());
            }
        }
    }

    Ok(build)
}

fn make_this_crate(prj: &Project) -> Result<Crate> {
    let crate_dir = make_crate_dir(prj);
    let include_dir = make_include_dir(prj)?;

    let mut this_crate = Crate {
        include_prefix: Some(prj.include_prefix.clone()),
        links: env::var_os("CARGO_MANIFEST_LINKS"),
        header_dirs: Vec::new(),
    };

    // The generated code directory (include_dir) is placed in front of
    // crate_dir on the include line so that `#include "path/to/file.rs"` from
    // C++ "magically" works and refers to the API generated from that Rust
    // source file.
    this_crate.header_dirs.push(HeaderDir {
        exported: true,
        path: include_dir,
    });

    if let Some(crate_dir) = crate_dir {
        this_crate.header_dirs.push(HeaderDir {
            exported: true,
            path: crate_dir,
        });
    }

    for exported_dir in &CFG.exported_header_dirs {
        if !exported_dir.is_absolute() {
            return Err(Error::ExportedDirNotAbsolute(exported_dir));
        }
        this_crate.header_dirs.push(HeaderDir {
            exported: true,
            path: PathBuf::from(exported_dir),
        });
    }

    Ok(this_crate)
}

fn make_crate_dir(prj: &Project) -> Option<PathBuf> {
    if prj.include_prefix.as_os_str().is_empty() {
        return Some(prj.manifest_dir.clone());
    }
    let crate_dir = prj.out_dir.join("cxxbridge").join("crate");
    let link = crate_dir.join(&prj.include_prefix);
    if out::symlink_dir(&prj.manifest_dir, link).is_ok() {
        Some(crate_dir)
    } else {
        None
    }
}

fn make_include_dir(prj: &Project) -> Result<PathBuf> {
    let include_dir = prj.out_dir.join("cxxbridge").join("include");
    let cxx_h = include_dir.join("rust").join("cxx.h");
    let ref shared_cxx_h = prj.shared_dir.join("rust").join("cxx.h");
    if let Some(ref original) = env::var_os("DEP_CXXBRIDGE05_HEADER") {
        out::symlink_file(original, cxx_h)?;
        out::symlink_file(original, shared_cxx_h)?;
    } else {
        out::write(shared_cxx_h, gen::include::HEADER.as_bytes())?;
        out::symlink_file(shared_cxx_h, cxx_h)?;
    }
    Ok(include_dir)
}

fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) -> Result<()> {
    let opt = Opt {
        allow_dot_includes: false,
        ..Opt::default()
    };
    let generated = gen::generate_from_path(rust_source_file, &opt);
    let ref rel_path = paths::local_relative_path(rust_source_file);

    let cxxbridge = prj.out_dir.join("cxxbridge");
    let include_dir = cxxbridge.join("include").join(&prj.include_prefix);
    let sources_dir = cxxbridge.join("sources").join(&prj.include_prefix);

    let ref rel_path_h = rel_path.with_appended_extension(".h");
    let ref header_path = include_dir.join(rel_path_h);
    out::write(header_path, &generated.header)?;

    let ref link_path = include_dir.join(rel_path);
    let _ = out::symlink_file(header_path, link_path);

    let ref rel_path_cc = rel_path.with_appended_extension(".cc");
    let ref implementation_path = sources_dir.join(rel_path_cc);
    out::write(implementation_path, &generated.implementation)?;
    build.file(implementation_path);

    let shared_h = prj.shared_dir.join(&prj.include_prefix).join(rel_path_h);
    let shared_cc = prj.shared_dir.join(&prj.include_prefix).join(rel_path_cc);
    let _ = out::symlink_file(header_path, shared_h);
    let _ = out::symlink_file(implementation_path, shared_cc);
    Ok(())
}

fn env_os(key: impl AsRef<OsStr>) -> Result<OsString> {
    let key = key.as_ref();
    env::var_os(key).ok_or_else(|| Error::NoEnv(key.to_owned()))
}
<commit_msg>Implement CFG.exported_header_links<commit_after>//! The CXX code generator for constructing and compiling C++ code.
//!
//! This is intended to be used from Cargo build scripts to execute CXX's
//! C++ code generator, set up any additional compiler flags depending on
//! the use case, and make the C++ compiler invocation.
//!
//!

//!
//! # Example
//!
//! Example of a canonical Cargo build script that builds a CXX bridge:
//!
//! ```no_run
//! // build.rs
//!
//! fn main() {
//!     cxx_build::bridge("src/main.rs")
//!         .file("src/demo.cc")
//!         .flag_if_supported("-std=c++11")
//!         .compile("cxxbridge-demo");
//!
//!     println!("cargo:rerun-if-changed=src/main.rs");
//!     println!("cargo:rerun-if-changed=src/demo.cc");
//!     println!("cargo:rerun-if-changed=include/demo.h");
//! }
//! ```
//!
//! A runnable working setup with this build script is shown in the *demo*
//! directory of [https://github.com/dtolnay/cxx].
//!
//! [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
//!
//!

//!
//! # Alternatives
//!
//! For use in non-Cargo builds like Bazel or Buck, CXX provides an
//! alternate way of invoking the C++ code generator as a standalone command
//! line tool. The tool is packaged as the `cxxbridge-cmd` crate.
//!
//! ```bash
//! $ cargo install cxxbridge-cmd  # or build it from the repo
//!
//! $ cxxbridge src/main.rs --header > path/to/mybridge.h
//! $ cxxbridge src/main.rs > path/to/mybridge.cc
//! ```

#![allow(
    clippy::drop_copy,
    clippy::inherent_to_string,
    clippy::needless_doctest_main,
    clippy::new_without_default,
    clippy::or_fun_call,
    clippy::toplevel_ref_arg
)]

mod cfg;
mod deps;
mod error;
mod gen;
mod intern;
mod out;
mod paths;
mod syntax;
mod target;
mod vec;

use crate::deps::{Crate, HeaderDir};
use crate::error::{Error, Result};
use crate::gen::error::report;
use crate::gen::Opt;
use crate::paths::PathExt;
use crate::target::TargetDir;
use cc::Build;
use std::env;
use std::ffi::{OsStr, OsString};
use std::io::{self, Write};
use std::iter;
use std::path::{Path, PathBuf};
use std::process;

pub use crate::cfg::{Cfg, CFG};

/// This returns a [`cc::Build`] on which you should continue to set up any
/// additional source files or compiler flags, and lastly call its [`compile`]
/// method to execute the C++ build.
///
/// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
#[must_use]
pub fn bridge(rust_source_file: impl AsRef<Path>) -> Build {
    bridges(iter::once(rust_source_file))
}

/// `cxx_build::bridge` but for when more than one file contains a
/// #\[cxx::bridge\] module.
///
/// ```no_run
/// let source_files = vec!["src/main.rs", "src/path/to/other.rs"];
/// cxx_build::bridges(source_files)
///     .file("src/demo.cc")
///     .flag_if_supported("-std=c++11")
///     .compile("cxxbridge-demo");
/// ```
#[must_use]
pub fn bridges(rust_source_files: impl IntoIterator<Item = impl AsRef<Path>>) -> Build {
    let ref mut rust_source_files = rust_source_files.into_iter();
    build(rust_source_files).unwrap_or_else(|err| {
        let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {}\n\n", report(err));
        process::exit(1);
    })
}

struct Project {
    include_prefix: PathBuf,
    manifest_dir: PathBuf,
    // Output directory as received from Cargo.
    out_dir: PathBuf,
    // Directory into which to symlink all generated code.
    //
    // This is *not* used for an #include path, only as a debugging convenience.
    // Normally available at target/cxxbridge/ if we are able to know where the
    // target dir is, otherwise under a common scratch dir.
    //
    // The reason this isn't the #include dir is that we do not want builds to
    // have access to headers from arbitrary other parts of the dependency
    // graph. Using a global directory for all builds would be both a race
    // condition depending on what order Cargo randomly executes the build
    // scripts, as well as semantically undesirable for builds not to have to
    // declare their real dependencies.
    shared_dir: PathBuf,
}

impl Project {
    fn init() -> Result<Self> {
        let include_prefix = Path::new(CFG.include_prefix);
        assert!(include_prefix.is_relative());
        let include_prefix = include_prefix.components().collect();

        let manifest_dir = paths::manifest_dir()?;
        let out_dir = paths::out_dir()?;

        let shared_dir = match target::find_target_dir(&out_dir) {
            TargetDir::Path(target_dir) => target_dir.join("cxxbridge"),
            TargetDir::Unknown => scratch::path("cxxbridge"),
        };

        Ok(Project {
            include_prefix,
            manifest_dir,
            out_dir,
            shared_dir,
        })
    }
}

// We lay out the OUT_DIR as follows. Everything is namespaced under a cxxbridge
// subdirectory to avoid stomping on other things that the caller's build script
// might be doing inside OUT_DIR.
//
//     $OUT_DIR/
//        cxxbridge/
//           crate/
//              $CARGO_PKG_NAME -> $CARGO_MANIFEST_DIR
//           include/
//              rust/
//                 cxx.h
//              $CARGO_PKG_NAME/
//                 .../
//                    lib.rs.h
//           sources/
//              $CARGO_PKG_NAME/
//                 .../
//                    lib.rs.cc
//
// The crate/ and include/ directories are placed on the #include path for the
// current build as well as for downstream builds that have a direct dependency
// on the current crate.
fn build(rust_source_files: &mut dyn Iterator<Item = impl AsRef<Path>>) -> Result<Build> {
    let ref prj = Project::init()?;
    let this_crate = make_this_crate(prj)?;
    this_crate.print_to_cargo();

    let mut build = Build::new();
    build.cpp(true);
    build.cpp_link_stdlib(None); // linked via link-cplusplus crate

    for path in rust_source_files {
        generate_bridge(prj, &mut build, path.as_ref())?;
    }

    eprintln!("\nCXX include path:");
    for header_dir in this_crate.header_dirs {
        build.include(&header_dir.path);
        if header_dir.exported {
            eprintln!("  {}", header_dir.path.display());
        } else {
            eprintln!("  {} (private)", header_dir.path.display());
        }
    }

    Ok(build)
}

fn make_this_crate(prj: &Project) -> Result<Crate> {
    let crate_dir = make_crate_dir(prj);
    let include_dir = make_include_dir(prj)?;

    let mut this_crate = Crate {
        include_prefix: Some(prj.include_prefix.clone()),
        links: env::var_os("CARGO_MANIFEST_LINKS"),
        header_dirs: Vec::new(),
    };

    // The generated code directory (include_dir) is placed in front of
    // crate_dir on the include line so that `#include "path/to/file.rs"` from
    // C++ "magically" works and refers to the API generated from that Rust
    // source file.
    this_crate.header_dirs.push(HeaderDir {
        exported: true,
        path: include_dir,
    });

    if let Some(crate_dir) = crate_dir {
        this_crate.header_dirs.push(HeaderDir {
            exported: true,
            path: crate_dir,
        });
    }

    for exported_dir in &CFG.exported_header_dirs {
        if !exported_dir.is_absolute() {
            return Err(Error::ExportedDirNotAbsolute(exported_dir));
        }
        this_crate.header_dirs.push(HeaderDir {
            exported: true,
            path: PathBuf::from(exported_dir),
        });
    }

    for krate in deps::direct_dependencies() {
        let links_attribute = match krate.links {
            Some(links) => links,
            None => continue,
        };

        let exported = CFG
            .exported_header_links
            .iter()
            .any(|exported| links_attribute == *exported);

        this_crate
            .header_dirs
            .extend(krate.header_dirs.into_iter().map(|dir| HeaderDir {
                exported,
                path: dir.path,
            }));
    }

    Ok(this_crate)
}

fn make_crate_dir(prj: &Project) -> Option<PathBuf> {
    if prj.include_prefix.as_os_str().is_empty() {
        return Some(prj.manifest_dir.clone());
    }
    let crate_dir = prj.out_dir.join("cxxbridge").join("crate");
    let link = crate_dir.join(&prj.include_prefix);
    if out::symlink_dir(&prj.manifest_dir, link).is_ok() {
        Some(crate_dir)
    } else {
        None
    }
}

fn make_include_dir(prj: &Project) -> Result<PathBuf> {
    let include_dir = prj.out_dir.join("cxxbridge").join("include");
    let cxx_h = include_dir.join("rust").join("cxx.h");
    let ref shared_cxx_h = prj.shared_dir.join("rust").join("cxx.h");
    if let Some(ref original) = env::var_os("DEP_CXXBRIDGE05_HEADER") {
        out::symlink_file(original, cxx_h)?;
        out::symlink_file(original, shared_cxx_h)?;
    } else {
        out::write(shared_cxx_h, gen::include::HEADER.as_bytes())?;
        out::symlink_file(shared_cxx_h, cxx_h)?;
    }
    Ok(include_dir)
}

fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) -> Result<()> {
    let opt = Opt {
        allow_dot_includes: false,
        ..Opt::default()
    };
    let generated = gen::generate_from_path(rust_source_file, &opt);
    let ref rel_path = paths::local_relative_path(rust_source_file);

    let cxxbridge = prj.out_dir.join("cxxbridge");
    let include_dir = cxxbridge.join("include").join(&prj.include_prefix);
    let sources_dir = cxxbridge.join("sources").join(&prj.include_prefix);

    let ref rel_path_h = rel_path.with_appended_extension(".h");
    let ref header_path = include_dir.join(rel_path_h);
    out::write(header_path, &generated.header)?;

    let ref link_path = include_dir.join(rel_path);
    let _ = out::symlink_file(header_path, link_path);

    let ref rel_path_cc = rel_path.with_appended_extension(".cc");
    let ref implementation_path = sources_dir.join(rel_path_cc);
    out::write(implementation_path, &generated.implementation)?;
    build.file(implementation_path);

    let shared_h = prj.shared_dir.join(&prj.include_prefix).join(rel_path_h);
    let shared_cc = prj.shared_dir.join(&prj.include_prefix).join(rel_path_cc);
    let _ = out::symlink_file(header_path, shared_h);
    let _ = out::symlink_file(implementation_path, shared_cc);
    Ok(())
}

fn env_os(key: impl AsRef<OsStr>) -> Result<OsString> {
    let key = key.as_ref();
    env::var_os(key).ok_or_else(|| Error::NoEnv(key.to_owned()))
}
<|endoftext|>