<commit_before>//! Reminisce is a lightweight library intended to be used for detecting and
//! reading from joysticks.
#![allow(unused_features)]
#![feature(alloc, core, std_misc, libc, fs, fs_walk, os, rustc_private, path)]
extern crate libc;
#[cfg(target_os = "windows")]
#[macro_use] extern crate rustc_bitflags;

#[cfg(feature = "sdl")]
extern crate sdl2;

/// Someday, somehow
#[cfg(all(feature = "emscripten", not(feature = "sdl")))]
mod emscripten;

#[cfg(all(feature = "emscripten", not(feature = "sdl")))]
pub use emscripten as native;

#[cfg(all(target_os = "linux", not(feature = "sdl")))]
mod linux;

#[cfg(all(target_os = "linux", not(feature = "sdl")))]
pub use linux as native;

#[cfg(all(target_os = "windows", not(feature = "sdl")))]
mod windows;

#[cfg(all(target_os = "windows", not(feature = "sdl")))]
pub use windows as native;

#[cfg(feature = "sdl")]
mod sdl;

#[cfg(feature = "sdl")]
pub use sdl as native;

mod mapper;

pub use mapper::JoystickMapper;
pub use native::{NativeJoystick, scan};

/// The maximum axis value
pub static MAX_AXIS_VALUE:i16 = 32767;
/// The minimum axis value
pub static MIN_AXIS_VALUE:i16 = -32767;

use std::borrow::Cow;
use std::mem::transmute as cast;

#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
/// A direction on a joystick
///
/// This uses the order that Linux drivers and the HTML5 Gamepad API uses so it should ring a bell
pub enum Axis {
	/// The x direction of the left stick
    ///
    /// This is usually used for horizontal movement in a game
    LeftX,
	/// The y direction of the left stick
    ///
    /// This is usually used for vertical movement in a game
    LeftY,
	/// The x direction of the right stick
    //
    /// This is usually used for looking around in a game
    RightX,
	/// The y direction of the right stick
    //
    /// This is usually used for looking around in a game
    RightY,
	/// How far down the left trigger is pressed
    ///
    /// This is only used as a button on some platforms so don't rely on just this
    TriggerLeft,
	/// How far down the right trigger is pressed
    ///
    /// This is only used as a button on some platforms so don't rely on just this
    TriggerRight
}

#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
/// A button on a joystick
///
/// This uses the order that Linux drivers and the HTML5 Gamepad API uses so it should be familiar
pub enum Button {
	/// The A button
    ///
    /// This is typically used for jumping
	A,
	/// The B button
    ///
    /// This is typically used for hitting
	B,
	/// The X button
	X,
	/// The Y button
	Y,
	/// The left top shoulder button
    ///
    /// This is usually used in FPS games for throwing a certain kind of grenade
	LeftShoulder,
	/// The right top shoulder button
	RightShoulder,
	/// The left bottom shoulder / trigger button
    ///
    /// This is typically used in FPS games for aiming down the sights in a weapon
	LeftTrigger,
	/// The right bottom shoulder / trigger button
    ///
    /// This is typically used in FPS games for shooting with a weapon
	RightTrigger,
	/// The back / select button
    ///
    /// This is usually used as an alternate pause menu or to open a menu in-game.
	Select,
	/// The start / forward button
    ///
    /// This is usually used to start and pause a game
	Start,
	/// The left stick button
	LeftStick,
	/// The right stick button
	RightStick,
	/// The up button on the directional pad
	DPadUp,
	/// The down button on the directional pad
	DPadDown,
	/// The left button on the directional pad
	DPadLeft,
	/// The right button on the directional pad
	DPadRight
}

#[derive(Copy, Debug, Eq, PartialEq)]
/// An event from a joystick
pub enum Event {
	/// Fired when a button is pressed with the button's index
	ButtonPressed(Button),
	/// Fired when a button is released with the button's index
	ButtonReleased(Button),
	/// Fired when a axis is moved with the axis index and its value,
	/// which is between `MIN_JOYSTICK_VALUE` and `MAX_JOYSTICK_VALUE`
	AxisMoved(Axis, i16)
}
/// Convert a raw event into a Reminisce event
pub trait IntoEvent {
	/// Convert this into a Reminisce event
	fn into_event(self) -> Event;
}

impl IntoEvent for Event {
    /// Convert the event into itself
    ///
    /// The only reason this exists is because windows doesn't have events so the backend has to
    /// make reminisce events directly and pretend that they are the native events.
    fn into_event(self) -> Event {
        self
    }
}

/// A joystick or gamepad
///
/// Each `Joystick` has its own event queue that can be polled repeatedly
/// using the `iter()` method or by calling the `poll()` method repeatedly.
///
/// ``` rust
/// use reminisce::{scan, Axis, Event, Joystick};
/// let mut joysticks = scan();
/// let (mut x, mut y) = (0, 0);
/// for joystick in &mut joysticks {
///     for event in joystick.iter() {
///         match event {
///             Event::AxisMoved(Axis::LeftX, nx) =>
///                 x += nx,
///             Event::AxisMoved(Axis::LeftY, ny) =>
///                 y += ny,
///             _ => ()
///         }
///     }
/// }
/// println!("{}, {}", x, y);
/// ```
pub trait Joystick : Sized {
	/// The version of this joystick that includes the state
    ///
    /// On Linux, this is a wrapper around the joystick, but on Windows,
    /// this is the same stucture because the joystick always includes
    /// state on it.
	type WithState : StatefulJoystick;

    /// The event that this joystick processes
    type NativeEvent: IntoEvent;

	/// Create a new joystick from its index
    ///
    /// If an error occurs, this will return the textual representation of that error.
    ///
    /// ``` rust
    /// use reminisce::{NativeJoystick, Joystick};
    /// let joystick:Result<NativeJoystick, &str> = Joystick::new(0);
    /// if let Ok(joystick) = joystick {
    ///     println!("{}", joystick.get_id())
    /// } else {
    ///     println!("No joystick plugged in")
    /// }
    /// ```
	fn new(index: u8) -> Result<Self, &'static str>;

	/// Check if the joystick is still connected
	fn is_connected(&self) -> bool;

	/// Get the identifier of this joystick
    ///
    /// This is a cow because it can be a static or owned String depending on the
    /// implementation.
	fn get_id(&self) -> Cow<str>;

	/// Get the index of this joystick
	fn get_index(&self) -> u8;

	/// Get the number of axes this joystick has
    ///
    /// This is capped at 6 axes for now.
	fn get_num_axes(&self) -> u8;

	/// Get the number of buttons this joystick has
    ///
    /// This is capped at 16 buttons currently.
	fn get_num_buttons(&self) -> u8;

    /// Get the battery level of this joystick
    ///
    /// Returns none if the joystick is wired or this operation is not supported
    /// by the backend
    fn get_battery(&self) -> Option<f32>;

    /// Poll the joystick for events in non-blocking mode and return the native event
    /// as returned from the backend
	fn poll_native(&mut self) -> Option<Self::NativeEvent>;

    /// Poll the joystick for events in non-blocking mode
    ///
    /// This runs `self.poll_native()` then converts it into an event using
    /// the `into_event` method.
    fn poll(&mut self) -> Option<Event> {
        self.poll_native().map(|e| e.into_event())
    }

    /// Map the axes and buttons of this joystick by wrapping it in a `JoystickMapper`
    fn into_mapper(self) -> JoystickMapper<Self> {
        JoystickMapper::new(self)
    }

    /// Iterate through the events that haven't been processed yet
    fn iter(&mut self) -> Poller<Self> {
        Poller {
            joystick: self
        }
    }

	/// Get the version of this joystick which includes state
    ///
    /// On the Linux backend, a wrapper is made, but on the Windows
    /// backend no wrapper is needed so this just returns the
    ///n `NativeJoystick` structure
	fn with_state(self) -> Self::WithState;
}

/// A joystick that keeps a record of its state
/// This makes it really easy to write the input for games, etc because its just a matter
/// of calling a single method to query where the axes are
///
/// ``` rust
/// use reminisce::{scan, Axis, Joystick, StatefulJoystick};
/// let mut joysticks = scan().into_iter().filter_map(|js| js.map(|js| with_state())).collect::<Vec<_>>();
/// for joystick in &joysticks {
///     let x = joystick.get_axis(Axis::LeftX).unwrap_or(0);
///     let y = joystick.get_axis(Axis::LeftY).unwrap_or(0);
///     println!("{}, {}", x, y)
/// }
/// ```
pub trait StatefulJoystick : Joystick + Sized {
	/// Get the value of a specific axis as an integer between `MIN_AXIS_VALUE` and `MAX_AXIS_VALUE`
	fn get_axis(&self, index: Axis) -> Option<i16>;

	/// Get the value of a specific axis normalised to between -1.0 and 1.0
	fn get_normalised_axis(&self, index: Axis) -> Option<f32> {
		self.get_axis(index).map(|v| v as f32 / MAX_AXIS_VALUE as f32)
	}

	/// Iterate over the axes in this joystick
	fn axes(&self) -> Axes<Self> {
		use std::mem;
		Axes {
			joystick: self,
			axis: unsafe { mem::zeroed() }
		}
	}

	/// Iterate over the buttons in this joystick
	fn buttons(&self) -> Buttons<Self> {
		use std::mem;
		Buttons {
			joystick: self,
			button: unsafe { mem::zeroed() }
		}
	}

	/// Get the value (if it is pressed or not) of a specific button
	///
	/// The first two buttons are usually the accept and back buttons
	fn get_button(&self, index: Button) -> Option<bool>;

	/// Update the state of this joystick by polling the native backend
	fn update(&mut self);
}

/// An iterator over a joystick's axes
pub struct Axes<'a, J> where J:StatefulJoystick+'a {
	joystick: &'a J,
	axis: u8
}
impl<'a, J> Iterator for Axes<'a, J> where J:StatefulJoystick {
	type Item = (Axis, i16);
	fn next(&mut self) -> Option<(Axis, i16)> {
		self.axis += 1;
		let axis = unsafe { cast(self.axis - 1) };
		self.joystick.get_axis(axis).map(|v| (axis, v))
	}
}

/// An iterator over a joystick's buttons
pub struct Buttons<'a, J> where J:StatefulJoystick+'a {
	joystick: &'a J,
	button: u8
}
impl<'a, J> Iterator for Buttons<'a, J> where J:StatefulJoystick {
	type Item = (Button, bool);
	fn next(&mut self) -> Option<(Button, bool)> {
		self.button += 1;
		let button = unsafe { cast(self.button - 1) };
		self.joystick.get_button(button).map(|v| (button, v))
	}
}

/// An iterator over a joystick's event queue
pub struct Poller<'a, J> where J:Joystick+'a {
    joystick: &'a mut J
}

impl<'a, J> Iterator for Poller<'a, J> where J:Joystick {
	type Item = Event;
    /// This calls the `joystick.poll()` method to poll for the next event
	fn next(&mut self) -> Option<Event> {
		self.joystick.poll()
	}
}
<commit_msg>Implement `String` for `Button` and `Axis`<commit_after>//! Reminisce is a lightweight library intended to be used for detecting and
//! reading from joysticks.
#![allow(unused_features)]
#![feature(alloc, core, std_misc, libc, fs, fs_walk, os, rustc_private, path)]
extern crate libc;
#[cfg(target_os = "windows")]
#[macro_use] extern crate rustc_bitflags;

#[cfg(feature = "sdl")]
extern crate sdl2;

/// Someday, somehow
#[cfg(all(feature = "emscripten", not(feature = "sdl")))]
mod emscripten;

#[cfg(all(feature = "emscripten", not(feature = "sdl")))]
pub use emscripten as native;

#[cfg(all(target_os = "linux", not(feature = "sdl")))]
mod linux;

#[cfg(all(target_os = "linux", not(feature = "sdl")))]
pub use linux as native;

#[cfg(all(target_os = "windows", not(feature = "sdl")))]
mod windows;

#[cfg(all(target_os = "windows", not(feature = "sdl")))]
pub use windows as native;

#[cfg(feature = "sdl")]
mod sdl;

#[cfg(feature = "sdl")]
pub use sdl as native;

mod mapper;

pub use mapper::JoystickMapper;
pub use native::{NativeJoystick, scan};

/// The maximum axis value
pub static MAX_AXIS_VALUE:i16 = 32767;
/// The minimum axis value
pub static MIN_AXIS_VALUE:i16 = -32767;

use std::borrow::Cow;
use std::mem::transmute as cast;

macro_rules! text_enum(
    ($name:ident, $($enumer:ident => $text:expr),+) => (
        impl ::std::fmt::Display for $name {
            fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                write!(fmt, "{}", match *self {
                    $($name::$enumer => $text),+
                })
            }
        }
        impl ::std::str::FromStr for $name {
            type Err = String;
            fn from_str(s: &str) -> Result<$name, String> {
                match s {
                    $($text => Ok($name::$enumer),)+
                    _ => Err(format!("Could not make {} from {}", stringify!($name), s))
                }
            }
        }
    )
);
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
/// A direction on a joystick
///
/// This uses the order that Linux drivers and the HTML5 Gamepad API uses so it should ring a bell
pub enum Axis {
	/// The x direction of the left stick
    ///
    /// This is usually used for horizontal movement in a game
    LeftX,
	/// The y direction of the left stick
    ///
    /// This is usually used for vertical movement in a game
    LeftY,
	/// The x direction of the right stick
    //
    /// This is usually used for looking around in a game
    RightX,
	/// The y direction of the right stick
    //
    /// This is usually used for looking around in a game
    RightY,
	/// How far down the left trigger is pressed
    ///
    /// This is only used as a button on some platforms so don't rely on just this
    TriggerLeft,
	/// How far down the right trigger is pressed
    ///
    /// This is only used as a button on some platforms so don't rely on just this
    TriggerRight
}
text_enum!(Axis,
    LeftX => "leftx",
    LeftY => "lefty",
    RightX => "rightx",
    RightY => "righty",
    TriggerLeft => "triggerleft",
    TriggerRight => "triggerright"
);

#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
/// A button on a joystick
///
/// This uses the order that Linux drivers and the HTML5 Gamepad API uses so it should be familiar
pub enum Button {
	/// The A button
    ///
    /// This is typically used for jumping
	A,
	/// The B button
    ///
    /// This is typically used for hitting
	B,
	/// The X button
	X,
	/// The Y button
	Y,
	/// The left top shoulder button
    ///
    /// This is usually used in FPS games for throwing a certain kind of grenade
	LeftShoulder,
	/// The right top shoulder button
	RightShoulder,
	/// The left bottom shoulder / trigger button
    ///
    /// This is typically used in FPS games for aiming down the sights in a weapon
	LeftTrigger,
	/// The right bottom shoulder / trigger button
    ///
    /// This is typically used in FPS games for shooting with a weapon
	RightTrigger,
	/// The back / select button
    ///
    /// This is usually used as an alternate pause menu or to open a menu in-game.
	Select,
	/// The start / forward button
    ///
    /// This is usually used to start and pause a game
	Start,
	/// The left stick button
	LeftStick,
	/// The right stick button
	RightStick,
	/// The up button on the directional pad
	DPadUp,
	/// The down button on the directional pad
	DPadDown,
	/// The left button on the directional pad
	DPadLeft,
	/// The right button on the directional pad
	DPadRight
}
text_enum!(Button,
    A => "a",
    B => "b",
    X => "x",
    Y => "y",
    LeftShoulder => "leftshoulder",
    RightShoulder => "rightshoulder",
    LeftTrigger => "lefttrigger",
    RightTrigger => "righttrigger",
    Select => "select",
    Start => "start",
    LeftStick => "leftstick",
    RightStick => "rightstick",
    DPadUp => "dpadup",
    DPadDown => "dpaddown",
    DPadLeft => "dpadleft",
    DPadRight => "dpadright"
);

#[derive(Copy, Debug, Eq, PartialEq)]
/// An event from a joystick
pub enum Event {
	/// Fired when a button is pressed with the button's index
	ButtonPressed(Button),
	/// Fired when a button is released with the button's index
	ButtonReleased(Button),
	/// Fired when a axis is moved with the axis index and its value,
	/// which is between `MIN_JOYSTICK_VALUE` and `MAX_JOYSTICK_VALUE`
	AxisMoved(Axis, i16)
}
/// Convert a raw event into a Reminisce event
pub trait IntoEvent {
	/// Convert this into a Reminisce event
	fn into_event(self) -> Event;
}

impl IntoEvent for Event {
    /// Convert the event into itself
    ///
    /// The only reason this exists is because windows doesn't have events so the backend has to
    /// make reminisce events directly and pretend that they are the native events.
    fn into_event(self) -> Event {
        self
    }
}

/// A joystick or gamepad
///
/// Each `Joystick` has its own event queue that can be polled repeatedly
/// using the `iter()` method or by calling the `poll()` method repeatedly.
///
/// ``` rust
/// use reminisce::{scan, Axis, Event, Joystick};
/// let mut joysticks = scan();
/// let (mut x, mut y) = (0, 0);
/// for joystick in &mut joysticks {
///     for event in joystick.iter() {
///         match event {
///             Event::AxisMoved(Axis::LeftX, nx) =>
///                 x += nx,
///             Event::AxisMoved(Axis::LeftY, ny) =>
///                 y += ny,
///             _ => ()
///         }
///     }
/// }
/// println!("{}, {}", x, y);
/// ```
pub trait Joystick : Sized {
	/// The version of this joystick that includes the state
    ///
    /// On Linux, this is a wrapper around the joystick, but on Windows,
    /// this is the same stucture because the joystick always includes
    /// state on it.
	type WithState : StatefulJoystick;

    /// The event that this joystick processes
    type NativeEvent: IntoEvent;

	/// Create a new joystick from its index
    ///
    /// If an error occurs, this will return the textual representation of that error.
    ///
    /// ``` rust
    /// use reminisce::{NativeJoystick, Joystick};
    /// let joystick:Result<NativeJoystick, &str> = Joystick::new(0);
    /// if let Ok(joystick) = joystick {
    ///     println!("{}", joystick.get_id())
    /// } else {
    ///     println!("No joystick plugged in")
    /// }
    /// ```
	fn new(index: u8) -> Result<Self, &'static str>;

	/// Check if the joystick is still connected
	fn is_connected(&self) -> bool;

	/// Get the identifier of this joystick
    ///
    /// This is a cow because it can be a static or owned String depending on the
    /// implementation.
	fn get_id(&self) -> Cow<str>;

	/// Get the index of this joystick
	fn get_index(&self) -> u8;

	/// Get the number of axes this joystick has
    ///
    /// This is capped at 6 axes for now.
	fn get_num_axes(&self) -> u8;

	/// Get the number of buttons this joystick has
    ///
    /// This is capped at 16 buttons currently.
	fn get_num_buttons(&self) -> u8;

    /// Get the battery level of this joystick
    ///
    /// Returns none if the joystick is wired or this operation is not supported
    /// by the backend
    fn get_battery(&self) -> Option<f32>;

    /// Poll the joystick for events in non-blocking mode and return the native event
    /// as returned from the backend
	fn poll_native(&mut self) -> Option<Self::NativeEvent>;

    /// Poll the joystick for events in non-blocking mode
    ///
    /// This runs `self.poll_native()` then converts it into an event using
    /// the `into_event` method.
    fn poll(&mut self) -> Option<Event> {
        self.poll_native().map(|e| e.into_event())
    }

    /// Map the axes and buttons of this joystick by wrapping it in a `JoystickMapper`
    fn into_mapper(self) -> JoystickMapper<Self> {
        JoystickMapper::new(self)
    }

    /// Iterate through the events that haven't been processed yet
    fn iter(&mut self) -> Poller<Self> {
        Poller {
            joystick: self
        }
    }

	/// Get the version of this joystick which includes state
    ///
    /// On the Linux backend, a wrapper is made, but on the Windows
    /// backend no wrapper is needed so this just returns the
    ///n `NativeJoystick` structure
	fn with_state(self) -> Self::WithState;
}

/// A joystick that keeps a record of its state
/// This makes it really easy to write the input for games, etc because its just a matter
/// of calling a single method to query where the axes are
///
/// ``` rust
/// use reminisce::{scan, Axis, Joystick, StatefulJoystick};
/// let mut joysticks = scan().into_iter().filter_map(|js| js.map(|js| with_state())).collect::<Vec<_>>();
/// for joystick in &joysticks {
///     let x = joystick.get_axis(Axis::LeftX).unwrap_or(0);
///     let y = joystick.get_axis(Axis::LeftY).unwrap_or(0);
///     println!("{}, {}", x, y)
/// }
/// ```
pub trait StatefulJoystick : Joystick + Sized {
	/// Get the value of a specific axis as an integer between `MIN_AXIS_VALUE` and `MAX_AXIS_VALUE`
	fn get_axis(&self, index: Axis) -> Option<i16>;

	/// Get the value of a specific axis normalised to between -1.0 and 1.0
	fn get_normalised_axis(&self, index: Axis) -> Option<f32> {
		self.get_axis(index).map(|v| v as f32 / MAX_AXIS_VALUE as f32)
	}

	/// Iterate over the axes in this joystick
	fn axes(&self) -> Axes<Self> {
		use std::mem;
		Axes {
			joystick: self,
			axis: unsafe { mem::zeroed() }
		}
	}

	/// Iterate over the buttons in this joystick
	fn buttons(&self) -> Buttons<Self> {
		use std::mem;
		Buttons {
			joystick: self,
			button: unsafe { mem::zeroed() }
		}
	}

	/// Get the value (if it is pressed or not) of a specific button
	///
	/// The first two buttons are usually the accept and back buttons
	fn get_button(&self, index: Button) -> Option<bool>;

	/// Update the state of this joystick by polling the native backend
	fn update(&mut self);
}

/// An iterator over a joystick's axes
pub struct Axes<'a, J> where J:StatefulJoystick+'a {
	joystick: &'a J,
	axis: u8
}
impl<'a, J> Iterator for Axes<'a, J> where J:StatefulJoystick {
	type Item = (Axis, i16);
	fn next(&mut self) -> Option<(Axis, i16)> {
		self.axis += 1;
		let axis = unsafe { cast(self.axis - 1) };
		self.joystick.get_axis(axis).map(|v| (axis, v))
	}
}

/// An iterator over a joystick's buttons
pub struct Buttons<'a, J> where J:StatefulJoystick+'a {
	joystick: &'a J,
	button: u8
}
impl<'a, J> Iterator for Buttons<'a, J> where J:StatefulJoystick {
	type Item = (Button, bool);
	fn next(&mut self) -> Option<(Button, bool)> {
		self.button += 1;
		let button = unsafe { cast(self.button - 1) };
		self.joystick.get_button(button).map(|v| (button, v))
	}
}

/// An iterator over a joystick's event queue
pub struct Poller<'a, J> where J:Joystick+'a {
    joystick: &'a mut J
}

impl<'a, J> Iterator for Poller<'a, J> where J:Joystick {
	type Item = Event;
    /// This calls the `joystick.poll()` method to poll for the next event
	fn next(&mut self) -> Option<Event> {
		self.joystick.poll()
	}
}
<|endoftext|>


<commit_before>use std::{
    ops::Deref,
    sync::{atomic::AtomicU64, Arc, RwLock},
};

use pagecache::FastMap8;

use super::*;

/// The `sled` embedded database!
#[derive(Clone)]
pub struct Db {
    context: Context,
    default: Arc<Tree>,
    tenants: Arc<RwLock<FastMap8<Vec<u8>, Arc<Tree>>>>,
}

unsafe impl Send for Db {}

unsafe impl Sync for Db {}

impl Deref for Db {
    type Target = Tree;

    fn deref(&self) -> &Tree {
        &self.default
    }
}

impl Db {
    /// Load existing or create a new `Db` with a default configuration.
    pub fn start_default<P: AsRef<std::path::Path>>(path: P) -> Result<Db> {
        let config = ConfigBuilder::new().path(path).build();
        Self::start(config)
    }

    /// Load existing or create a new `Db`.
    pub fn start(config: Config) -> Result<Db> {
        let _measure = Measure::new(&M.tree_start);

        let context = Context::start(config)?;

        let flusher_pagecache = context.pagecache.clone();
        let flusher = context.flush_every_ms.map(move |fem| {
            flusher::Flusher::new(
                "log flusher".to_owned(),
                flusher_pagecache,
                fem,
            )
        });
        *context._flusher.lock().unwrap() = flusher;

        // create or open the default tree
        let tx = context.pagecache.begin()?;
        let default = Arc::new(meta::open_tree(
            context.clone(),
            DEFAULT_TREE_ID.to_vec(),
            &tx,
        )?);

        let ret = Db {
            context: context.clone(),
            default,
            tenants: Arc::new(RwLock::new(FastMap8::default())),
        };

        let mut tenants = ret.tenants.write().unwrap();

        for (id, root) in context.pagecache.meta(&tx)?.tenants().into_iter() {
            let tree = Tree {
                tree_id: id.clone(),
                subscriptions: Arc::new(Subscriptions::default()),
                context: context.clone(),
                root: Arc::new(AtomicU64::new(root)),
            };
            tenants.insert(id, Arc::new(tree));
        }

        drop(tenants);

        #[cfg(feature = "event_log")]
        context.event_log.meta_after_restart(
            context
                .pagecache
                .meta(&tx)
                .expect("should be able to get meta under test")
                .clone(),
        );

        Ok(ret)
    }

    /// Open or create a new disk-backed Tree with its own keyspace,
    /// accessible from the `Db` via the provided identifier.
    pub fn open_tree<V: AsRef<[u8]>>(&self, name: V) -> Result<Arc<Tree>> {
        let name = name.as_ref();
        let tenants = self.tenants.read().unwrap();
        if let Some(tree) = tenants.get(name) {
            return Ok(tree.clone());
        }
        drop(tenants);

        let tx = self.context.pagecache.begin()?;

        let mut tenants = self.tenants.write().unwrap();
        let tree = Arc::new(meta::open_tree(
            self.context.clone(),
            name.to_vec(),
            &tx,
        )?);
        tenants.insert(name.to_vec(), tree.clone());
        drop(tenants);
        Ok(tree)
    }

    /// Remove a disk-backed collection.
    pub fn drop_tree(&self, name: &[u8]) -> Result<bool> {
        if name == DEFAULT_TREE_ID {
            return Err(Error::Unsupported(
                "cannot remove the core structures".into(),
            ));
        }
        trace!("dropping tree {:?}", name,);

        let mut tenants = self.tenants.write().unwrap();

        let tree = if let Some(tree) = tenants.remove(&*name) {
            tree
        } else {
            return Ok(false);
        };

        let tx = self.context.pagecache.begin()?;

        let mut root_id =
            Some(self.context.pagecache.meta_pid_for_name(&name, &tx)?);

        let mut leftmost_chain: Vec<PageId> = vec![root_id.unwrap()];
        let mut cursor = root_id.unwrap();
        loop {
            let (tree_ptr, frags) =
                self.context.pagecache.get_page_frags(cursor, &tx)?;
            let view = View::new(cursor, tree_ptr, frags);
            let node = view.compact(&self.context);

            if let Some(index) = node.data.index_ref() {
                let leftmost_child = index[0].1;
                leftmost_chain.push(leftmost_child);
                cursor = leftmost_child;
            } else {
                break;
            }
        }

        loop {
            let res = self.context.pagecache.cas_root_in_meta(
                name.to_vec(),
                root_id,
                None,
                &tx,
            )?;

            if let Err(actual_root) = res {
                root_id = actual_root;
            } else {
                break;
            }
        }

        tree.root
            .store(u64::max_value(), std::sync::atomic::Ordering::SeqCst);

        // drop writer lock
        drop(tenants);

        tree.gc_pages(leftmost_chain)?;

        tx.flush();

        Ok(true)
    }

    /// Returns the trees names saved in this Db.
    pub fn tree_names(&self) -> Vec<Vec<u8>> {
        let tenants = self.tenants.read().unwrap();
        tenants.iter().map(|(name, _)| name.clone()).collect()
    }

    /// Returns `true` if the database was
    /// recovered from a previous process.
    /// Note that database state is only
    /// guaranteed to be present up to the
    /// last call to `flush`! Otherwise state
    /// is synced to disk periodically if the
    /// `sync_every_ms` configuration option
    /// is set to `Some(number_of_ms_between_syncs)`
    /// or if the IO buffer gets filled to
    /// capacity before being rotated.
    pub fn was_recovered(&self) -> bool {
        self.context.was_recovered()
    }

    /// Generate a monotonic ID. Not guaranteed to be
    /// contiguous. Written to disk every `idgen_persist_interval`
    /// operations, followed by a blocking flush. During recovery, we
    /// take the last recovered generated ID and add 2x
    /// the `idgen_persist_interval` to it. While persisting, if the
    /// previous persisted counter wasn't synced to disk yet, we will do
    /// a blocking flush to fsync the latest counter, ensuring
    /// that we will never give out the same counter twice.
    pub fn generate_id(&self) -> Result<u64> {
        self.context.generate_id()
    }
}
<commit_msg>switch db over to using view_for_pid<commit_after>use std::{
    ops::Deref,
    sync::{atomic::AtomicU64, Arc, RwLock},
};

use pagecache::FastMap8;

use super::*;

/// The `sled` embedded database!
#[derive(Clone)]
pub struct Db {
    context: Context,
    default: Arc<Tree>,
    tenants: Arc<RwLock<FastMap8<Vec<u8>, Arc<Tree>>>>,
}

unsafe impl Send for Db {}

unsafe impl Sync for Db {}

impl Deref for Db {
    type Target = Tree;

    fn deref(&self) -> &Tree {
        &self.default
    }
}

impl Db {
    /// Load existing or create a new `Db` with a default configuration.
    pub fn start_default<P: AsRef<std::path::Path>>(path: P) -> Result<Db> {
        let config = ConfigBuilder::new().path(path).build();
        Self::start(config)
    }

    /// Load existing or create a new `Db`.
    pub fn start(config: Config) -> Result<Db> {
        let _measure = Measure::new(&M.tree_start);

        let context = Context::start(config)?;

        let flusher_pagecache = context.pagecache.clone();
        let flusher = context.flush_every_ms.map(move |fem| {
            flusher::Flusher::new(
                "log flusher".to_owned(),
                flusher_pagecache,
                fem,
            )
        });
        *context._flusher.lock().unwrap() = flusher;

        // create or open the default tree
        let tx = context.pagecache.begin()?;
        let default = Arc::new(meta::open_tree(
            context.clone(),
            DEFAULT_TREE_ID.to_vec(),
            &tx,
        )?);

        let ret = Db {
            context: context.clone(),
            default,
            tenants: Arc::new(RwLock::new(FastMap8::default())),
        };

        let mut tenants = ret.tenants.write().unwrap();

        for (id, root) in context.pagecache.meta(&tx)?.tenants().into_iter() {
            let tree = Tree {
                tree_id: id.clone(),
                subscriptions: Arc::new(Subscriptions::default()),
                context: context.clone(),
                root: Arc::new(AtomicU64::new(root)),
            };
            tenants.insert(id, Arc::new(tree));
        }

        drop(tenants);

        #[cfg(feature = "event_log")]
        context.event_log.meta_after_restart(
            context
                .pagecache
                .meta(&tx)
                .expect("should be able to get meta under test")
                .clone(),
        );

        Ok(ret)
    }

    /// Open or create a new disk-backed Tree with its own keyspace,
    /// accessible from the `Db` via the provided identifier.
    pub fn open_tree<V: AsRef<[u8]>>(&self, name: V) -> Result<Arc<Tree>> {
        let name = name.as_ref();
        let tenants = self.tenants.read().unwrap();
        if let Some(tree) = tenants.get(name) {
            return Ok(tree.clone());
        }
        drop(tenants);

        let tx = self.context.pagecache.begin()?;

        let mut tenants = self.tenants.write().unwrap();
        let tree = Arc::new(meta::open_tree(
            self.context.clone(),
            name.to_vec(),
            &tx,
        )?);
        tenants.insert(name.to_vec(), tree.clone());
        drop(tenants);
        Ok(tree)
    }

    /// Remove a disk-backed collection.
    pub fn drop_tree(&self, name: &[u8]) -> Result<bool> {
        if name == DEFAULT_TREE_ID {
            return Err(Error::Unsupported(
                "cannot remove the core structures".into(),
            ));
        }
        trace!("dropping tree {:?}", name,);

        let mut tenants = self.tenants.write().unwrap();

        let tree = if let Some(tree) = tenants.remove(&*name) {
            tree
        } else {
            return Ok(false);
        };

        let tx = self.context.pagecache.begin()?;

        let mut root_id =
            Some(self.context.pagecache.meta_pid_for_name(&name, &tx)?);

        let mut leftmost_chain: Vec<PageId> = vec![root_id.unwrap()];
        let mut cursor = root_id.unwrap();
        loop {
            let view = self.view_for_pid(cursor, &tx)?;
            let node = view.compact(&self.context);

            if let Some(index) = node.data.index_ref() {
                let leftmost_child = index[0].1;
                leftmost_chain.push(leftmost_child);
                cursor = leftmost_child;
            } else {
                break;
            }
        }

        loop {
            let res = self.context.pagecache.cas_root_in_meta(
                name.to_vec(),
                root_id,
                None,
                &tx,
            )?;

            if let Err(actual_root) = res {
                root_id = actual_root;
            } else {
                break;
            }
        }

        tree.root
            .store(u64::max_value(), std::sync::atomic::Ordering::SeqCst);

        // drop writer lock
        drop(tenants);

        tree.gc_pages(leftmost_chain)?;

        tx.flush();

        Ok(true)
    }

    /// Returns the trees names saved in this Db.
    pub fn tree_names(&self) -> Vec<Vec<u8>> {
        let tenants = self.tenants.read().unwrap();
        tenants.iter().map(|(name, _)| name.clone()).collect()
    }

    /// Returns `true` if the database was
    /// recovered from a previous process.
    /// Note that database state is only
    /// guaranteed to be present up to the
    /// last call to `flush`! Otherwise state
    /// is synced to disk periodically if the
    /// `sync_every_ms` configuration option
    /// is set to `Some(number_of_ms_between_syncs)`
    /// or if the IO buffer gets filled to
    /// capacity before being rotated.
    pub fn was_recovered(&self) -> bool {
        self.context.was_recovered()
    }

    /// Generate a monotonic ID. Not guaranteed to be
    /// contiguous. Written to disk every `idgen_persist_interval`
    /// operations, followed by a blocking flush. During recovery, we
    /// take the last recovered generated ID and add 2x
    /// the `idgen_persist_interval` to it. While persisting, if the
    /// previous persisted counter wasn't synced to disk yet, we will do
    /// a blocking flush to fsync the latest counter, ensuring
    /// that we will never give out the same counter twice.
    pub fn generate_id(&self) -> Result<u64> {
        self.context.generate_id()
    }
}
<|endoftext|>


<commit_before>//! A Loop Invariant Code Motion optimization pass

use ir::{Function, Ebb, Inst, Value, Cursor, Type, InstBuilder, Layout};
use flowgraph::ControlFlowGraph;
use std::collections::HashSet;
use dominator_tree::DominatorTree;
use entity_list::{EntityList, ListPool};
use loop_analysis::{Loop, LoopAnalysis};

/// Performs the LICM pass by detecting loops within the CFG and moving
/// loop-invariant instructions out of them.
/// Changes the CFG and domtree in-place during the operation.
pub fn do_licm(func: &mut Function,
               cfg: &mut ControlFlowGraph,
               domtree: &mut DominatorTree,
               loop_analysis: &mut LoopAnalysis) {
    loop_analysis.compute(func, cfg, domtree);
    for lp in loop_analysis.loops() {
        // For each loop that we want to optimize we determine the set of loop-invariant
        // instructions
        let invariant_inst = remove_loop_invariant_instructions(lp, func, cfg, loop_analysis);
        // Then we create the loop's pre-header and fill it with the invariant instructions
        // Then we remove the invariant instructions from the loop body
        if invariant_inst.len() > 0 {
            // If the loop has a natural pre-header we use it, otherwise we create it.
            let mut pos;
            match has_pre_header(&func.layout,
                                 cfg,
                                 domtree,
                                 loop_analysis.loop_header(lp).clone()) {
                None => {
                    let pre_header = create_pre_header(loop_analysis.loop_header(lp).clone(),
                                                       func,
                                                       cfg,
                                                       domtree);
                    pos = Cursor::new(&mut func.layout);
                    pos.goto_bottom(pre_header);
                    pos.prev_inst();
                }
                // If there is a natural pre-header we insert new instructions just before the
                // related jumping instruction (which is not necessarily at the end).
                Some((_, last_inst)) => {
                    pos = Cursor::new(&mut func.layout);
                    pos.goto_inst(last_inst);
                }
            };
            // The last instruction of the pre-header is the termination instruction (usually
            // a jump) so we need to insert just before this.
            for inst in invariant_inst.iter() {
                pos.insert_inst(inst.clone());
            }
        }
    }
    // We have to recompute the domtree to account for the changes
    cfg.compute(func);
    domtree.compute(func, cfg);
}

// Insert a pre-header before the header, modifying the function layout and CFG to reflect it.
// A jump instruction to the header is placed at the end of the pre-header.
fn create_pre_header(header: Ebb,
                     func: &mut Function,
                     cfg: &mut ControlFlowGraph,
                     domtree: &DominatorTree)
                     -> Ebb {
    let pool = &mut ListPool::<Value>::new();
    let header_args_values: Vec<Value> = func.dfg
        .ebb_args(header)
        .into_iter()
        .map(|val| *val)
        .collect();
    let header_args_types: Vec<Type> = header_args_values
        .clone()
        .into_iter()
        .map(|val| func.dfg.value_type(val))
        .collect();
    let pre_header = func.dfg.make_ebb();
    let mut pre_header_args_value: EntityList<Value> = EntityList::new();
    for typ in header_args_types {
        pre_header_args_value.push(func.dfg.append_ebb_arg(pre_header, typ), pool);
    }
    for &(_, last_inst) in cfg.get_predecessors(header) {
        // We only follow normal edges (not the back edges)
        if !domtree.ebb_dominates(header.clone(), last_inst, &func.layout) {
            change_branch_jump_destination(last_inst, pre_header, func);
        }
    }
    {
        let mut pos = Cursor::new(&mut func.layout);
        pos.goto_top(header);
        // Inserts the pre-header at the right place in the layout.
        pos.insert_ebb(pre_header);
        pos.next_inst();
        func.dfg
            .ins(&mut pos)
            .jump(header, pre_header_args_value.as_slice(pool));
    }
    pre_header
}

// Detects if a loop header has a natural pre-header.
//
// A loop header has a pre-header if there is only one predecessor that the header doesn't
// dominate.
// Returns the pre-header Ebb and the instruction jumping to  the header.
fn has_pre_header(layout: &Layout,
                  cfg: &ControlFlowGraph,
                  domtree: &DominatorTree,
                  header: Ebb)
                  -> Option<(Ebb, Inst)> {
    let mut result = None;
    let mut found = false;
    for &(pred_ebb, last_inst) in cfg.get_predecessors(header) {
        // We only count normal edges (not the back edges)
        if !domtree.ebb_dominates(header.clone(), last_inst, layout) {
            if found {
                // We have already found one, there are more than one
                return None;
            } else {
                result = Some((pred_ebb, last_inst));
                found = true;
            }
        }
    }
    result
}

// Change the destination of a jump or branch instruction. Does nothing if called with a non-jump
// or non-branch instruction.
fn change_branch_jump_destination(inst: Inst, new_ebb: Ebb, func: &mut Function) {
    match func.dfg[inst].branch_destination_mut() {
        None => (),
        Some(instruction_dest) => *instruction_dest = new_ebb,
    }
}

// Traverses a loop in reverse post-order from a header EBB and identify lopp-invariant
// instructions. Theseloop-invariant instructions are then removed from the code and returned
// (in reverse post-order) for later use.
fn remove_loop_invariant_instructions(lp: Loop,
                                      func: &mut Function,
                                      cfg: &ControlFlowGraph,
                                      loop_analysis: &LoopAnalysis)
                                      -> Vec<Inst> {
    let mut loop_values: HashSet<Value> = HashSet::new();
    let mut invariant_inst: Vec<Inst> = Vec::new();
    let mut pos = Cursor::new(&mut func.layout);
    // We traverse the loop EBB in reverse post-order.
    for ebb in postorder_ebbs_loop(loop_analysis, cfg, lp).iter().rev() {
        // Arguments of the EBB are loop values
        for val in func.dfg.ebb_args(*ebb) {
            loop_values.insert(val.clone());
        }
        pos.goto_top(*ebb);
        while let Some(inst) = pos.next_inst() {
            if func.dfg.has_results(inst) &&
               func.dfg
                   .inst_args(inst)
                   .into_iter()
                   .all(|arg| !loop_values.contains(arg)) {
                // If all the instruction's argument are defined outside the loop
                // then this instruction is loop-invariant
                invariant_inst.push(inst);
                // We remove it from the loop
                pos.remove_inst();
                pos.prev_inst();
            } else {
                // If the instruction is not loop-invariant we push its results in the set of
                // loop values
                for out in func.dfg.inst_results(inst) {
                    loop_values.insert(out.clone());
                }
            }
        }
    }
    invariant_inst
}

/// Return ebbs from a loop in post-order, starting from an entry point in the block.
pub fn postorder_ebbs_loop(loop_analysis: &LoopAnalysis,
                           cfg: &ControlFlowGraph,
                           lp: Loop)
                           -> Vec<Ebb> {
    let mut grey = HashSet::new();
    let mut black = HashSet::new();
    let mut stack = vec![loop_analysis.loop_header(lp).clone()];
    let mut postorder = Vec::new();

    while !stack.is_empty() {
        let node = stack.pop().unwrap();
        if !grey.contains(&node) {
            // This is a white node. Mark it as gray.
            grey.insert(node);
            stack.push(node);
            // Get any children we've never seen before.
            for child in cfg.get_successors(node) {
                if loop_analysis.is_in_loop(child.clone(), lp) && !grey.contains(child) {
                    stack.push(child.clone());
                }
            }
        } else if !black.contains(&node) {
            postorder.push(node.clone());
            black.insert(node.clone());
        }
    }
    postorder
}
<commit_msg>LICM pass: small changes after code review (#94)<commit_after>//! A Loop Invariant Code Motion optimization pass

use ir::{Function, Ebb, Inst, Value, Cursor, Type, InstBuilder, Layout};
use flowgraph::ControlFlowGraph;
use std::collections::HashSet;
use dominator_tree::DominatorTree;
use entity_list::{EntityList, ListPool};
use loop_analysis::{Loop, LoopAnalysis};

/// Performs the LICM pass by detecting loops within the CFG and moving
/// loop-invariant instructions out of them.
/// Changes the CFG and domtree in-place during the operation.
pub fn do_licm(func: &mut Function,
               cfg: &mut ControlFlowGraph,
               domtree: &mut DominatorTree,
               loop_analysis: &mut LoopAnalysis) {
    loop_analysis.compute(func, cfg, domtree);
    for lp in loop_analysis.loops() {
        // For each loop that we want to optimize we determine the set of loop-invariant
        // instructions
        let invariant_inst = remove_loop_invariant_instructions(lp, func, cfg, loop_analysis);
        // Then we create the loop's pre-header and fill it with the invariant instructions
        // Then we remove the invariant instructions from the loop body
        if invariant_inst.len() > 0 {
            // If the loop has a natural pre-header we use it, otherwise we create it.
            let mut pos;
            match has_pre_header(&func.layout,
                                 cfg,
                                 domtree,
                                 loop_analysis.loop_header(lp).clone()) {
                None => {
                    let pre_header = create_pre_header(loop_analysis.loop_header(lp).clone(),
                                                       func,
                                                       cfg,
                                                       domtree);
                    pos = Cursor::new(&mut func.layout);
                    pos.goto_bottom(pre_header);
                    pos.prev_inst();
                }
                // If there is a natural pre-header we insert new instructions just before the
                // related jumping instruction (which is not necessarily at the end).
                Some((_, last_inst)) => {
                    pos = Cursor::new(&mut func.layout);
                    pos.goto_inst(last_inst);
                }
            };
            // The last instruction of the pre-header is the termination instruction (usually
            // a jump) so we need to insert just before this.
            for inst in invariant_inst {
                pos.insert_inst(inst.clone());
            }
        }
    }
    // We have to recompute the domtree to account for the changes
    cfg.compute(func);
    domtree.compute(func, cfg);
}

// Insert a pre-header before the header, modifying the function layout and CFG to reflect it.
// A jump instruction to the header is placed at the end of the pre-header.
fn create_pre_header(header: Ebb,
                     func: &mut Function,
                     cfg: &mut ControlFlowGraph,
                     domtree: &DominatorTree)
                     -> Ebb {
    let pool = &mut ListPool::<Value>::new();
    let header_args_values: Vec<Value> = func.dfg.ebb_args(header).into_iter().cloned().collect();
    let header_args_types: Vec<Type> = header_args_values
        .clone()
        .into_iter()
        .map(|val| func.dfg.value_type(val))
        .collect();
    let pre_header = func.dfg.make_ebb();
    let mut pre_header_args_value: EntityList<Value> = EntityList::new();
    for typ in header_args_types {
        pre_header_args_value.push(func.dfg.append_ebb_arg(pre_header, typ), pool);
    }
    for &(_, last_inst) in cfg.get_predecessors(header) {
        // We only follow normal edges (not the back edges)
        if !domtree.ebb_dominates(header.clone(), last_inst, &func.layout) {
            change_branch_jump_destination(last_inst, pre_header, func);
        }
    }
    {
        let mut pos = Cursor::new(&mut func.layout);
        pos.goto_top(header);
        // Inserts the pre-header at the right place in the layout.
        pos.insert_ebb(pre_header);
        pos.next_inst();
        func.dfg
            .ins(&mut pos)
            .jump(header, pre_header_args_value.as_slice(pool));
    }
    pre_header
}

// Detects if a loop header has a natural pre-header.
//
// A loop header has a pre-header if there is only one predecessor that the header doesn't
// dominate.
// Returns the pre-header Ebb and the instruction jumping to  the header.
fn has_pre_header(layout: &Layout,
                  cfg: &ControlFlowGraph,
                  domtree: &DominatorTree,
                  header: Ebb)
                  -> Option<(Ebb, Inst)> {
    let mut result = None;
    let mut found = false;
    for &(pred_ebb, last_inst) in cfg.get_predecessors(header) {
        // We only count normal edges (not the back edges)
        if !domtree.ebb_dominates(header.clone(), last_inst, layout) {
            if found {
                // We have already found one, there are more than one
                return None;
            } else {
                result = Some((pred_ebb, last_inst));
                found = true;
            }
        }
    }
    result
}

// Change the destination of a jump or branch instruction. Does nothing if called with a non-jump
// or non-branch instruction.
fn change_branch_jump_destination(inst: Inst, new_ebb: Ebb, func: &mut Function) {
    match func.dfg[inst].branch_destination_mut() {
        None => (),
        Some(instruction_dest) => *instruction_dest = new_ebb,
    }
}

// Traverses a loop in reverse post-order from a header EBB and identify loop-invariant
// instructions. These loop-invariant instructions are then removed from the code and returned
// (in reverse post-order) for later use.
fn remove_loop_invariant_instructions(lp: Loop,
                                      func: &mut Function,
                                      cfg: &ControlFlowGraph,
                                      loop_analysis: &LoopAnalysis)
                                      -> Vec<Inst> {
    let mut loop_values: HashSet<Value> = HashSet::new();
    let mut invariant_inst: Vec<Inst> = Vec::new();
    let mut pos = Cursor::new(&mut func.layout);
    // We traverse the loop EBB in reverse post-order.
    for ebb in postorder_ebbs_loop(loop_analysis, cfg, lp).iter().rev() {
        // Arguments of the EBB are loop values
        for val in func.dfg.ebb_args(*ebb) {
            loop_values.insert(val.clone());
        }
        pos.goto_top(*ebb);
        while let Some(inst) = pos.next_inst() {
            if func.dfg.has_results(inst) &&
               func.dfg
                   .inst_args(inst)
                   .into_iter()
                   .all(|arg| !loop_values.contains(arg)) {
                // If all the instruction's argument are defined outside the loop
                // then this instruction is loop-invariant
                invariant_inst.push(inst);
                // We remove it from the loop
                pos.remove_inst_and_step_back();
            } else {
                // If the instruction is not loop-invariant we push its results in the set of
                // loop values
                for out in func.dfg.inst_results(inst) {
                    loop_values.insert(out.clone());
                }
            }
        }
    }
    invariant_inst
}

/// Return ebbs from a loop in post-order, starting from an entry point in the block.
fn postorder_ebbs_loop(loop_analysis: &LoopAnalysis, cfg: &ControlFlowGraph, lp: Loop) -> Vec<Ebb> {
    let mut grey = HashSet::new();
    let mut black = HashSet::new();
    let mut stack = vec![loop_analysis.loop_header(lp).clone()];
    let mut postorder = Vec::new();

    while !stack.is_empty() {
        let node = stack.pop().unwrap();
        if !grey.contains(&node) {
            // This is a white node. Mark it as gray.
            grey.insert(node);
            stack.push(node);
            // Get any children we've never seen before.
            for child in cfg.get_successors(node) {
                if loop_analysis.is_in_loop(child.clone(), lp) && !grey.contains(child) {
                    stack.push(child.clone());
                }
            }
        } else if !black.contains(&node) {
            postorder.push(node.clone());
            black.insert(node.clone());
        }
    }
    postorder
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::fs::File;
use std::io::prelude::*;
use toml::{self, Value};
use toml::value::Table;

use config::Config;
use env::Env;
use file_saver::save_to_file;
use nameutil;
use version::Version;

pub fn generate(env: &Env) -> String {
    info!(
        "Generatnig sys Cargo.toml for {}",
        env.config.library_name
    );

    let path = env.config.target_path.join("Cargo.toml");

    let mut toml_str = String::new();
    if let Ok(mut file) = File::open(&path) {
        file.read_to_string(&mut toml_str).unwrap();
    }
    let empty = toml_str.trim().is_empty();
    let mut root_table = toml::from_str(&toml_str).unwrap_or_else(|_| Table::new());
    let crate_name = get_crate_name(&env.config, &root_table);

    if empty {
        fill_empty(&mut root_table, env, &crate_name);
    }
    fill_in(&mut root_table, env);

    save_to_file(&path, env.config.make_backup, |w| {
        w.write_all(toml::to_string(&root_table).unwrap().as_bytes())
    });

    crate_name
}

fn fill_empty(root: &mut Table, env: &Env, crate_name: &str) {
    let package_name = crate_name.replace("_", "-");

    {
        let package = upsert_table(root, "package");
        set_string(package, "name", package_name);
        set_string(package, "version", "0.2.0");
        set_string(package, "links", nameutil::crate_name(&env.config.library_name));
    }

    {
        let lib = upsert_table(root, "lib");
        set_string(lib, "name", crate_name);
    }

    let deps = upsert_table(root, "dependencies");
    for ext_lib in &env.config.external_libraries {
        let ext_package = format!("{}-sys", ext_lib.crate_name);
        let dep = upsert_table(deps, &*ext_package);
        set_string(dep, "path", format!("../{}", ext_package));
        set_string(dep, "version", "0.2.0");
    }
}

fn fill_in(root: &mut Table, env: &Env) {
    {
        let package = upsert_table(root, "package");
        set_string(package, "build", "build.rs");
        //set_string(package, "version", "0.2.0");
    }

    {
        let deps = upsert_table(root, "dependencies");
        set_string(deps, "libc", "0.2");
    }

    {
        let build_deps = upsert_table(root, "build-dependencies");
        set_string(build_deps, "pkg-config", "0.3.7");
    }

    {
        let dev_deps = upsert_table(root, "dev-dependencies");
        set_string(dev_deps, "shell-words", "0.1.0");
        set_string(dev_deps, "tempdir", "0.3");
    }

    {
        let features = upsert_table(root, "features");
        let versions = env.namespaces
            .main()
            .versions
            .iter()
            .filter(|&&v| v > env.config.min_cfg_version);
        versions.fold(None::<Version>, |prev, &version| {
            let prev_array: Vec<Value> =
                prev.iter().map(|v| Value::String(v.to_feature())).collect();
            features.insert(version.to_feature(), Value::Array(prev_array));
            Some(version)
        });
        features.insert("dox".to_string(), Value::Array(Vec::new()));
    }
}

/// Returns the name of crate being currently generated.
fn get_crate_name(config: &Config, root: &Table) -> String {
    if let Some(&Value::Table(ref lib)) = root.get("lib") {
        if let Some(&Value::String(ref lib_name)) = lib.get("name") {
            return lib_name.to_owned();
        }
    }
    if let Some(&Value::Table(ref package)) = root.get("package") {
        if let Some(&Value::String(ref package_name)) = package.get("name") {
            return nameutil::crate_name(package_name);
        }
    }
    return format!("{}_sys", nameutil::crate_name(&config.library_name));
}

fn set_string<S: Into<String>>(table: &mut Table, name: &str, new_value: S) {
    if let Some(v) = table.get_mut(name) {
        *v = Value::String(new_value.into());
        return;
    }
    table.insert(name.into(), Value::String(new_value.into()));
}

fn upsert_table<S: Into<String>>(parent: &mut Table, name: S) -> &mut Table {
    if let Value::Table(ref mut table) = *parent
        .entry(name.into())
        .or_insert_with(|| Value::Table(BTreeMap::new()))
    {
        table
    } else {
        unreachable!()
    }
}
<commit_msg>sys: fix typo<commit_after>use std::collections::BTreeMap;
use std::fs::File;
use std::io::prelude::*;
use toml::{self, Value};
use toml::value::Table;

use config::Config;
use env::Env;
use file_saver::save_to_file;
use nameutil;
use version::Version;

pub fn generate(env: &Env) -> String {
    info!(
        "Generating sys Cargo.toml for {}",
        env.config.library_name
    );

    let path = env.config.target_path.join("Cargo.toml");

    let mut toml_str = String::new();
    if let Ok(mut file) = File::open(&path) {
        file.read_to_string(&mut toml_str).unwrap();
    }
    let empty = toml_str.trim().is_empty();
    let mut root_table = toml::from_str(&toml_str).unwrap_or_else(|_| Table::new());
    let crate_name = get_crate_name(&env.config, &root_table);

    if empty {
        fill_empty(&mut root_table, env, &crate_name);
    }
    fill_in(&mut root_table, env);

    save_to_file(&path, env.config.make_backup, |w| {
        w.write_all(toml::to_string(&root_table).unwrap().as_bytes())
    });

    crate_name
}

fn fill_empty(root: &mut Table, env: &Env, crate_name: &str) {
    let package_name = crate_name.replace("_", "-");

    {
        let package = upsert_table(root, "package");
        set_string(package, "name", package_name);
        set_string(package, "version", "0.2.0");
        set_string(package, "links", nameutil::crate_name(&env.config.library_name));
    }

    {
        let lib = upsert_table(root, "lib");
        set_string(lib, "name", crate_name);
    }

    let deps = upsert_table(root, "dependencies");
    for ext_lib in &env.config.external_libraries {
        let ext_package = format!("{}-sys", ext_lib.crate_name);
        let dep = upsert_table(deps, &*ext_package);
        set_string(dep, "path", format!("../{}", ext_package));
        set_string(dep, "version", "0.2.0");
    }
}

fn fill_in(root: &mut Table, env: &Env) {
    {
        let package = upsert_table(root, "package");
        set_string(package, "build", "build.rs");
        //set_string(package, "version", "0.2.0");
    }

    {
        let deps = upsert_table(root, "dependencies");
        set_string(deps, "libc", "0.2");
    }

    {
        let build_deps = upsert_table(root, "build-dependencies");
        set_string(build_deps, "pkg-config", "0.3.7");
    }

    {
        let dev_deps = upsert_table(root, "dev-dependencies");
        set_string(dev_deps, "shell-words", "0.1.0");
        set_string(dev_deps, "tempdir", "0.3");
    }

    {
        let features = upsert_table(root, "features");
        let versions = env.namespaces
            .main()
            .versions
            .iter()
            .filter(|&&v| v > env.config.min_cfg_version);
        versions.fold(None::<Version>, |prev, &version| {
            let prev_array: Vec<Value> =
                prev.iter().map(|v| Value::String(v.to_feature())).collect();
            features.insert(version.to_feature(), Value::Array(prev_array));
            Some(version)
        });
        features.insert("dox".to_string(), Value::Array(Vec::new()));
    }
}

/// Returns the name of crate being currently generated.
fn get_crate_name(config: &Config, root: &Table) -> String {
    if let Some(&Value::Table(ref lib)) = root.get("lib") {
        if let Some(&Value::String(ref lib_name)) = lib.get("name") {
            return lib_name.to_owned();
        }
    }
    if let Some(&Value::Table(ref package)) = root.get("package") {
        if let Some(&Value::String(ref package_name)) = package.get("name") {
            return nameutil::crate_name(package_name);
        }
    }
    return format!("{}_sys", nameutil::crate_name(&config.library_name));
}

fn set_string<S: Into<String>>(table: &mut Table, name: &str, new_value: S) {
    if let Some(v) = table.get_mut(name) {
        *v = Value::String(new_value.into());
        return;
    }
    table.insert(name.into(), Value::String(new_value.into()));
}

fn upsert_table<S: Into<String>>(parent: &mut Table, name: S) -> &mut Table {
    if let Value::Table(ref mut table) = *parent
        .entry(name.into())
        .or_insert_with(|| Value::Table(BTreeMap::new()))
    {
        table
    } else {
        unreachable!()
    }
}
<|endoftext|>


<commit_before>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};

static IP: &'static str  = "127.0.0.1";
static PORT:        int  = 4414;
static mut visitor_count: uint = 0;

fn main() {
    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {
        // Spawn a task to handle the connection
        do spawn {
            let mut stream = stream;

            match stream {
                Some(ref mut s) => {
                             match s.peer_name() {
                                Some(pn) => {println(format!("Received connection from: [{:s}]", pn.to_str()));},
                                None => ()
                             }
                           },
                None => ()
            }

            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);
            let lines: ~[&str] = request_str.split('\n').collect();
            println(format!("line one: {:s}", lines[0]));
            println(format!("Received request :\n{:s}", request_str));
            unsafe { atomic_add(&mut visitor_count, 1);
                     println!("Visitor count: {:u}", visitor_count);
            }
            let response: ~str =
                ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                 <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

Visitor count: "
                    + unsafe{
                        visitor_count.to_str()
                    } + "

                 \r\n";
            stream.write(response.as_bytes());
            println!("Connection terminates.");
        }
    }
}

fn atomic_add(var: &mut uint, count: uint) -> uint {
    let oldval = var.clone();
    *var = *var + count;
    return oldval;
}
<commit_msg>Return file contents in a directory<commit_after>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.9
//
// Note that this code has serious security risks!  You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#[feature(globs)];
use std::io::*;
use std::io::net::ip::{SocketAddr};
use std::{str};
use std::io::buffered::BufferedReader;

static IP: &'static str  = "127.0.0.1";
static PORT:        int  = 4414;
static mut visitor_count: uint = 0;

fn main() {
    let addr = from_str::<SocketAddr>(format!("{:s}:{:d}", IP, PORT)).unwrap();
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen();

    println(format!("Listening on [{:s}] ...", addr.to_str()));

    for stream in acceptor.incoming() {
        // Spawn a task to handle the connection
        do spawn {
            let mut stream = stream;

            match stream {
                Some(ref mut s) => {
                             match s.peer_name() {
                                Some(pn) => {println(format!("Received connection from: [{:s}]", pn.to_str()));},
                                None => ()
                             }
                           },
                None => ()
            }
            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);
            let lines: ~[&str] = request_str.split('\n').collect();
            let firstline = lines[0];
            let after=firstline.slice_from(4).to_owned();
            let then: ~[&str]=after.split(' ').collect();
            let filename = then[0].slice_from(1);
            println!("filename: {:s}", filename);
            println!("Received request :\n{:s}", request_str);
            unsafe { atomic_add(&mut visitor_count, 1);
                     println!("Visitor count: {:u}", visitor_count);
            }
            let filepath = Path::new(filename);
            match File::open(&filepath) {
                Some (file) => {
                    let mut filereader = ~BufferedReader::new(file);
                    let mut contents : ~str = ~"";
                    println("Reading file ...");
                    for line in filereader.lines() {
                        println!("Found line: {:s}.", line);
                        contents = contents + "
" + line;
                    }
                    let response: ~str =
                        ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                        <doctype !html><title>Hello, Rust!</title>
                        "
                        + contents
                            + unsafe{
                                visitor_count.to_str()
                            } + "

                        \r\n";
                    stream.write(response.as_bytes());
                    println("Connection terminates.");
                }
                None => {
                    let response: ~str =
                        ~"HTTP/1.1 404 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                        <doctype !html><title>Hello, Rust!</title>

                        \r\n";
                    stream.write(response.as_bytes());
                    println!("Mad world.");
                }
            }
        }
    }
}

fn atomic_add(var: &mut uint, count: uint) -> uint {
    let oldval = var.clone();
    *var = *var + count;
    return oldval;
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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 target::TargetOptions;
use std::default::Default;

pub fn opts() -> TargetOptions {
    TargetOptions {
        linker: "cc".to_string(),
        dynamic_linking: true,
        executables: true,
        morestack: false,
        linker_is_gnu: true,
        has_rpath: true,
        position_independent_executables: true,
        archive_format: "".to_string(),

        .. Default::default()
    }
}
<commit_msg>review feedback fixes<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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 target::TargetOptions;
use std::default::Default;

pub fn opts() -> TargetOptions {
    TargetOptions {
        linker: "cc".to_string(),
        dynamic_linking: true,
        executables: true,
        morestack: false,
        linker_is_gnu: true,
        has_rpath: true,
        position_independent_executables: true,

        .. Default::default()
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use super::{LldFlavor, TargetOptions, PanicStrategy, LinkerFlavor};

pub fn options() -> TargetOptions {
    let mut lld_args = Vec::new();
    let mut clang_args = Vec::new();
    let mut arg = |arg: &str| {
        lld_args.push(arg.to_string());
        clang_args.push(format!("-Wl,{}", arg));
    };

    // There have been reports in the wild (rustwasm/wasm-bindgen#119) of
    // using threads causing weird hangs and bugs. Disable it entirely as
    // this isn't yet the bottleneck of compilation at all anyway.
    //
    // FIXME: we should file an upstream issue with LLD about this
    arg("--no-threads");

    // By default LLD only gives us one page of stack (64k) which is a
    // little small. Default to a larger stack closer to other PC platforms
    // (1MB) and users can always inject their own link-args to override this.
    arg("-z");
    arg("stack-size=1048576");

    // By default LLD's memory layout is:
    //
    // 1. First, a blank page
    // 2. Next, all static data
    // 3. Finally, the main stack (which grows down)
    //
    // This has the unfortunate consequence that on stack overflows you
    // corrupt static data and can cause some exceedingly weird bugs. To
    // help detect this a little sooner we instead request that the stack is
    // placed before static data.
    //
    // This means that we'll generate slightly larger binaries as references
    // to static data will take more bytes in the ULEB128 encoding, but
    // stack overflow will be guaranteed to trap as it underflows instead of
    // corrupting static data.
    arg("--stack-first");

    // FIXME we probably shouldn't pass this but instead pass an explicit
    // whitelist of symbols we'll allow to be undefined. We don't currently have
    // a mechanism of knowing, however, which symbols are intended to be
    // imported from the environment and which are intended to be imported from
    // other objects linked elsewhere. This is a coarse approximation but is
    // sure to hide some bugs and frustrate someone at some point, so we should
    // ideally work towards a world where we can explicitly list symbols that
    // are supposed to be imported and have all other symbols generate errors if
    // they remain undefined.
    arg("--allow-undefined");

    // Rust code should never have warnings, and warnings are often
    // indicative of bugs, let's prevent them.
    arg("--fatal-warnings");

    // LLD only implements C++-like demangling, which doesn't match our own
    // mangling scheme. Tell LLD to not demangle anything and leave it up to
    // us to demangle these symbols later. Currently rustc does not perform
    // further demangling, but tools like twiggy and wasm-bindgen are intended
    // to do so.
    arg("--no-demangle");

    // The symbol visibility story is a bit in flux right now with LLD.
    // It's... not entirely clear to me what's going on, but this looks to
    // make everything work when `export_symbols` isn't otherwise called for
    // things like executables.
    //
    // This is really only here to get things working. If it can be removed and
    // basic tests still work, then sounds like it should be removed!
    arg("--export-dynamic");

    let mut pre_link_args = BTreeMap::new();
    pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Wasm), lld_args);
    pre_link_args.insert(LinkerFlavor::Gcc, clang_args);

    TargetOptions {
        // we allow dynamic linking, but only cdylibs. Basically we allow a
        // final library artifact that exports some symbols (a wasm module) but
        // we don't allow intermediate `dylib` crate types
        dynamic_linking: true,
        only_cdylib: true,

        // This means we'll just embed a `start` function in the wasm module
        executables: true,

        // relatively self-explanatory!
        exe_suffix: ".wasm".to_string(),
        dll_prefix: String::new(),
        dll_suffix: ".wasm".to_string(),
        linker_is_gnu: false,

        max_atomic_width: Some(64),

        // Unwinding doesn't work right now, so the whole target unconditionally
        // defaults to panic=abort. Note that this is guaranteed to change in
        // the future once unwinding is implemented. Don't rely on this as we're
        // basically guaranteed to change it once WebAssembly supports
        // exceptions.
        panic_strategy: PanicStrategy::Abort,

        // Wasm doesn't have atomics yet, so tell LLVM that we're in a single
        // threaded model which will legalize atomics to normal operations.
        singlethread: true,

        // no dynamic linking, no need for default visibility!
        default_hidden_visibility: true,

        // we use the LLD shipped with the Rust toolchain by default
        linker: Some("rust-lld".to_owned()),
        lld_flavor: LldFlavor::Wasm,

        // No need for indirection here, simd types can always be passed by
        // value as the whole module either has simd or not, which is different
        // from x86 (for example) where programs can have functions that don't
        // enable simd features.
        simd_types_indirect: false,

        pre_link_args,

        .. Default::default()
    }
}
<commit_msg>Rollup merge of #59712 - alexcrichton:wasm-static-not-pic, r=eddyb<commit_after>use std::collections::BTreeMap;
use super::{LldFlavor, TargetOptions, PanicStrategy, LinkerFlavor};

pub fn options() -> TargetOptions {
    let mut lld_args = Vec::new();
    let mut clang_args = Vec::new();
    let mut arg = |arg: &str| {
        lld_args.push(arg.to_string());
        clang_args.push(format!("-Wl,{}", arg));
    };

    // There have been reports in the wild (rustwasm/wasm-bindgen#119) of
    // using threads causing weird hangs and bugs. Disable it entirely as
    // this isn't yet the bottleneck of compilation at all anyway.
    //
    // FIXME: we should file an upstream issue with LLD about this
    arg("--no-threads");

    // By default LLD only gives us one page of stack (64k) which is a
    // little small. Default to a larger stack closer to other PC platforms
    // (1MB) and users can always inject their own link-args to override this.
    arg("-z");
    arg("stack-size=1048576");

    // By default LLD's memory layout is:
    //
    // 1. First, a blank page
    // 2. Next, all static data
    // 3. Finally, the main stack (which grows down)
    //
    // This has the unfortunate consequence that on stack overflows you
    // corrupt static data and can cause some exceedingly weird bugs. To
    // help detect this a little sooner we instead request that the stack is
    // placed before static data.
    //
    // This means that we'll generate slightly larger binaries as references
    // to static data will take more bytes in the ULEB128 encoding, but
    // stack overflow will be guaranteed to trap as it underflows instead of
    // corrupting static data.
    arg("--stack-first");

    // FIXME we probably shouldn't pass this but instead pass an explicit
    // whitelist of symbols we'll allow to be undefined. We don't currently have
    // a mechanism of knowing, however, which symbols are intended to be
    // imported from the environment and which are intended to be imported from
    // other objects linked elsewhere. This is a coarse approximation but is
    // sure to hide some bugs and frustrate someone at some point, so we should
    // ideally work towards a world where we can explicitly list symbols that
    // are supposed to be imported and have all other symbols generate errors if
    // they remain undefined.
    arg("--allow-undefined");

    // Rust code should never have warnings, and warnings are often
    // indicative of bugs, let's prevent them.
    arg("--fatal-warnings");

    // LLD only implements C++-like demangling, which doesn't match our own
    // mangling scheme. Tell LLD to not demangle anything and leave it up to
    // us to demangle these symbols later. Currently rustc does not perform
    // further demangling, but tools like twiggy and wasm-bindgen are intended
    // to do so.
    arg("--no-demangle");

    // The symbol visibility story is a bit in flux right now with LLD.
    // It's... not entirely clear to me what's going on, but this looks to
    // make everything work when `export_symbols` isn't otherwise called for
    // things like executables.
    //
    // This is really only here to get things working. If it can be removed and
    // basic tests still work, then sounds like it should be removed!
    arg("--export-dynamic");

    let mut pre_link_args = BTreeMap::new();
    pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Wasm), lld_args);
    pre_link_args.insert(LinkerFlavor::Gcc, clang_args);

    TargetOptions {
        // we allow dynamic linking, but only cdylibs. Basically we allow a
        // final library artifact that exports some symbols (a wasm module) but
        // we don't allow intermediate `dylib` crate types
        dynamic_linking: true,
        only_cdylib: true,

        // This means we'll just embed a `start` function in the wasm module
        executables: true,

        // relatively self-explanatory!
        exe_suffix: ".wasm".to_string(),
        dll_prefix: String::new(),
        dll_suffix: ".wasm".to_string(),
        linker_is_gnu: false,

        max_atomic_width: Some(64),

        // Unwinding doesn't work right now, so the whole target unconditionally
        // defaults to panic=abort. Note that this is guaranteed to change in
        // the future once unwinding is implemented. Don't rely on this as we're
        // basically guaranteed to change it once WebAssembly supports
        // exceptions.
        panic_strategy: PanicStrategy::Abort,

        // Wasm doesn't have atomics yet, so tell LLVM that we're in a single
        // threaded model which will legalize atomics to normal operations.
        singlethread: true,

        // no dynamic linking, no need for default visibility!
        default_hidden_visibility: true,

        // we use the LLD shipped with the Rust toolchain by default
        linker: Some("rust-lld".to_owned()),
        lld_flavor: LldFlavor::Wasm,

        // No need for indirection here, simd types can always be passed by
        // value as the whole module either has simd or not, which is different
        // from x86 (for example) where programs can have functions that don't
        // enable simd features.
        simd_types_indirect: false,

        pre_link_args,

        // This has no effect in LLVM 8 or prior, but in LLVM 9 and later when
        // PIC code is implemented this has quite a drastric effect if it stays
        // at the default, `pic`. In an effort to keep wasm binaries as minimal
        // as possible we're defaulting to `static` for now, but the hope is
        // that eventually we can ship a `pic`-compatible standard library which
        // works with `static` as well (or works with some method of generating
        // non-relative calls and such later on).
        relocation_model: "static".to_string(),

        .. Default::default()
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![warn(rust_2018_idioms)]
#![doc(html_root_url = "https://docs.rs/amq-protocol-tcp/6.0.0-rc12/")]

//! # AMQP URI TCP connection handling
//!
//! amq-protocol-tcp is a library aiming at providing tools to help
//! connecting to an AMQP URI

use amq_protocol_uri::{AMQPScheme, AMQPUri};
use std::{
    mem::ManuallyDrop,
    ops::{Deref, DerefMut},
    time::Duration,
};
use tracing::trace;

/// Re-export TcpStream
pub use tcp_stream::{
    HandshakeError, HandshakeResult, Identity, MidHandshakeTlsStream, OwnedIdentity,
    OwnedTLSConfig, TLSConfig, TcpStream,
};

#[cfg(feature = "native-tls")]
pub use tcp_stream::NativeTlsConnector;

#[cfg(feature = "openssl")]
pub use tcp_stream::OpenSslConnector;

#[cfg(feature = "rustls-connector")]
pub use tcp_stream::{RustlsConnector, RustlsConnectorConfig};

/// Trait providing a method to connect to a TcpStream
pub trait AMQPUriTcpExt {
    /// connect to a TcpStream
    fn connect(&self) -> HandshakeResult
    where
        Self: Sized,
    {
        self.connect_with_config(TLSConfig::default())
    }

    /// connect to a TcpStream with the given configuration
    fn connect_with_config(&self, config: TLSConfig<'_, '_, '_>) -> HandshakeResult;
}

impl AMQPUriTcpExt for AMQPUri {
    fn connect_with_config(&self, config: TLSConfig<'_, '_, '_>) -> HandshakeResult {
        let uri = format!("{}:{}", self.authority.host, self.authority.port);
        trace!(uri = %uri, "Connecting");
        let stream = if let Some(timeout) = self.query.connection_timeout {
            TcpStream::connect_timeout(uri, Duration::from_millis(timeout))
        } else {
            TcpStream::connect(uri)
        }?;

        match self.scheme {
            AMQPScheme::AMQP => Ok(stream),
            AMQPScheme::AMQPS => stream.into_tls(&self.authority.host, config),
        }
    }
}

/// Unsafe wrapper "Cloning" the TcpStream but not closing it on drop.
pub struct TcpStreamWrapper(ManuallyDrop<TcpStream>);

impl Deref for TcpStreamWrapper {
    type Target = TcpStream;

    fn deref(&self) -> &Self::Target {
        &*self.0
    }
}

impl DerefMut for TcpStreamWrapper {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut *self.0
    }
}

#[cfg(unix)]
mod sys {
    use crate::{TcpStream, TcpStreamWrapper};
    use std::{
        mem::ManuallyDrop,
        os::unix::io::{AsRawFd, FromRawFd, RawFd},
    };

    impl TcpStreamWrapper {
        /// Clone the TcpStream. Original one needs to last at least for the same lifetime.
        ///
        /// # Safety
        ///
        /// The inner TcpStream won't be closed on drop and the original one needs to live longer
        pub unsafe fn new(socket: &TcpStream) -> Self {
            Self(ManuallyDrop::new(TcpStream::from_raw_fd(
                socket.as_raw_fd(),
            )))
        }
    }

    impl AsRawFd for TcpStreamWrapper {
        fn as_raw_fd(&self) -> RawFd {
            self.0.as_raw_fd()
        }
    }
}

#[cfg(windows)]
mod sys {
    use crate::{TcpStream, TcpStreamWrapper};
    use std::{
        mem::ManuallyDrop,
        os::windows::io::{AsRawSocket, FromRawSocket, RawSocket},
    };

    impl TcpStreamWrapper {
        /// Clone the TcpStream. Original one needs to last at least for the same lifetime.
        pub unsafe fn new(socket: &TcpStream) -> Self {
            Self(ManuallyDrop::new(TcpStream::from_raw_socket(
                socket.as_raw_socket(),
            )))
        }
    }

    impl AsRawSocket for TcpStreamWrapper {
        fn as_raw_socket(&self) -> RawSocket {
            self.0.as_raw_socket()
        }
    }
}
<commit_msg>tcp: tweak log<commit_after>#![deny(missing_docs)]
#![warn(rust_2018_idioms)]
#![doc(html_root_url = "https://docs.rs/amq-protocol-tcp/6.0.0-rc12/")]

//! # AMQP URI TCP connection handling
//!
//! amq-protocol-tcp is a library aiming at providing tools to help
//! connecting to an AMQP URI

use amq_protocol_uri::{AMQPScheme, AMQPUri};
use std::{
    mem::ManuallyDrop,
    ops::{Deref, DerefMut},
    time::Duration,
};
use tracing::trace;

/// Re-export TcpStream
pub use tcp_stream::{
    HandshakeError, HandshakeResult, Identity, MidHandshakeTlsStream, OwnedIdentity,
    OwnedTLSConfig, TLSConfig, TcpStream,
};

#[cfg(feature = "native-tls")]
pub use tcp_stream::NativeTlsConnector;

#[cfg(feature = "openssl")]
pub use tcp_stream::OpenSslConnector;

#[cfg(feature = "rustls-connector")]
pub use tcp_stream::{RustlsConnector, RustlsConnectorConfig};

/// Trait providing a method to connect to a TcpStream
pub trait AMQPUriTcpExt {
    /// connect to a TcpStream
    fn connect(&self) -> HandshakeResult
    where
        Self: Sized,
    {
        self.connect_with_config(TLSConfig::default())
    }

    /// connect to a TcpStream with the given configuration
    fn connect_with_config(&self, config: TLSConfig<'_, '_, '_>) -> HandshakeResult;
}

impl AMQPUriTcpExt for AMQPUri {
    fn connect_with_config(&self, config: TLSConfig<'_, '_, '_>) -> HandshakeResult {
        let uri = format!("{}:{}", self.authority.host, self.authority.port);
        trace!(uri = %uri, "Connecting.");
        let stream = if let Some(timeout) = self.query.connection_timeout {
            TcpStream::connect_timeout(uri, Duration::from_millis(timeout))
        } else {
            TcpStream::connect(uri)
        }?;

        match self.scheme {
            AMQPScheme::AMQP => Ok(stream),
            AMQPScheme::AMQPS => stream.into_tls(&self.authority.host, config),
        }
    }
}

/// Unsafe wrapper "Cloning" the TcpStream but not closing it on drop.
pub struct TcpStreamWrapper(ManuallyDrop<TcpStream>);

impl Deref for TcpStreamWrapper {
    type Target = TcpStream;

    fn deref(&self) -> &Self::Target {
        &*self.0
    }
}

impl DerefMut for TcpStreamWrapper {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut *self.0
    }
}

#[cfg(unix)]
mod sys {
    use crate::{TcpStream, TcpStreamWrapper};
    use std::{
        mem::ManuallyDrop,
        os::unix::io::{AsRawFd, FromRawFd, RawFd},
    };

    impl TcpStreamWrapper {
        /// Clone the TcpStream. Original one needs to last at least for the same lifetime.
        ///
        /// # Safety
        ///
        /// The inner TcpStream won't be closed on drop and the original one needs to live longer
        pub unsafe fn new(socket: &TcpStream) -> Self {
            Self(ManuallyDrop::new(TcpStream::from_raw_fd(
                socket.as_raw_fd(),
            )))
        }
    }

    impl AsRawFd for TcpStreamWrapper {
        fn as_raw_fd(&self) -> RawFd {
            self.0.as_raw_fd()
        }
    }
}

#[cfg(windows)]
mod sys {
    use crate::{TcpStream, TcpStreamWrapper};
    use std::{
        mem::ManuallyDrop,
        os::windows::io::{AsRawSocket, FromRawSocket, RawSocket},
    };

    impl TcpStreamWrapper {
        /// Clone the TcpStream. Original one needs to last at least for the same lifetime.
        pub unsafe fn new(socket: &TcpStream) -> Self {
            Self(ManuallyDrop::new(TcpStream::from_raw_socket(
                socket.as_raw_socket(),
            )))
        }
    }

    impl AsRawSocket for TcpStreamWrapper {
        fn as_raw_socket(&self) -> RawSocket {
            self.0.as_raw_socket()
        }
    }
}
<|endoftext|>


<commit_before>use url::TELEGRAM_URL;

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum RequestUrl {
    Method(&'static str),
}

impl RequestUrl {
    pub fn method(method: &'static str) -> Self {
        RequestUrl::Method(method)
    }

    pub fn url(&self, token: &str) -> String {
        match self {
            &RequestUrl::Method(method) => format!("{}bot{}/{}", TELEGRAM_URL, token, method),
        }
    }
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum Method {
    Get,
    Post,
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum Body {
    Empty,
    Json(Vec<u8>),
    #[doc(hidden)]
    __Nonexhaustive,
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct HttpRequest {
    pub url: RequestUrl,
    pub method: Method,
    pub body: Body,
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct HttpResponse {
    pub body: Option<Vec<u8>>
}
<commit_msg>multipart body type<commit_after>use url::TELEGRAM_URL;

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum RequestUrl {
    Method(&'static str),
}

impl RequestUrl {
    pub fn method(method: &'static str) -> Self {
        RequestUrl::Method(method)
    }

    pub fn url(&self, token: &str) -> String {
        match self {
            &RequestUrl::Method(method) => format!("{}bot{}/{}", TELEGRAM_URL, token, method),
        }
    }
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum Method {
    Get,
    Post,
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum MultipartField {
    Text(String),
    File { filename: String, path: String },
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum Body {
    Empty,
    Json(Vec<u8>),
    Multipart(Vec<(String, MultipartField)>),
    #[doc(hidden)]
    __Nonexhaustive,
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct HttpRequest {
    pub url: RequestUrl,
    pub method: Method,
    pub body: Body,
}

#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub struct HttpResponse {
    pub body: Option<Vec<u8>>,
}
<|endoftext|>


<commit_before><commit_msg>"dotprot" -> "dotprod"<commit_after><|endoftext|>