<commit_before>#![deny(missing_docs)]

use ::errors::*;
use ::backend::{
    MidiInputPort as MidiInputPortImpl,
    MidiInput as MidiInputImpl,
    MidiInputConnection as MidiInputConnectionImpl,
    MidiOutputPort as MidiOutputPortImpl,
    MidiOutput as MidiOutputImpl,
    MidiOutputConnection as MidiOutputConnectionImpl
};
use ::Ignore;

/// An object representing a single input port.
/// How the port is identified internally is backend-dependent.
/// If the backend allows it, port objects remain valid when
/// other ports in the system change (i.e. it is not just an index).
///
/// Use the `ports` method of a `MidiInput` instance to obtain
/// available ports.
pub struct MidiInputPort {
    pub(crate) imp: MidiInputPortImpl
}

/// A collection of input ports.
pub type MidiInputPorts = Vec<MidiInputPort>;

/// An instance of `MidiInput` is required for anything related to MIDI input.
/// Create one with `MidiInput::new`.
pub struct MidiInput {
    //ignore_flags: Ignore
    imp: MidiInputImpl
}

impl MidiInput {
    /// Creates a new `MidiInput` object that is required for any MIDI input functionality.
    pub fn new(client_name: &str) -> Result<Self, InitError> {
        MidiInputImpl::new(client_name).map(|imp| MidiInput { imp: imp })
    }

    /// Set flags to decide what kind of messages should be ignored (i.e., filtered out)
    /// by this `MidiInput`. By default, no messages are ignored.
    pub fn ignore(&mut self, flags: Ignore) {
       self.imp.ignore(flags);
    }

    /// Get a collection of all MIDI input ports that *midir* can connect to.
    /// The resulting vector contains one object per port, which you can use to
    /// query metadata about the port or connect to it in order to receive
    /// MIDI messages.
    pub fn ports(&self) -> MidiInputPorts {
        self.imp.ports_internal()
    }

    /// Get the number of available MIDI input ports that *midir* can connect to.
    pub fn port_count(&self) -> usize {
        self.imp.port_count()
    }

    /// Get the name of a specified MIDI input port.
    ///
    /// An error will be returned when the port is no longer valid
    /// (e.g. the respective device has been disconnected).
    pub fn port_name(&self, port: &MidiInputPort) -> Result<String, PortInfoError> {
        self.imp.port_name(&port.imp)
    }

    /// Connect to a specified MIDI input port in order to receive messages.
    /// For each incoming MIDI message, the provided `callback` function will
    /// be called. The first parameter of the callback function is a timestamp
    /// (in microseconds) designating the time since some unspecified point in
    /// the past (which will not change during the lifetime of a
    /// `MidiInputConnection`). The second parameter contains the actual bytes
    /// of the MIDI message.
    ///
    /// Additional data that should be passed whenever the callback is
    /// invoked can be specified by `data`. Use the empty tuple `()` if
    /// you do not want to pass any additional data.
    ///
    /// The connection will be kept open as long as the returned
    /// `MidiInputConnection` is kept alive.
    ///
    /// The `port_name` is an additional name that will be assigned to the
    /// connection. It is only used by some backends.
    ///
    /// An error will be returned when the port is no longer valid
    /// (e.g. the respective device has been disconnected).
    pub fn connect<F, T: Send>(
        self, port: &MidiInputPort, port_name: &str, callback: F, data: T
    ) -> Result<MidiInputConnection<T>, ConnectError<MidiInput>>
        where F: FnMut(u64, &[u8], &mut T) + Send + 'static {
        match self.imp.connect(&port.imp, port_name, callback, data) {
            Ok(imp) => Ok(MidiInputConnection { imp: imp }),
            Err(imp) => {
                let kind = imp.kind();
                Err(ConnectError::new(kind, MidiInput { imp: imp.into_inner() }))
            }
        }
    }
}

#[cfg(unix)]
impl<T: Send> ::os::unix::VirtualInput<T> for MidiInput {
    fn create_virtual<F>(
        self, port_name: &str, callback: F, data: T
    ) -> Result<MidiInputConnection<T>, ConnectError<Self>>
    where F: FnMut(u64, &[u8], &mut T) + Send + 'static {
        match self.imp.create_virtual(port_name, callback, data) {
            Ok(imp) => Ok(MidiInputConnection { imp: imp }),
            Err(imp) => {
                let kind = imp.kind();
                Err(ConnectError::new(kind, MidiInput { imp: imp.into_inner() }))
            }
        }
    }
}

/// Represents an open connection to a MIDI input port.
pub struct MidiInputConnection<T: 'static> {
    imp: MidiInputConnectionImpl<T>
}

impl<T> MidiInputConnection<T> {
    /// Closes the connection. The returned values allow you to
    /// inspect the additional data passed to the callback (the `data`
    /// parameter of `connect`), or to reuse the `MidiInput` object,
    /// but they can be safely ignored.
    pub fn close(self) -> (MidiInput, T) {
        let (imp, data) = self.imp.close();
        (MidiInput { imp: imp }, data)
    }
}

/// An object representing a single input port.
/// How the port is identified internally is backend-dependent.
/// If the backend allows it, port objects remain valid when
/// other ports in the system change (i.e. it is not just an index).
///
/// Use the `ports` method of a `MidiOutput` instance to obtain
/// available ports.
pub struct MidiOutputPort {
    pub(crate) imp: MidiOutputPortImpl
}

/// A collection of output ports.
pub type MidiOutputPorts = Vec<MidiOutputPort>;

/// An instance of `MidiOutput` is required for anything related to MIDI output.
/// Create one with `MidiOutput::new`.
pub struct MidiOutput {
    imp: MidiOutputImpl
}

impl MidiOutput {
    /// Creates a new `MidiOutput` object that is required for any MIDI output functionality.
    pub fn new(client_name: &str) -> Result<Self, InitError> {
        MidiOutputImpl::new(client_name).map(|imp| MidiOutput { imp: imp })
    }

    /// Get a collection of all MIDI output ports that *midir* can connect to.
    /// The resulting vector contains one object per port, which you can use to
    /// query metadata about the port or connect to it in order to send
    /// MIDI messages.
    pub fn ports(&self) -> MidiOutputPorts {
        self.imp.ports_internal()
    }

    /// Get the number of available MIDI output ports that *midir* can connect to.
    pub fn port_count(&self) -> usize {
        self.imp.port_count()
    }

    /// Get the name of a specified MIDI output port.
    ///
    /// An error will be returned when the port is no longer valid
    /// (e.g. the respective device has been disconnected).
    pub fn port_name(&self, port: &MidiOutputPort) -> Result<String, PortInfoError> {
        self.imp.port_name(&port.imp)
    }

    /// Connect to a specified MIDI output port in order to send messages.
    /// The connection will be kept open as long as the returned
    /// `MidiOutputConnection` is kept alive.
    ///
    /// The `port_name` is an additional name that will be assigned to the
    /// connection. It is only used by some backends.
    ///
    /// An error will be returned when the port is no longer valid
    /// (e.g. the respective device has been disconnected).
    pub fn connect(self, port: &MidiOutputPort, port_name: &str) -> Result<MidiOutputConnection, ConnectError<MidiOutput>> {
        match self.imp.connect(&port.imp, port_name) {
            Ok(imp) => Ok(MidiOutputConnection { imp: imp }),
            Err(imp) => {
                let kind = imp.kind();
                Err(ConnectError::new(kind, MidiOutput { imp: imp.into_inner() }))
            }
        }
    }
}

#[cfg(unix)]
impl ::os::unix::VirtualOutput for MidiOutput {
    fn create_virtual(self, port_name: &str) -> Result<MidiOutputConnection, ConnectError<MidiOutput>> {
        match self.imp.create_virtual(port_name) {
            Ok(imp) => Ok(MidiOutputConnection { imp: imp }),
            Err(imp) => {
                let kind = imp.kind();
                Err(ConnectError::new(kind, MidiOutput { imp: imp.into_inner() }))
            }
        }
    }
}

/// Represents an open connection to a MIDI output port.
pub struct MidiOutputConnection {
   imp: MidiOutputConnectionImpl
}

impl MidiOutputConnection {
    /// Closes the connection. The returned value allows you to
    /// reuse the `MidiOutput` object, but it can be safely ignored.
    pub fn close(self) -> MidiOutput {
        MidiOutput { imp: self.imp.close() }
    }

    /// Send a message to the port that this output connection is connected to.
    /// The message must be a valid MIDI message (see https://www.midi.org/specifications/item/table-1-summary-of-midi-message).
    pub fn send(&mut self, message: &[u8]) -> Result<(), SendError> {
        self.imp.send(message)
    }
}

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

    #[test]
    fn test_trait_impls() {
        // make sure that all the structs implement `Send`
        fn is_send<T: Send>() {}
        is_send::<MidiInput>();
        is_send::<MidiOutput>();
        #[cfg(not(target_arch = "wasm32"))] {
            is_send::<MidiInputPort>();
            is_send::<MidiInputConnection<()>>();
            is_send::<MidiOutputPort>();
            is_send::<MidiOutputConnection>();
        }
    }
}
<commit_msg>Reference send issues for webmidi.<commit_after>#![deny(missing_docs)]

use ::errors::*;
use ::backend::{
    MidiInputPort as MidiInputPortImpl,
    MidiInput as MidiInputImpl,
    MidiInputConnection as MidiInputConnectionImpl,
    MidiOutputPort as MidiOutputPortImpl,
    MidiOutput as MidiOutputImpl,
    MidiOutputConnection as MidiOutputConnectionImpl
};
use ::Ignore;

/// An object representing a single input port.
/// How the port is identified internally is backend-dependent.
/// If the backend allows it, port objects remain valid when
/// other ports in the system change (i.e. it is not just an index).
///
/// Use the `ports` method of a `MidiInput` instance to obtain
/// available ports.
pub struct MidiInputPort {
    pub(crate) imp: MidiInputPortImpl
}

/// A collection of input ports.
pub type MidiInputPorts = Vec<MidiInputPort>;

/// An instance of `MidiInput` is required for anything related to MIDI input.
/// Create one with `MidiInput::new`.
pub struct MidiInput {
    //ignore_flags: Ignore
    imp: MidiInputImpl
}

impl MidiInput {
    /// Creates a new `MidiInput` object that is required for any MIDI input functionality.
    pub fn new(client_name: &str) -> Result<Self, InitError> {
        MidiInputImpl::new(client_name).map(|imp| MidiInput { imp: imp })
    }

    /// Set flags to decide what kind of messages should be ignored (i.e., filtered out)
    /// by this `MidiInput`. By default, no messages are ignored.
    pub fn ignore(&mut self, flags: Ignore) {
       self.imp.ignore(flags);
    }

    /// Get a collection of all MIDI input ports that *midir* can connect to.
    /// The resulting vector contains one object per port, which you can use to
    /// query metadata about the port or connect to it in order to receive
    /// MIDI messages.
    pub fn ports(&self) -> MidiInputPorts {
        self.imp.ports_internal()
    }

    /// Get the number of available MIDI input ports that *midir* can connect to.
    pub fn port_count(&self) -> usize {
        self.imp.port_count()
    }

    /// Get the name of a specified MIDI input port.
    ///
    /// An error will be returned when the port is no longer valid
    /// (e.g. the respective device has been disconnected).
    pub fn port_name(&self, port: &MidiInputPort) -> Result<String, PortInfoError> {
        self.imp.port_name(&port.imp)
    }

    /// Connect to a specified MIDI input port in order to receive messages.
    /// For each incoming MIDI message, the provided `callback` function will
    /// be called. The first parameter of the callback function is a timestamp
    /// (in microseconds) designating the time since some unspecified point in
    /// the past (which will not change during the lifetime of a
    /// `MidiInputConnection`). The second parameter contains the actual bytes
    /// of the MIDI message.
    ///
    /// Additional data that should be passed whenever the callback is
    /// invoked can be specified by `data`. Use the empty tuple `()` if
    /// you do not want to pass any additional data.
    ///
    /// The connection will be kept open as long as the returned
    /// `MidiInputConnection` is kept alive.
    ///
    /// The `port_name` is an additional name that will be assigned to the
    /// connection. It is only used by some backends.
    ///
    /// An error will be returned when the port is no longer valid
    /// (e.g. the respective device has been disconnected).
    pub fn connect<F, T: Send>(
        self, port: &MidiInputPort, port_name: &str, callback: F, data: T
    ) -> Result<MidiInputConnection<T>, ConnectError<MidiInput>>
        where F: FnMut(u64, &[u8], &mut T) + Send + 'static {
        match self.imp.connect(&port.imp, port_name, callback, data) {
            Ok(imp) => Ok(MidiInputConnection { imp: imp }),
            Err(imp) => {
                let kind = imp.kind();
                Err(ConnectError::new(kind, MidiInput { imp: imp.into_inner() }))
            }
        }
    }
}

#[cfg(unix)]
impl<T: Send> ::os::unix::VirtualInput<T> for MidiInput {
    fn create_virtual<F>(
        self, port_name: &str, callback: F, data: T
    ) -> Result<MidiInputConnection<T>, ConnectError<Self>>
    where F: FnMut(u64, &[u8], &mut T) + Send + 'static {
        match self.imp.create_virtual(port_name, callback, data) {
            Ok(imp) => Ok(MidiInputConnection { imp: imp }),
            Err(imp) => {
                let kind = imp.kind();
                Err(ConnectError::new(kind, MidiInput { imp: imp.into_inner() }))
            }
        }
    }
}

/// Represents an open connection to a MIDI input port.
pub struct MidiInputConnection<T: 'static> {
    imp: MidiInputConnectionImpl<T>
}

impl<T> MidiInputConnection<T> {
    /// Closes the connection. The returned values allow you to
    /// inspect the additional data passed to the callback (the `data`
    /// parameter of `connect`), or to reuse the `MidiInput` object,
    /// but they can be safely ignored.
    pub fn close(self) -> (MidiInput, T) {
        let (imp, data) = self.imp.close();
        (MidiInput { imp: imp }, data)
    }
}

/// An object representing a single input port.
/// How the port is identified internally is backend-dependent.
/// If the backend allows it, port objects remain valid when
/// other ports in the system change (i.e. it is not just an index).
///
/// Use the `ports` method of a `MidiOutput` instance to obtain
/// available ports.
pub struct MidiOutputPort {
    pub(crate) imp: MidiOutputPortImpl
}

/// A collection of output ports.
pub type MidiOutputPorts = Vec<MidiOutputPort>;

/// An instance of `MidiOutput` is required for anything related to MIDI output.
/// Create one with `MidiOutput::new`.
pub struct MidiOutput {
    imp: MidiOutputImpl
}

impl MidiOutput {
    /// Creates a new `MidiOutput` object that is required for any MIDI output functionality.
    pub fn new(client_name: &str) -> Result<Self, InitError> {
        MidiOutputImpl::new(client_name).map(|imp| MidiOutput { imp: imp })
    }

    /// Get a collection of all MIDI output ports that *midir* can connect to.
    /// The resulting vector contains one object per port, which you can use to
    /// query metadata about the port or connect to it in order to send
    /// MIDI messages.
    pub fn ports(&self) -> MidiOutputPorts {
        self.imp.ports_internal()
    }

    /// Get the number of available MIDI output ports that *midir* can connect to.
    pub fn port_count(&self) -> usize {
        self.imp.port_count()
    }

    /// Get the name of a specified MIDI output port.
    ///
    /// An error will be returned when the port is no longer valid
    /// (e.g. the respective device has been disconnected).
    pub fn port_name(&self, port: &MidiOutputPort) -> Result<String, PortInfoError> {
        self.imp.port_name(&port.imp)
    }

    /// Connect to a specified MIDI output port in order to send messages.
    /// The connection will be kept open as long as the returned
    /// `MidiOutputConnection` is kept alive.
    ///
    /// The `port_name` is an additional name that will be assigned to the
    /// connection. It is only used by some backends.
    ///
    /// An error will be returned when the port is no longer valid
    /// (e.g. the respective device has been disconnected).
    pub fn connect(self, port: &MidiOutputPort, port_name: &str) -> Result<MidiOutputConnection, ConnectError<MidiOutput>> {
        match self.imp.connect(&port.imp, port_name) {
            Ok(imp) => Ok(MidiOutputConnection { imp: imp }),
            Err(imp) => {
                let kind = imp.kind();
                Err(ConnectError::new(kind, MidiOutput { imp: imp.into_inner() }))
            }
        }
    }
}

#[cfg(unix)]
impl ::os::unix::VirtualOutput for MidiOutput {
    fn create_virtual(self, port_name: &str) -> Result<MidiOutputConnection, ConnectError<MidiOutput>> {
        match self.imp.create_virtual(port_name) {
            Ok(imp) => Ok(MidiOutputConnection { imp: imp }),
            Err(imp) => {
                let kind = imp.kind();
                Err(ConnectError::new(kind, MidiOutput { imp: imp.into_inner() }))
            }
        }
    }
}

/// Represents an open connection to a MIDI output port.
pub struct MidiOutputConnection {
   imp: MidiOutputConnectionImpl
}

impl MidiOutputConnection {
    /// Closes the connection. The returned value allows you to
    /// reuse the `MidiOutput` object, but it can be safely ignored.
    pub fn close(self) -> MidiOutput {
        MidiOutput { imp: self.imp.close() }
    }

    /// Send a message to the port that this output connection is connected to.
    /// The message must be a valid MIDI message (see https://www.midi.org/specifications/item/table-1-summary-of-midi-message).
    pub fn send(&mut self, message: &[u8]) -> Result<(), SendError> {
        self.imp.send(message)
    }
}

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

    #[test]
    fn test_trait_impls() {
        // make sure that all the structs implement `Send`
        fn is_send<T: Send>() {}
        is_send::<MidiInput>();
        is_send::<MidiOutput>();
        #[cfg(not(target_arch = "wasm32"))] {
            // The story around threading and `Send` on WASM is not clear yet
            // Tracking issue:      https://github.com/Boddlnagg/midir/issues/49
            // Prev. discussion:    https://github.com/Boddlnagg/midir/pull/47
            is_send::<MidiInputPort>();
            is_send::<MidiInputConnection<()>>();
            is_send::<MidiOutputPort>();
            is_send::<MidiOutputConnection>();
        }
    }
}
<|endoftext|>


<commit_before>use tile::Tile;
use util::Grid;
use std::ops::{Index};

pub struct Level {
	tiles: Grid<Option<Tile>>,
}

impl Level {
	pub fn new(width: usize, height: usize) -> Level {
		Level{
			tiles: Grid::new_filled_with(Some(Tile::Void) ,width, height),
		}
	}

	pub fn new_filled_with(tile: Option<Tile>, width: usize, height: usize) -> level {
		Level{
			tiles: Grid::new_filled_with(tile, width, height),
		}
	}

	pub fn fill_with(&mut self, tile: Tile) {
		let width = tiles.get_width();
		let height = tiles.get_height();

		for x in 0..width {
			for y in 0..height {
				self.tiles[(x, y)] = tile;
			}
		}
	}

	pub fn get_width(&self) -> usize {
		self.tiles.get_width()
	}

	pub fn get_height(&self) -> usize {
		self.tiles.get_height()
	}

	pub fn get_mut_tile(&mut self, width: usize, height: usize) -> Option<&mut Tile> {
		if x < self.get_width() && y < self.get_height() {
			self.tiles[(x, y)]
		} else {
			None
		}
	}

}

static NONE: Option<Tile> = None;

impl Index<(usize, usize)> for Level {
	type Output= Option<Tile>;

    pub fn index(&self, (x, y): (usize, usize)) -> &Option<Tile>{
		if x < self.get_width() && y < self.get_height() {
			&self.tiles[(x, y)]
		} else {
			&NONE
		}
    }
}
<commit_msg>added apply method<commit_after>use tile::Tile;
use util::Grid;
use std::ops::{Index};

pub struct Level {
	tiles: Grid<Option<Tile>>,
}

impl Level {
	pub fn new(width: usize, height: usize) -> Level {
		Level{
			tiles: Grid::new_filled_with(Some(Tile::Void) ,width, height),
		}
	}

	pub fn new_filled_with(tile: Option<Tile>, width: usize, height: usize) -> level {
		Level{
			tiles: Grid::new_filled_with(tile, width, height),
		}
	}

	pub fn fill_with(&mut self, tile: Tile) {
		let width = tiles.get_width();
		let height = tiles.get_height();

		for x in 0..width {
			for y in 0..height {
				self.tiles[(x, y)] = tile;
			}
		}
	}

	pub fn get_width(&self) -> usize {
		self.tiles.get_width()
	}

	pub fn get_height(&self) -> usize {
		self.tiles.get_height()
	}

	pub fn get_mut_tile(&mut self, width: usize, height: usize) -> Option<&mut Tile> {
		if x < self.get_width() && y < self.get_height() {
			self.tiles[(x, y)]
		} else {
			None
		}
	}

	pub fn apply<F>(&mut self, gen: F) -> &mut Level where F: FnOnce(&mut Level) {
		gen(self);
		self
	}

}

static NONE: Option<Tile> = None;

impl Index<(usize, usize)> for Level {
	type Output= Option<Tile>;

    pub fn index(&self, (x, y): (usize, usize)) -> &Option<Tile>{
		if x < self.get_width() && y < self.get_height() {
			&self.tiles[(x, y)]
		} else {
			&NONE
		}
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::util::CUSTOM_METADATA_DIRECTIVES;
use graphql_ir::Selection;
use graphql_ir::{
    Directive, FragmentDefinition, FragmentSpread, InlineFragment, LinkedField, Program,
    ScalarField, Transformed, Transformer,
};
use interner::StringKey;
use schema::Schema;

/// Transform to skip IR nodes if they are client-defined extensions
/// to the schema
pub fn skip_client_extensions(program: &Program) -> Program {
    let mut transform = SkipClientExtensionsTransform::new(program);
    transform
        .transform_program(program)
        .replace_or_else(|| program.clone())
}

struct SkipClientExtensionsTransform<'s> {
    program: &'s Program,
}

impl<'s> SkipClientExtensionsTransform<'s> {
    fn new(program: &'s Program) -> Self {
        Self { program }
    }
}

impl<'s> SkipClientExtensionsTransform<'s> {
    fn is_client_directive(&self, name: StringKey) -> bool {
        // Return true if:
        // - directive is a custom internal directive used to hold
        //   metadata in the IR
        // - or, directive is a client-defined directive, not present
        //   in the server schema
        CUSTOM_METADATA_DIRECTIVES.is_custom_metadata_directive(name)
            || self.program.schema.is_extension_directive(name)
    }
}

impl<'s> Transformer for SkipClientExtensionsTransform<'s> {
    const NAME: &'static str = "SkipClientExtensionsTransform";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = true;

    fn transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        if self
            .program
            .schema
            .is_extension_type(fragment.type_condition)
        {
            Transformed::Delete
        } else {
            self.default_transform_fragment(fragment)
        }
    }

    fn transform_fragment_spread(&mut self, spread: &FragmentSpread) -> Transformed<Selection> {
        let fragment = self.program.fragment(spread.fragment.item).unwrap();
        if self
            .program
            .schema
            .is_extension_type(fragment.type_condition)
        {
            Transformed::Delete
        } else {
            Transformed::Keep
        }
    }

    fn transform_inline_fragment(&mut self, fragment: &InlineFragment) -> Transformed<Selection> {
        if let Some(type_condition) = fragment.type_condition {
            if self.program.schema.is_extension_type(type_condition) {
                return Transformed::Delete;
            }
        }
        self.default_transform_inline_fragment(fragment)
    }

    fn transform_linked_field(&mut self, field: &LinkedField) -> Transformed<Selection> {
        if self
            .program
            .schema
            .field(field.definition.item)
            .is_extension
        {
            Transformed::Delete
        } else {
            self.default_transform_linked_field(field)
        }
    }

    fn transform_scalar_field(&mut self, field: &ScalarField) -> Transformed<Selection> {
        if self
            .program
            .schema
            .field(field.definition.item)
            .is_extension
        {
            Transformed::Delete
        } else {
            self.default_transform_scalar_field(field)
        }
    }

    fn transform_directive(&mut self, directive: &Directive) -> Transformed<Directive> {
        if self.is_client_directive(directive.name.item) {
            Transformed::Delete
        } else {
            self.default_transform_directive(directive)
        }
    }
}
<commit_msg>Strip metadata directives from fragment spreads<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::util::CUSTOM_METADATA_DIRECTIVES;
use graphql_ir::Selection;
use graphql_ir::{
    Directive, FragmentDefinition, FragmentSpread, InlineFragment, LinkedField, Program,
    ScalarField, Transformed, Transformer,
};
use interner::StringKey;
use schema::Schema;

/// Transform to skip IR nodes if they are client-defined extensions
/// to the schema
pub fn skip_client_extensions(program: &Program) -> Program {
    let mut transform = SkipClientExtensionsTransform::new(program);
    transform
        .transform_program(program)
        .replace_or_else(|| program.clone())
}

struct SkipClientExtensionsTransform<'s> {
    program: &'s Program,
}

impl<'s> SkipClientExtensionsTransform<'s> {
    fn new(program: &'s Program) -> Self {
        Self { program }
    }
}

impl<'s> SkipClientExtensionsTransform<'s> {
    fn is_client_directive(&self, name: StringKey) -> bool {
        // Return true if:
        // - directive is a custom internal directive used to hold
        //   metadata in the IR
        // - or, directive is a client-defined directive, not present
        //   in the server schema
        CUSTOM_METADATA_DIRECTIVES.is_custom_metadata_directive(name)
            || self.program.schema.is_extension_directive(name)
    }
}

impl<'s> Transformer for SkipClientExtensionsTransform<'s> {
    const NAME: &'static str = "SkipClientExtensionsTransform";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = true;

    fn transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        if self
            .program
            .schema
            .is_extension_type(fragment.type_condition)
        {
            Transformed::Delete
        } else {
            self.default_transform_fragment(fragment)
        }
    }

    fn transform_fragment_spread(&mut self, spread: &FragmentSpread) -> Transformed<Selection> {
        let fragment = self.program.fragment(spread.fragment.item).unwrap();
        if self
            .program
            .schema
            .is_extension_type(fragment.type_condition)
        {
            Transformed::Delete
        } else {
            self.default_transform_fragment_spread(spread)
        }
    }

    fn transform_inline_fragment(&mut self, fragment: &InlineFragment) -> Transformed<Selection> {
        if let Some(type_condition) = fragment.type_condition {
            if self.program.schema.is_extension_type(type_condition) {
                return Transformed::Delete;
            }
        }
        self.default_transform_inline_fragment(fragment)
    }

    fn transform_linked_field(&mut self, field: &LinkedField) -> Transformed<Selection> {
        if self
            .program
            .schema
            .field(field.definition.item)
            .is_extension
        {
            Transformed::Delete
        } else {
            self.default_transform_linked_field(field)
        }
    }

    fn transform_scalar_field(&mut self, field: &ScalarField) -> Transformed<Selection> {
        if self
            .program
            .schema
            .field(field.definition.item)
            .is_extension
        {
            Transformed::Delete
        } else {
            self.default_transform_scalar_field(field)
        }
    }

    fn transform_directive(&mut self, directive: &Directive) -> Transformed<Directive> {
        if self.is_client_directive(directive.name.item) {
            Transformed::Delete
        } else {
            self.default_transform_directive(directive)
        }
    }
}
<|endoftext|>


<commit_before>#![cfg(feature = "serialization")]
extern crate serde_state as serde;

use std::{fs::File, io::Read};

use crate::serde::ser::SerializeState;

use gluon::{
    new_vm, new_vm_async,
    vm::{
        api::{Hole, OpaqueValue, IO},
        serialization::{DeSeed, SeSeed},
        thread::{RootedThread, RootedValue, Thread},
        Variants,
    },
    ThreadExt,
};

fn serialize_value(value: Variants) {
    let mut buffer = Vec::new();
    {
        let mut ser = serde_json::Serializer::pretty(&mut buffer);
        let ser_state = SeSeed::new();
        value.serialize_state(&mut ser, &ser_state).unwrap();
    }
    String::from_utf8(buffer).unwrap();
}

fn roundtrip(
    thread: &RootedThread,
    value: &OpaqueValue<&Thread, Hole>,
) -> RootedValue<RootedThread> {
    use std::str::from_utf8;

    let value = value.get_variant();

    let mut buffer = Vec::new();
    {
        let mut ser = serde_json::Serializer::pretty(&mut buffer);
        let ser_state = SeSeed::new();
        value.serialize_state(&mut ser, &ser_state).unwrap();
    }
    let buffer = from_utf8(&buffer).unwrap();

    let mut de = serde_json::Deserializer::from_str(buffer);

    let deserialize_value = DeSeed::new(thread, &mut thread.current_context())
        .deserialize(&mut de)
        .unwrap_or_else(|err| panic!("{}\n{}", err, buffer));

    // We can't compare functions for equality so serialize again and check that for equality with
    // the first serialization
    let mut buffer2 = Vec::new();
    {
        let mut ser = serde_json::Serializer::pretty(&mut buffer2);
        let ser_state = SeSeed::new();
        value.serialize_state(&mut ser, &ser_state).unwrap();
    }
    eprintln!("{}", buffer);
    assert_eq!(buffer, from_utf8(&buffer2).unwrap());

    deserialize_value
}

#[test]
fn roundtrip_module() {
    let thread = new_vm();
    let (value, _) = thread
        .run_expr::<OpaqueValue<&Thread, Hole>>("test", r#" { x = 1, y = "test" } "#)
        .unwrap();
    let deserialize_value = roundtrip(&thread, &value);
    assert_eq!(deserialize_value, value.into_inner());
}

#[test]
fn roundtrip_recursive_closure() {
    let thread = new_vm();
    let expr = r#"
        rec
        let f x = g x
        let g x = f x
        { f, g }
        "#;
    let (value, _) = thread
        .run_expr::<OpaqueValue<&Thread, Hole>>("test", expr)
        .unwrap();
    roundtrip(&thread, &value);
}

#[test]
fn roundtrip_std_prelude() {
    let thread = new_vm();
    let expr = r#" import! std.prelude "#;
    let (value, _) = thread
        .run_expr::<OpaqueValue<&Thread, Hole>>("test", expr)
        .unwrap();
    roundtrip(&thread, &value);
}

#[test]
fn roundtrip_std_libs() {
    use std::fmt::Write;

    let _ = env_logger::try_init();

    let thread = new_vm();
    let mut expr = "{\n".to_string();
    for entry in walkdir::WalkDir::new("std") {
        let entry = entry.unwrap();
        let path = entry.path();
        // Can't check the extension since vim swap files ".glu.swp" will report ".glu" as the
        // extension
        let path_str = path.to_str().unwrap();
        if path.to_str().unwrap().ends_with(".glu") &&
            path_str.starts_with("std/regex") &&
            path_str.starts_with("std/repl") &&
            path_str.starts_with("std/stream") &&
            // floats cannot be roundtripped with serde json
            // https://github.com/serde-rs/json/issues/128
            path_str.starts_with("std/float")
        {
            let module = gluon_base::filename_to_module(path_str);
            write!(
                expr,
                "    {} = import! {:?},\n",
                module.replace(".", "_"),
                module
            )
            .unwrap();
        }
    }
    expr.push_str("}\n");
    let (value, _) = thread
        .run_expr::<OpaqueValue<&Thread, Hole>>("test", &expr)
        .unwrap_or_else(|err| panic!("{}", err));
    roundtrip(&thread, &value);
}

#[tokio::test]
async fn precompile() {
    use gluon::compiler_pipeline::*;

    let thread = new_vm_async().await;
    let mut text = String::new();
    File::open("std/map.glu")
        .expect("Unable to open map.glu")
        .read_to_string(&mut text)
        .unwrap();

    let mut buffer = Vec::new();
    {
        let mut serializer = serde_json::Serializer::new(&mut buffer);
        thread
            .compile_to_bytecode("test", &text, &mut serializer)
            .await
            .unwrap()
    }
    let precompiled_result = {
        let mut deserializer = serde_json::Deserializer::from_slice(&buffer);
        Precompiled(&mut deserializer)
            .run_expr(
                &mut thread.module_compiler(&mut thread.get_database()),
                &*thread,
                "test",
                "",
                (),
            )
            .await
            .unwrap()
    };
    let thread2 = new_vm_async().await;
    assert_eq!(
        serialize_value(
            text.run_expr(
                &mut thread.module_compiler(&mut thread2.get_database()),
                &*thread2,
                "test",
                &text,
                None
            )
            .await
            .unwrap()
            .value
            .get_variant()
        ),
        serialize_value(precompiled_result.value.get_variant())
    );
}

#[test]
fn roundtrip_reference() {
    let thread = new_vm();
    let expr = r#" import! std.reference "#;
    let (value, _) = thread
        .run_expr::<OpaqueValue<&Thread, Hole>>("test", &expr)
        .unwrap_or_else(|err| panic!("{}", err));
    roundtrip(&thread, &value);
}

#[test]
fn roundtrip_lazy() {
    let thread = new_vm();
    let expr = r#" import! std.lazy "#;
    let (value, _) = thread
        .run_expr::<OpaqueValue<&Thread, Hole>>("test", &expr)
        .unwrap_or_else(|err| panic!("{}", err));
    roundtrip(&thread, &value);
}

#[test]
fn roundtrip_std_thread() {
    let thread = new_vm();
    let expr = r#" import! std.thread "#;
    let (value, _) = thread
        .run_expr::<OpaqueValue<&Thread, Hole>>("test", &expr)
        .unwrap_or_else(|err| panic!("{}", err));
    roundtrip(&thread, &value);
}

#[test]
#[ignore] // Unimplemented so far
fn roundtrip_thread() {
    let thread = new_vm();
    thread.get_database_mut().run_io(true);
    let expr = r#" let t = import! std.thread in t.new_thread ()"#;
    let (value, _) = thread
        .run_expr::<IO<OpaqueValue<&Thread, Hole>>>("test", &expr)
        .unwrap_or_else(|err| panic!("{}", err));
    roundtrip(&thread, &Into::<Result<_, _>>::into(value).unwrap());
}
<commit_msg>test: issue_805<commit_after>#![cfg(feature = "serialization")]
extern crate serde_state as serde;

use std::{fs::File, io::Read};

use crate::serde::ser::SerializeState;

use gluon::{
    new_vm, new_vm_async,
    vm::{
        api::{Hole, OpaqueValue, IO},
        serialization::{DeSeed, SeSeed},
        thread::{RootedThread, RootedValue, Thread},
        Variants,
    },
    ThreadExt,
};

fn serialize_value(value: Variants) {
    let mut buffer = Vec::new();
    {
        let mut ser = serde_json::Serializer::pretty(&mut buffer);
        let ser_state = SeSeed::new();
        value.serialize_state(&mut ser, &ser_state).unwrap();
    }
    String::from_utf8(buffer).unwrap();
}

fn roundtrip(
    thread: &RootedThread,
    value: &OpaqueValue<&Thread, Hole>,
) -> RootedValue<RootedThread> {
    use std::str::from_utf8;

    let value = value.get_variant();

    let mut buffer = Vec::new();
    {
        let mut ser = serde_json::Serializer::pretty(&mut buffer);
        let ser_state = SeSeed::new();
        value.serialize_state(&mut ser, &ser_state).unwrap();
    }
    let buffer = from_utf8(&buffer).unwrap();

    let mut de = serde_json::Deserializer::from_str(buffer);

    let deserialize_value = DeSeed::new(thread, &mut thread.current_context())
        .deserialize(&mut de)
        .unwrap_or_else(|err| panic!("{}\n{}", err, buffer));

    // We can't compare functions for equality so serialize again and check that for equality with
    // the first serialization
    let mut buffer2 = Vec::new();
    {
        let mut ser = serde_json::Serializer::pretty(&mut buffer2);
        let ser_state = SeSeed::new();
        value.serialize_state(&mut ser, &ser_state).unwrap();
    }
    eprintln!("{}", buffer);
    assert_eq!(buffer, from_utf8(&buffer2).unwrap());

    deserialize_value
}

#[test]
fn roundtrip_module() {
    let thread = new_vm();
    let (value, _) = thread
        .run_expr::<OpaqueValue<&Thread, Hole>>("test", r#" { x = 1, y = "test" } "#)
        .unwrap();
    let deserialize_value = roundtrip(&thread, &value);
    assert_eq!(deserialize_value, value.into_inner());
}

#[test]
fn roundtrip_recursive_closure() {
    let thread = new_vm();
    let expr = r#"
        rec
        let f x = g x
        let g x = f x
        { f, g }
        "#;
    let (value, _) = thread
        .run_expr::<OpaqueValue<&Thread, Hole>>("test", expr)
        .unwrap();
    roundtrip(&thread, &value);
}

#[test]
fn roundtrip_std_prelude() {
    let thread = new_vm();
    let expr = r#" import! std.prelude "#;
    let (value, _) = thread
        .run_expr::<OpaqueValue<&Thread, Hole>>("test", expr)
        .unwrap();
    roundtrip(&thread, &value);
}

#[test]
fn roundtrip_std_libs() {
    use std::fmt::Write;

    let _ = env_logger::try_init();

    let thread = new_vm();
    let mut expr = "{\n".to_string();
    for entry in walkdir::WalkDir::new("std") {
        let entry = entry.unwrap();
        let path = entry.path();
        // Can't check the extension since vim swap files ".glu.swp" will report ".glu" as the
        // extension
        let path_str = path.to_str().unwrap();
        if path.to_str().unwrap().ends_with(".glu") &&
            path_str.starts_with("std/regex") &&
            path_str.starts_with("std/repl") &&
            path_str.starts_with("std/stream") &&
            // floats cannot be roundtripped with serde json
            // https://github.com/serde-rs/json/issues/128
            path_str.starts_with("std/float")
        {
            let module = gluon_base::filename_to_module(path_str);
            write!(
                expr,
                "    {} = import! {:?},\n",
                module.replace(".", "_"),
                module
            )
            .unwrap();
        }
    }
    expr.push_str("}\n");
    let (value, _) = thread
        .run_expr::<OpaqueValue<&Thread, Hole>>("test", &expr)
        .unwrap_or_else(|err| panic!("{}", err));
    roundtrip(&thread, &value);
}

#[tokio::test]
async fn precompile() {
    use gluon::compiler_pipeline::*;

    let thread = new_vm_async().await;
    let mut text = String::new();
    File::open("std/map.glu")
        .expect("Unable to open map.glu")
        .read_to_string(&mut text)
        .unwrap();

    let mut buffer = Vec::new();
    {
        let mut serializer = serde_json::Serializer::new(&mut buffer);
        thread
            .compile_to_bytecode("test", &text, &mut serializer)
            .await
            .unwrap()
    }
    let precompiled_result = {
        let mut deserializer = serde_json::Deserializer::from_slice(&buffer);
        Precompiled(&mut deserializer)
            .run_expr(
                &mut thread.module_compiler(&mut thread.get_database()),
                &*thread,
                "test",
                "",
                (),
            )
            .await
            .unwrap()
    };
    let thread2 = new_vm_async().await;
    assert_eq!(
        serialize_value(
            text.run_expr(
                &mut thread.module_compiler(&mut thread2.get_database()),
                &*thread2,
                "test",
                &text,
                None
            )
            .await
            .unwrap()
            .value
            .get_variant()
        ),
        serialize_value(precompiled_result.value.get_variant())
    );
}

#[test]
fn roundtrip_reference() {
    let thread = new_vm();
    let expr = r#" import! std.reference "#;
    let (value, _) = thread
        .run_expr::<OpaqueValue<&Thread, Hole>>("test", &expr)
        .unwrap_or_else(|err| panic!("{}", err));
    roundtrip(&thread, &value);
}

#[test]
fn roundtrip_lazy() {
    let thread = new_vm();
    let expr = r#" import! std.lazy "#;
    let (value, _) = thread
        .run_expr::<OpaqueValue<&Thread, Hole>>("test", &expr)
        .unwrap_or_else(|err| panic!("{}", err));
    roundtrip(&thread, &value);
}

#[test]
fn roundtrip_std_thread() {
    let thread = new_vm();
    let expr = r#" import! std.thread "#;
    let (value, _) = thread
        .run_expr::<OpaqueValue<&Thread, Hole>>("test", &expr)
        .unwrap_or_else(|err| panic!("{}", err));
    roundtrip(&thread, &value);
}

#[test]
#[ignore] // Unimplemented so far
fn roundtrip_thread() {
    let thread = new_vm();
    thread.get_database_mut().run_io(true);
    let expr = r#" let t = import! std.thread in t.new_thread ()"#;
    let (value, _) = thread
        .run_expr::<IO<OpaqueValue<&Thread, Hole>>>("test", &expr)
        .unwrap_or_else(|err| panic!("{}", err));
    roundtrip(&thread, &Into::<Result<_, _>>::into(value).unwrap());
}

#[test]
fn issue_805_no_deadlock_in_deserialize() {
    fn serialize_value(value: gluon::vm::Variants) -> Box<[u8]> {
        let mut buffer = Vec::new();
        {
            let mut ser = serde_json::Serializer::new(&mut buffer);
            let ser_state = gluon::vm::serialization::SeSeed::new();
            value.serialize_state(&mut ser, &ser_state).unwrap();
        }
        buffer.into_boxed_slice()
    }

    fn deserialize_value(
        thread: &gluon::RootedThread,
        serialized: &[u8],
    ) -> Result<gluon::vm::thread::RootedValue<gluon::vm::thread::RootedThread>, serde_json::Error>
    {
        let mut de = serde_json::Deserializer::from_slice(&serialized);
        gluon::vm::serialization::DeSeed::new(thread, &mut thread.current_context())
            .deserialize(&mut de)
    }

    let vm = gluon::new_vm();
    let script = r#"
        let concat a b = a ++ b
        concat"#;
    vm.load_script("test", script).unwrap();

    let (program, _) = vm
        .run_expr::<gluon::vm::api::OpaqueValue<&gluon::Thread, gluon::vm::api::Hole>>(
            "program",
            "import! test",
        )
        .unwrap_or_else(|e| panic!("fail to parse program: {}", e));
    let variant = program.get_variant();
    let serialized_client = serialize_value(variant);

    let vm2 = gluon::new_vm();
    assert!(deserialize_value(&vm2, &serialized_client)
        .unwrap_err()
        .to_string()
        .contains("is not defined"));
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::mem;

use llvm_sys::{core, LLVMIntPredicate, LLVMRealPredicate};
use llvm_sys::prelude::{
  LLVMBuilderRef,
  LLVMValueRef
};
use libc::{c_char, c_uint};

use types::Ty;
use block::BasicBlock;
use value::{Function, Value, ValueRef, Predicate, PhiNode};

static NULL_NAME:[c_char; 1] = [0];

pub struct Builder(pub LLVMBuilderRef);
impl_dispose!(Builder, core::LLVMDisposeBuilder);

macro_rules! unary_op (
  ($name:ident, $func:ident) => (
    pub fn $name(&self, value: &Value) -> Value {
      Value(unsafe {
        core::$func(self.0, value.into(), NULL_NAME.as_ptr() as *const c_char)
      })
    }
  );
);

impl Builder {

  pub fn get_insert_block(&self) -> BasicBlock
  {
    BasicBlock(unsafe { core::LLVMGetInsertBlock(self.0)})
  }

  /// Position the builder at `instr` within `block`.
  pub fn position_at(&self, block: &BasicBlock, instr: &Value)
  {
    unsafe { core::LLVMPositionBuilder(self.0, block.0, instr.0) }
  }

  /// Position the builder at the end of `block`.
  pub fn position_at_end(&self, block: &BasicBlock)
  {
    unsafe { core::LLVMPositionBuilderAtEnd(self.0, block.0) }
  }

  /// Build an instruction that returns from the function with void.
  pub fn create_ret_void(&self) -> Value
  {
    Value(unsafe {core::LLVMBuildRetVoid(self.0)})
  }

  /// Build an instruction that returns from the function with `value`.
  pub fn create_ret(&self, value: &Value) -> Value
  {
    Value(unsafe { core::LLVMBuildRet(self.0, value.0)})
  }

  /// Build an instruction that allocates an array with the element type `elem` and
  /// the size `size`.
  ///
  /// The size of this array will be the size of `elem` times `size`.
  pub fn build_array_alloca(&self, elem: &Ty, size: &Value) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildArrayAlloca(self.0,
    														 elem.0,
    														 size.0,
    														 NULL_NAME.as_ptr() as *const c_char)
    })
  }

  /// Build an instruction that allocates a pointer to fit the size of `ty` then returns this
  /// pointer.
  ///
  /// Make sure to call `build_free` with the pointer value when you're done with it, or you're
  /// gonna have a bad time.
  pub fn create_alloca(&self, ty: &Ty) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildAlloca(self.0,
    												ty.0,
    												NULL_NAME.as_ptr() as *const c_char)
    })
  }

  /// Build an instruction that frees the `val`, which _MUST_ be a pointer that was returned
  /// from `build_alloca`.
  pub fn create_free(&self, val: &Value) -> Value
  {
    Value(unsafe { core::LLVMBuildFree(self.0, val.0) })
  }

  /// Build an instruction that store the value `val` in the pointer `ptr`.
  pub fn create_store(&self, val: &Value, ptr: &Value) -> Value
  {
    Value(unsafe { core::LLVMBuildStore(self.0, val.0, ptr.0) })
  }

  /// Build an instruction that branches to the block `dest`.
  pub fn create_br(&self, dest: &BasicBlock) -> Value
  {
    Value(unsafe { core::LLVMBuildBr(self.0, dest.0)})
  }

  /// Build an instruction that branches to `if_block` if `cond` evaluates to true, and
  /// `else_block` otherwise.
  pub fn create_cond_br(&self, cond: &Value,
  	                    if_block: &BasicBlock, else_block: &BasicBlock) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildCondBr(self.0,
    		                    cond.0,
    		                    if_block.0,
    		                    mem::transmute(else_block.0))
    })
  }

  /// Build an instruction that calls the function `func` with the arguments `args`.
  ///
  /// This will return the return value of the function.
  fn create_call_internal(&self, func: &Function, args: &[&Value], tail_call: bool) -> Value
  {
    let ref_array = to_llvmref_array!(args, LLVMValueRef);

    Value(unsafe {
        let call = core::LLVMBuildCall(self.0,
        	                             func.0,
                                       ref_array.as_ptr() as *mut LLVMValueRef,
        	                             args.len() as c_uint,
        	                             NULL_NAME.as_ptr());
        core::LLVMSetTailCall(call, if tail_call {1} else {0});
        call.into()
    })
  }

  /// Build an instruction that calls the function `func` with the arguments `args`.
  ///
  /// This will return the return value of the function.
  pub fn create_call(&self, func: &Function, args: &[&Value]) -> Value
  {
    self.create_call_internal(func, args, false)
  }

  /// Build an instruction that calls the function `func` with the arguments `args`.
  ///
  /// This will return the return value of the function.
  pub fn create_tail_call(&self, func: &Function, args: &[&Value]) -> Value
  {
    self.create_call_internal(func, args, true)
  }

  /// Build an instruction that yields to `true_val` if `cond` is equal to `1`, and `false_val`
  /// otherwise.
  pub fn create_select(&self, cond: &Value, true_val: &Value, false_val: &Value) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildSelect(self.0,
    		                    cond.0,
    		                    true_val.0,
    		                    false_val.0,
    		                    NULL_NAME.as_ptr()) })
  }

  /// Build an instruction that casts a value into a certain type.
  pub fn create_bit_cast(&self, value: &Value, dest: &Ty) -> Value
  {
    Value(unsafe { core::LLVMBuildBitCast(
    		self.0,
    		value.0,
    		dest.0,
    		NULL_NAME.as_ptr())
    })
  }

  /// Build an instruction that inserts a value into an aggregate data value.
  pub fn create_insert_value(&self, agg: &Value, elem: &Value, index: usize) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildInsertValue(self.0,
    		                         agg.0,
    		                         elem.0,
    		                         index as c_uint,
    		                         NULL_NAME.as_ptr())
    })
  }

  /// Build an instruction that extracts a value from an aggregate type.
	pub fn create_extract_value(&self, agg: &Value, index: usize) -> Value {
    Value(unsafe {
    	core::LLVMBuildExtractValue(self.0,
    		                          agg.0,
    		                          index as c_uint,
    		                          NULL_NAME.as_ptr())
   	})
  }

  unary_op!{create_load, LLVMBuildLoad}

  /// Build an instruction to compare two values with the predicate given.
  pub fn create_cmp(&self, l: &Value, r: &Value, pred: Predicate) -> Value
  {
    self.create_cmp_internal(l, r, pred, true)
  }

  /// Build an instruction to compare two values with the predicate given.
  pub fn create_ucmp(&self, l: &Value, r: &Value, pred: Predicate) -> Value
  {
    self.create_cmp_internal(l, r, pred, false)
  }

  fn create_cmp_internal(&self, l: &Value, r: &Value,
  											 pred: Predicate, signed: bool) -> Value {
  	let (lhs_ty, rhs_ty) = (l.ty(), r.ty());
    assert_eq!(lhs_ty, rhs_ty);

    if lhs_ty.is_integer() {
	    let p = match (pred, signed) {
	    	(Predicate::Eq,    _)   => LLVMIntPredicate::LLVMIntEQ,
	    	(Predicate::NotEq, _)   => LLVMIntPredicate::LLVMIntNE,
	    	(Predicate::Lth, true)  => LLVMIntPredicate::LLVMIntSLT,
	    	(Predicate::Lth, false) => LLVMIntPredicate::LLVMIntULT,
	    	(Predicate::Leq, true)  => LLVMIntPredicate::LLVMIntSLE,
	    	(Predicate::Leq, false) => LLVMIntPredicate::LLVMIntULE,
	    	(Predicate::Gth, true)  => LLVMIntPredicate::LLVMIntSGT,
	    	(Predicate::Gth, false) => LLVMIntPredicate::LLVMIntUGT,
	    	(Predicate::Geq, true)  => LLVMIntPredicate::LLVMIntSGE,
	    	(Predicate::Geq, false) => LLVMIntPredicate::LLVMIntUGE,
	    };

	    Value(unsafe {
		    core::LLVMBuildICmp(self.0,
	    		                  p,
	     		                  l.0, r.0,
	     		                  NULL_NAME.as_ptr())
	    })

    } else if lhs_ty.is_float() {
    	let p = match pred {
        Predicate::Eq    => LLVMRealPredicate::LLVMRealOEQ,
        Predicate::NotEq => LLVMRealPredicate::LLVMRealONE,
        Predicate::Gth   => LLVMRealPredicate::LLVMRealOGT,
        Predicate::Geq   => LLVMRealPredicate::LLVMRealOGE,
        Predicate::Lth   => LLVMRealPredicate::LLVMRealOLT,
        Predicate::Leq   => LLVMRealPredicate::LLVMRealOLE
      };

   	  Value(unsafe {
      	core::LLVMBuildFCmp(self.0,
      		                 p, l.0, r.0,
      		                 NULL_NAME.as_ptr())
      })

    } else {
      panic!("expected numbers, got {:?}", lhs_ty)
    }
  }

  /// Build an instruction that computes the address of a subelement of an aggregate data
  /// structure.
  ///
  /// Basically type-safe pointer arithmetic.
  pub fn create_gep(&self, pointer: &Value, indices: &[&Value]) -> Value
  {
    let ref_array = to_llvmref_array!(indices, LLVMValueRef);

    Value(unsafe {
    	core::LLVMBuildInBoundsGEP(self.0,
    	                           pointer.0,
    	                           ref_array.as_ptr() as *mut LLVMValueRef,
    	                           indices.len() as c_uint,
    	                           NULL_NAME.as_ptr())
    })
  }

  /// Build an instruction to select a value depending on the predecessor of the current block.
  pub fn create_phi(&self, ty: &Ty, name: &str) -> PhiNode
  {
	  PhiNode(unsafe {
	  	core::LLVMBuildPhi(self.0, ty.0, ::util::chars::from_str(name))
  	})
  }

  /// Build an instruction that runs whichever block matches the value, or `default` if none of
  /// them matched it.
  pub fn create_switch(&self,
  	                   value: &Value,
  	                   default: &BasicBlock,
  	                   cases: &[(&Value, &BasicBlock)]) -> Value {
    Value(unsafe {
      let switch = core::LLVMBuildSwitch(self.0,
      	                                 value.0,
      	                                 default.0,
        	                                 cases.len() as c_uint);
      for case in cases {
        core::LLVMAddCase(switch, (case.0).0, (case.1).0);
      }

      switch
    })
  }
}

#[cfg(test)]
mod tests {
	use super::*;
  use super::super::*;
  use types::LLVMTy;
  use value::{Predicate, ToValue};

	#[test]
	pub fn test_cond_br()
	{
		let jit = JitCompiler::new("test1").ok().unwrap();
    let ctx = jit.context();
    let module = jit.module();

    let func_ty = jit.create_func_ty(&u64::llvm_ty(ctx), &[&u64::llvm_ty(ctx)]);
    let func = jit.add_func("fib", &func_ty);
    let value = func.arg(0);

    let entry = func.append("entry");
    let then_bb = func.append("then_block");
    let else_bb = func.append("else_block");
    let merge_bb = func.append("merge_block");

    let builder = jit.builder();

    builder.position_at_end(&entry);
    let local = builder.create_alloca(&u64::llvm_ty(ctx));
    let cond = builder.create_cmp(&value.into(), &5u64.to_value(ctx), Predicate::Lth);
    builder.create_cond_br(&cond, &then_bb, &else_bb);

    builder.position_at_end(&then_bb);
    builder.create_store(&8u64.to_value(ctx), &local);
    builder.create_br(&merge_bb);

    builder.position_at_end(&else_bb);
    builder.create_store(&16u64.to_value(ctx), &local);
    builder.create_br(&merge_bb);

    builder.position_at_end(&merge_bb);
    let ret_val = builder.create_load(&local);
    builder.create_ret(&ret_val);

    jit.verify().unwrap();

    /*
    let ee = JitEngine::new(&module, JitOptions {opt_level: 0}).unwrap();
    ee.with_function(func, |fib: extern fn(u64) -> u64| {
      for i in 0..10 {
        if i < 5 {
          assert_eq!(8, fib(i));
        } else {
          assert_eq!(16, fib(i));
        }
      }
    });*/
	}
}<commit_msg>Moved create_switch.<commit_after>#![allow(dead_code)]

use std::mem;

use llvm_sys::{core, LLVMIntPredicate, LLVMRealPredicate};
use llvm_sys::prelude::{
  LLVMBuilderRef,
  LLVMValueRef
};
use libc::{c_char, c_uint};

use types::Ty;
use block::BasicBlock;
use value::{Function, Value, ValueRef, Predicate, PhiNode};

static NULL_NAME:[c_char; 1] = [0];

pub struct Builder(pub LLVMBuilderRef);
impl_dispose!(Builder, core::LLVMDisposeBuilder);

macro_rules! unary_op (
  ($name:ident, $func:ident) => (
    pub fn $name(&self, value: &Value) -> Value {
      Value(unsafe {
        core::$func(self.0, value.into(), NULL_NAME.as_ptr() as *const c_char)
      })
    }
  );
);

impl Builder {

  pub fn get_insert_block(&self) -> BasicBlock
  {
    BasicBlock(unsafe { core::LLVMGetInsertBlock(self.0)})
  }

  /// Position the builder at `instr` within `block`.
  pub fn position_at(&self, block: &BasicBlock, instr: &Value)
  {
    unsafe { core::LLVMPositionBuilder(self.0, block.0, instr.0) }
  }

  /// Position the builder at the end of `block`.
  pub fn position_at_end(&self, block: &BasicBlock)
  {
    unsafe { core::LLVMPositionBuilderAtEnd(self.0, block.0) }
  }

  /// Build an instruction that returns from the function with void.
  pub fn create_ret_void(&self) -> Value
  {
    Value(unsafe {core::LLVMBuildRetVoid(self.0)})
  }

  /// Build an instruction that returns from the function with `value`.
  pub fn create_ret(&self, value: &Value) -> Value
  {
    Value(unsafe { core::LLVMBuildRet(self.0, value.0)})
  }

  /// Build an instruction that allocates an array with the element type `elem` and
  /// the size `size`.
  ///
  /// The size of this array will be the size of `elem` times `size`.
  pub fn build_array_alloca(&self, elem: &Ty, size: &Value) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildArrayAlloca(self.0,
    														 elem.0,
    														 size.0,
    														 NULL_NAME.as_ptr() as *const c_char)
    })
  }

  /// Build an instruction that allocates a pointer to fit the size of `ty` then returns this
  /// pointer.
  ///
  /// Make sure to call `build_free` with the pointer value when you're done with it, or you're
  /// gonna have a bad time.
  pub fn create_alloca(&self, ty: &Ty) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildAlloca(self.0,
    												ty.0,
    												NULL_NAME.as_ptr() as *const c_char)
    })
  }

  /// Build an instruction that frees the `val`, which _MUST_ be a pointer that was returned
  /// from `build_alloca`.
  pub fn create_free(&self, val: &Value) -> Value
  {
    Value(unsafe { core::LLVMBuildFree(self.0, val.0) })
  }

  /// Build an instruction that store the value `val` in the pointer `ptr`.
  pub fn create_store(&self, val: &Value, ptr: &Value) -> Value
  {
    Value(unsafe { core::LLVMBuildStore(self.0, val.0, ptr.0) })
  }

  /// Build an instruction that branches to the block `dest`.
  pub fn create_br(&self, dest: &BasicBlock) -> Value
  {
    Value(unsafe { core::LLVMBuildBr(self.0, dest.0)})
  }

  /// Build an instruction that branches to `if_block` if `cond` evaluates to true, and
  /// `else_block` otherwise.
  pub fn create_cond_br(&self, cond: &Value,
  	                    if_block: &BasicBlock, else_block: &BasicBlock) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildCondBr(self.0,
    		                    cond.0,
    		                    if_block.0,
    		                    mem::transmute(else_block.0))
    })
  }

  /// Build an instruction that runs whichever block matches the value, or `default` if none of
  /// them matched it.
  pub fn create_switch(&self,
  	                   value: &Value,
  	                   default: &BasicBlock,
  	                   cases: &[(&Value, &BasicBlock)]) -> Value {
    Value(unsafe {
      let switch = core::LLVMBuildSwitch(self.0,
      	                                 value.0,
      	                                 default.0,
        	                                 cases.len() as c_uint);
      for case in cases {
        core::LLVMAddCase(switch, (case.0).0, (case.1).0);
      }

      switch
    })
  }

  /// Build an instruction that calls the function `func` with the arguments `args`.
  ///
  /// This will return the return value of the function.
  fn create_call_internal(&self, func: &Function, args: &[&Value], tail_call: bool) -> Value
  {
    let ref_array = to_llvmref_array!(args, LLVMValueRef);

    Value(unsafe {
        let call = core::LLVMBuildCall(self.0,
        	                             func.0,
                                       ref_array.as_ptr() as *mut LLVMValueRef,
        	                             args.len() as c_uint,
        	                             NULL_NAME.as_ptr());
        core::LLVMSetTailCall(call, if tail_call {1} else {0});
        call.into()
    })
  }

  /// Build an instruction that calls the function `func` with the arguments `args`.
  ///
  /// This will return the return value of the function.
  pub fn create_call(&self, func: &Function, args: &[&Value]) -> Value
  {
    self.create_call_internal(func, args, false)
  }

  /// Build an instruction that calls the function `func` with the arguments `args`.
  ///
  /// This will return the return value of the function.
  pub fn create_tail_call(&self, func: &Function, args: &[&Value]) -> Value
  {
    self.create_call_internal(func, args, true)
  }

  /// Build an instruction that yields to `true_val` if `cond` is equal to `1`, and `false_val`
  /// otherwise.
  pub fn create_select(&self, cond: &Value, true_val: &Value, false_val: &Value) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildSelect(self.0,
    		                    cond.0,
    		                    true_val.0,
    		                    false_val.0,
    		                    NULL_NAME.as_ptr()) })
  }

  /// Build an instruction that casts a value into a certain type.
  pub fn create_bit_cast(&self, value: &Value, dest: &Ty) -> Value
  {
    Value(unsafe { core::LLVMBuildBitCast(
    		self.0,
    		value.0,
    		dest.0,
    		NULL_NAME.as_ptr())
    })
  }

  /// Build an instruction that inserts a value into an aggregate data value.
  pub fn create_insert_value(&self, agg: &Value, elem: &Value, index: usize) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildInsertValue(self.0,
    		                         agg.0,
    		                         elem.0,
    		                         index as c_uint,
    		                         NULL_NAME.as_ptr())
    })
  }

  /// Build an instruction that extracts a value from an aggregate type.
	pub fn create_extract_value(&self, agg: &Value, index: usize) -> Value {
    Value(unsafe {
    	core::LLVMBuildExtractValue(self.0,
    		                          agg.0,
    		                          index as c_uint,
    		                          NULL_NAME.as_ptr())
   	})
  }

  unary_op!{create_load, LLVMBuildLoad}

  /// Build an instruction to compare two values with the predicate given.
  pub fn create_cmp(&self, l: &Value, r: &Value, pred: Predicate) -> Value
  {
    self.create_cmp_internal(l, r, pred, true)
  }

  /// Build an instruction to compare two values with the predicate given.
  pub fn create_ucmp(&self, l: &Value, r: &Value, pred: Predicate) -> Value
  {
    self.create_cmp_internal(l, r, pred, false)
  }

  fn create_cmp_internal(&self, l: &Value, r: &Value,
  											 pred: Predicate, signed: bool) -> Value {
  	let (lhs_ty, rhs_ty) = (l.ty(), r.ty());
    assert_eq!(lhs_ty, rhs_ty);

    if lhs_ty.is_integer() {
	    let p = match (pred, signed) {
	    	(Predicate::Eq,    _)   => LLVMIntPredicate::LLVMIntEQ,
	    	(Predicate::NotEq, _)   => LLVMIntPredicate::LLVMIntNE,
	    	(Predicate::Lth, true)  => LLVMIntPredicate::LLVMIntSLT,
	    	(Predicate::Lth, false) => LLVMIntPredicate::LLVMIntULT,
	    	(Predicate::Leq, true)  => LLVMIntPredicate::LLVMIntSLE,
	    	(Predicate::Leq, false) => LLVMIntPredicate::LLVMIntULE,
	    	(Predicate::Gth, true)  => LLVMIntPredicate::LLVMIntSGT,
	    	(Predicate::Gth, false) => LLVMIntPredicate::LLVMIntUGT,
	    	(Predicate::Geq, true)  => LLVMIntPredicate::LLVMIntSGE,
	    	(Predicate::Geq, false) => LLVMIntPredicate::LLVMIntUGE,
	    };

	    Value(unsafe {
		    core::LLVMBuildICmp(self.0,
	    		                  p,
	     		                  l.0, r.0,
	     		                  NULL_NAME.as_ptr())
	    })

    } else if lhs_ty.is_float() {
    	let p = match pred {
        Predicate::Eq    => LLVMRealPredicate::LLVMRealOEQ,
        Predicate::NotEq => LLVMRealPredicate::LLVMRealONE,
        Predicate::Gth   => LLVMRealPredicate::LLVMRealOGT,
        Predicate::Geq   => LLVMRealPredicate::LLVMRealOGE,
        Predicate::Lth   => LLVMRealPredicate::LLVMRealOLT,
        Predicate::Leq   => LLVMRealPredicate::LLVMRealOLE
      };

   	  Value(unsafe {
      	core::LLVMBuildFCmp(self.0,
      		                 p, l.0, r.0,
      		                 NULL_NAME.as_ptr())
      })

    } else {
      panic!("expected numbers, got {:?}", lhs_ty)
    }
  }

  /// Build an instruction that computes the address of a subelement of an aggregate data
  /// structure.
  ///
  /// Basically type-safe pointer arithmetic.
  pub fn create_gep(&self, pointer: &Value, indices: &[&Value]) -> Value
  {
    let ref_array = to_llvmref_array!(indices, LLVMValueRef);

    Value(unsafe {
    	core::LLVMBuildInBoundsGEP(self.0,
    	                           pointer.0,
    	                           ref_array.as_ptr() as *mut LLVMValueRef,
    	                           indices.len() as c_uint,
    	                           NULL_NAME.as_ptr())
    })
  }

  /// Build an instruction to select a value depending on the predecessor of the current block.
  pub fn create_phi(&self, ty: &Ty, name: &str) -> PhiNode
  {
	  PhiNode(unsafe {
	  	core::LLVMBuildPhi(self.0, ty.0, ::util::chars::from_str(name))
  	})
  }
}

#[cfg(test)]
mod tests {
	use super::*;
  use super::super::*;
  use types::LLVMTy;
  use value::{Predicate, ToValue};

	#[test]
	pub fn test_cond_br()
	{
		let jit = JitCompiler::new("test1").ok().unwrap();
    let ctx = jit.context();
    let module = jit.module();

    let func_ty = jit.create_func_ty(&u64::llvm_ty(ctx), &[&u64::llvm_ty(ctx)]);
    let func = jit.add_func("fib", &func_ty);
    let value = func.arg(0);

    let entry = func.append("entry");
    let then_bb = func.append("then_block");
    let else_bb = func.append("else_block");
    let merge_bb = func.append("merge_block");

    let builder = jit.builder();

    builder.position_at_end(&entry);
    let local = builder.create_alloca(&u64::llvm_ty(ctx));
    let cond = builder.create_cmp(&value.into(), &5u64.to_value(ctx), Predicate::Lth);
    builder.create_cond_br(&cond, &then_bb, &else_bb);

    builder.position_at_end(&then_bb);
    builder.create_store(&8u64.to_value(ctx), &local);
    builder.create_br(&merge_bb);

    builder.position_at_end(&else_bb);
    builder.create_store(&16u64.to_value(ctx), &local);
    builder.create_br(&merge_bb);

    builder.position_at_end(&merge_bb);
    let ret_val = builder.create_load(&local);
    builder.create_ret(&ret_val);

    jit.verify().unwrap();

    /*
    let ee = JitEngine::new(&module, JitOptions {opt_level: 0}).unwrap();
    ee.with_function(func, |fib: extern fn(u64) -> u64| {
      for i in 0..10 {
        if i < 5 {
          assert_eq!(8, fib(i));
        } else {
          assert_eq!(16, fib(i));
        }
      }
    });*/
	}
}<|endoftext|>


<commit_before>extern crate pkg_config;
extern crate gcc;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::{PathBuf, Path};
use std::process::Command;
use std::io::ErrorKind;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(t) => t,
        Err(e) => panic!("{} return the error {}", stringify!($e), e),
    })
}

fn main() {
    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    let src = env::current_dir().unwrap();
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let windows = target.contains("windows");

    // OSX ships libcurl by default, so we just use that version
    // unconditionally.
    if target.contains("apple") {
        return println!("cargo:rustc-flags=-l curl");
    }

    // Illumos/Solaris requires explicit linking with libnsl
    if target.contains("solaris") {
        println!("cargo:rustc-flags=-l nsl");
    }

    // Next, fall back and try to use pkg-config if its available.
    if !target.contains("windows") {
        match pkg_config::find_library("libcurl") {
            Ok(lib) => {
                for path in lib.include_paths.iter() {
                    println!("cargo:include={}", path.display());
                }
                return
            }
            Err(e) => println!("Couldn't find libcurl from \
                               pkgconfig ({:?}), compiling it from source...", e),
        }
    }

    if !Path::new("curl/.git").exists() {
        let _ = Command::new("git").args(&["submodule", "update", "--init"])
                                   .status();
    }

    println!("cargo:rustc-link-search={}/lib", dst.display());
    println!("cargo:rustc-link-lib=static=curl");
    println!("cargo:root={}", dst.display());
    println!("cargo:include={}/include", dst.display());
    if windows {
        println!("cargo:rustc-link-lib=ws2_32");
        println!("cargo:rustc-link-lib=crypt32");
    }

    // MSVC builds are just totally different
    if target.contains("msvc") {
        return build_msvc(&target);
    }

    let openssl_root = register_dep("OPENSSL");
    let zlib_root = register_dep("Z");
    let nghttp2_root = register_dep("NGHTTP2");

    let cfg = gcc::Config::new();
    let compiler = cfg.get_compiler();

    let _ = fs::create_dir(&dst.join("build"));

    let mut cmd = Command::new("sh");
    let mut cflags = OsString::new();
    for arg in compiler.args() {
        cflags.push(arg);
        cflags.push(" ");
    }

    // Can't run ./configure directly on msys2 b/c we're handing in
    // Windows-style paths (those starting with C:\), but it chokes on those.
    // For that reason we build up a shell script with paths converted to
    // posix versions hopefully...
    //
    // Also apparently the buildbots choke unless we manually set LD, who knows
    // why?!
    cmd.env("CC", compiler.path())
       .env("CFLAGS", cflags)
       .env("LD", &which("ld").unwrap())
       .env("VERBOSE", "1")
       .current_dir(&dst.join("build"))
       .arg(msys_compatible(&src.join("curl/configure")));

    // For now this build script doesn't support paths with spaces in them. This
    // is arguably a but in curl's configure script, but we could also try to
    // paper over it by using a tmp directory which *doesn't* have spaces in it.
    // As of now though that's not implemented so just give a nicer error for
    // the time being.
    let wants_space_error = windows &&
        (dst.to_str().map(|s| s.contains(" ")).unwrap_or(false) ||
         src.to_str().map(|s| s.contains(" ")).unwrap_or(false));
    if wants_space_error {
        panic!("\n\nunfortunately ./configure of libcurl is known to \
                fail if there's a space in the path to the current \
                directory\n\n\
                there's a space in either\n  {}\n  {}\nand this will cause the \
                build to fail\n\n\
                the MSVC build should work with a directory that has \
                spaces in it, and it would also work to move this to a \
                different directory without spaces\n\n",
               src.display(), dst.display())
    }

    if windows {
        cmd.arg("--with-winssl");
    } else {
        cmd.arg("--without-ca-bundle");
        cmd.arg("--without-ca-path");
    }
    if let Some(root) = openssl_root {
        cmd.arg(format!("--with-ssl={}", msys_compatible(&root)));
    }
    if let Some(root) = zlib_root {
        cmd.arg(format!("--with-zlib={}", msys_compatible(&root)));
    }
    cmd.arg("--enable-static=yes");
    cmd.arg("--enable-shared=no");
    match &env::var("PROFILE").unwrap()[..] {
        "bench" | "release" => {
            cmd.arg("--enable-optimize");
        }
        _ => {
            cmd.arg("--enable-debug");
            cmd.arg("--disable-optimize");
        }
    }
    cmd.arg(format!("--prefix={}", msys_compatible(&dst)));

    if target != host &&
       (!target.contains("windows") || !host.contains("windows")) {
        cmd.arg(format!("--build={}", host));
        cmd.arg(format!("--host={}", target));
        cmd.arg(format!("--target={}", target));
    }

    if let Some(root) = nghttp2_root {
        cmd.arg(format!("--with-nghttp2={}", msys_compatible(&root)));
    } else {
        cmd.arg("--without-nghttp2");
    }

    cmd.arg("--without-librtmp");
    cmd.arg("--without-libidn");
    cmd.arg("--without-libssh2");
    cmd.arg("--disable-ldap");
    cmd.arg("--disable-ldaps");
    cmd.arg("--disable-ftp");
    cmd.arg("--disable-rtsp");
    cmd.arg("--disable-dict");
    cmd.arg("--disable-telnet");
    cmd.arg("--disable-tftp");
    cmd.arg("--disable-pop3");
    cmd.arg("--disable-imap");
    cmd.arg("--disable-smtp");
    cmd.arg("--disable-gopher");
    cmd.arg("--disable-manual");
    cmd.arg("--disable-smb");
    cmd.arg("--disable-sspi");

    run(&mut cmd, "sh");
    run(Command::new(make())
                .arg(&format!("-j{}", env::var("NUM_JOBS").unwrap()))
                .current_dir(&dst.join("build")), "make");
    run(Command::new(make())
                .arg("install")
                .current_dir(&dst.join("build")), "make");
}

fn run(cmd: &mut Command, program: &str) {
    println!("running: {:?}", cmd);
    let status = match cmd.status() {
        Ok(status) => status,
        Err(ref e) if e.kind() == ErrorKind::NotFound => {
            fail(&format!("failed to execute command: {}\nis `{}` not installed?",
                          e, program));
        }
        Err(e) => fail(&format!("failed to execute command: {}", e)),
    };
    if !status.success() {
        fail(&format!("command did not execute successfully, got: {}", status));
    }
}

fn fail(s: &str) -> ! {
    panic!("\n{}\n\nbuild script failed, must exit now", s)
}

fn make() -> &'static str {
    if cfg!(target_os = "freebsd") {"gmake"} else {"make"}
}

fn which(cmd: &str) -> Option<PathBuf> {
    let cmd = format!("{}{}", cmd, env::consts::EXE_SUFFIX);
    let paths = env::var_os("PATH").unwrap();
    env::split_paths(&paths).map(|p| p.join(&cmd)).find(|p| {
        fs::metadata(p).is_ok()
    })
}

fn msys_compatible(path: &Path) -> String {
    let path = path.to_str().unwrap();
    if !cfg!(windows) {
        return path.to_string()
    }
    path.replace("C:\\", "/c/")
        .replace("\\", "/")
}

fn register_dep(dep: &str) -> Option<PathBuf> {
    if let Some(s) = env::var_os(&format!("DEP_{}_ROOT", dep)) {
        prepend("PKG_CONFIG_PATH", Path::new(&s).join("lib/pkgconfig"));
        return Some(s.into())
    }
    if let Some(s) = env::var_os(&format!("DEP_{}_INCLUDE", dep)) {
        let root = Path::new(&s).parent().unwrap();
        env::set_var(&format!("DEP_{}_ROOT", dep), root);
        let path = root.join("lib/pkgconfig");
        if path.exists() {
            prepend("PKG_CONFIG_PATH", path);
            return Some(root.to_path_buf())
        }
    }

    return None;

    fn prepend(var: &str, val: PathBuf) {
        let prefix = env::var(var).unwrap_or(String::new());
        let mut v = vec![val];
        v.extend(env::split_paths(&prefix));
        env::set_var(var, &env::join_paths(v).unwrap());
    }
}

fn build_msvc(target: &str) {
    let cmd = gcc::windows_registry::find(target, "nmake.exe");
    let mut cmd = cmd.unwrap_or(Command::new("nmake.exe"));
    let src = env::current_dir().unwrap();
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let machine = if target.starts_with("x86_64") {
        "x64"
    } else if target.starts_with("i686") {
        "x86"
    } else {
        panic!("unknown msvc target: {}", target);
    };

    t!(fs::create_dir_all(dst.join("include/curl")));
    t!(fs::create_dir_all(dst.join("lib")));

    cmd.current_dir(src.join("curl/winbuild"));
    cmd.arg("/f").arg("Makefile.vc")
       .arg("MODE=static")
       .arg("ENABLE_IDN=yes")
       .arg("DEBUG=no")
       .arg("GEN_PDB=no")
       .arg("ENABLE_WINSSL=yes")
       .arg("ENABLE_SSPI=yes")
       .arg(format!("MACHINE={}", machine));

    let features = env::var("CARGO_CFG_TARGET_FEATURE")
                      .unwrap_or(String::new());
    if features.contains("crt-static") {
        cmd.arg("RTLIBCFG=static");
    }

    if let Some(inc) = env::var_os("DEP_Z_ROOT") {
        let inc = PathBuf::from(inc);
        let mut s = OsString::from("WITH_DEVEL=");
        s.push(&inc);
        cmd.arg("WITH_ZLIB=static").arg(s);

        // the build system for curl expects this library to be called
        // zlib_a.lib, so make sure it's named correctly (where libz-sys just
        // produces zlib.lib)
        let _ = fs::remove_file(&inc.join("lib/zlib_a.lib"));
        t!(fs::hard_link(inc.join("lib/zlib.lib"), inc.join("lib/zlib_a.lib")));
    }
    run(&mut cmd, "nmake");

    let name = format!("libcurl-vc-{}-release-static-zlib-static-\
                        ipv6-sspi-winssl", machine);
    let libs = src.join("curl/builds").join(name);

    t!(fs::copy(libs.join("lib/libcurl_a.lib"), dst.join("lib/curl.lib")));
    for f in t!(fs::read_dir(libs.join("include/curl"))) {
        let path = t!(f).path();
        let dst = dst.join("include/curl").join(path.file_name().unwrap());
        t!(fs::copy(path, dst));
    }
    t!(fs::remove_dir_all(src.join("curl/builds")));
    println!("cargo:rustc-link-lib=wldap32");
    println!("cargo:rustc-link-lib=advapi32");
    println!("cargo:rustc-link-lib=normaliz");
}
<commit_msg>restore --host and --target for windows targets<commit_after>extern crate pkg_config;
extern crate gcc;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::{PathBuf, Path};
use std::process::Command;
use std::io::ErrorKind;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(t) => t,
        Err(e) => panic!("{} return the error {}", stringify!($e), e),
    })
}

fn main() {
    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    let src = env::current_dir().unwrap();
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let windows = target.contains("windows");

    // OSX ships libcurl by default, so we just use that version
    // unconditionally.
    if target.contains("apple") {
        return println!("cargo:rustc-flags=-l curl");
    }

    // Illumos/Solaris requires explicit linking with libnsl
    if target.contains("solaris") {
        println!("cargo:rustc-flags=-l nsl");
    }

    // Next, fall back and try to use pkg-config if its available.
    if !target.contains("windows") {
        match pkg_config::find_library("libcurl") {
            Ok(lib) => {
                for path in lib.include_paths.iter() {
                    println!("cargo:include={}", path.display());
                }
                return
            }
            Err(e) => println!("Couldn't find libcurl from \
                               pkgconfig ({:?}), compiling it from source...", e),
        }
    }

    if !Path::new("curl/.git").exists() {
        let _ = Command::new("git").args(&["submodule", "update", "--init"])
                                   .status();
    }

    println!("cargo:rustc-link-search={}/lib", dst.display());
    println!("cargo:rustc-link-lib=static=curl");
    println!("cargo:root={}", dst.display());
    println!("cargo:include={}/include", dst.display());
    if windows {
        println!("cargo:rustc-link-lib=ws2_32");
        println!("cargo:rustc-link-lib=crypt32");
    }

    // MSVC builds are just totally different
    if target.contains("msvc") {
        return build_msvc(&target);
    }

    let openssl_root = register_dep("OPENSSL");
    let zlib_root = register_dep("Z");
    let nghttp2_root = register_dep("NGHTTP2");

    let cfg = gcc::Config::new();
    let compiler = cfg.get_compiler();

    let _ = fs::create_dir(&dst.join("build"));

    let mut cmd = Command::new("sh");
    let mut cflags = OsString::new();
    for arg in compiler.args() {
        cflags.push(arg);
        cflags.push(" ");
    }

    // Can't run ./configure directly on msys2 b/c we're handing in
    // Windows-style paths (those starting with C:\), but it chokes on those.
    // For that reason we build up a shell script with paths converted to
    // posix versions hopefully...
    //
    // Also apparently the buildbots choke unless we manually set LD, who knows
    // why?!
    cmd.env("CC", compiler.path())
       .env("CFLAGS", cflags)
       .env("LD", &which("ld").unwrap())
       .env("VERBOSE", "1")
       .current_dir(&dst.join("build"))
       .arg(msys_compatible(&src.join("curl/configure")));

    // For now this build script doesn't support paths with spaces in them. This
    // is arguably a but in curl's configure script, but we could also try to
    // paper over it by using a tmp directory which *doesn't* have spaces in it.
    // As of now though that's not implemented so just give a nicer error for
    // the time being.
    let wants_space_error = windows &&
        (dst.to_str().map(|s| s.contains(" ")).unwrap_or(false) ||
         src.to_str().map(|s| s.contains(" ")).unwrap_or(false));
    if wants_space_error {
        panic!("\n\nunfortunately ./configure of libcurl is known to \
                fail if there's a space in the path to the current \
                directory\n\n\
                there's a space in either\n  {}\n  {}\nand this will cause the \
                build to fail\n\n\
                the MSVC build should work with a directory that has \
                spaces in it, and it would also work to move this to a \
                different directory without spaces\n\n",
               src.display(), dst.display())
    }

    if windows {
        cmd.arg("--with-winssl");
    } else {
        cmd.arg("--without-ca-bundle");
        cmd.arg("--without-ca-path");
    }
    if let Some(root) = openssl_root {
        cmd.arg(format!("--with-ssl={}", msys_compatible(&root)));
    }
    if let Some(root) = zlib_root {
        cmd.arg(format!("--with-zlib={}", msys_compatible(&root)));
    }
    cmd.arg("--enable-static=yes");
    cmd.arg("--enable-shared=no");
    match &env::var("PROFILE").unwrap()[..] {
        "bench" | "release" => {
            cmd.arg("--enable-optimize");
        }
        _ => {
            cmd.arg("--enable-debug");
            cmd.arg("--disable-optimize");
        }
    }
    cmd.arg(format!("--prefix={}", msys_compatible(&dst)));

    if target != host &&
       (!target.contains("windows") || !host.contains("windows")) {
        // NOTE GNU terminology
        // BUILD = machine where we are (cross) compiling curl
        // HOST = machine where the compiled curl will be used
        // TARGET = only relevant when compiling compilers
        if target.contains("windows") {
            // curl's configure can't parse `-windows-` triples when used
            // as `--host`s. In those cases we use this combination of
            // `host` and `target` that appears to do the right thing.
            cmd.arg(format!("--host={}", host));
            cmd.arg(format!("--target={}", target));
        } else {
            cmd.arg(format!("--build={}", host));
            cmd.arg(format!("--host={}", target));
        }
    }

    if let Some(root) = nghttp2_root {
        cmd.arg(format!("--with-nghttp2={}", msys_compatible(&root)));
    } else {
        cmd.arg("--without-nghttp2");
    }

    cmd.arg("--without-librtmp");
    cmd.arg("--without-libidn");
    cmd.arg("--without-libssh2");
    cmd.arg("--disable-ldap");
    cmd.arg("--disable-ldaps");
    cmd.arg("--disable-ftp");
    cmd.arg("--disable-rtsp");
    cmd.arg("--disable-dict");
    cmd.arg("--disable-telnet");
    cmd.arg("--disable-tftp");
    cmd.arg("--disable-pop3");
    cmd.arg("--disable-imap");
    cmd.arg("--disable-smtp");
    cmd.arg("--disable-gopher");
    cmd.arg("--disable-manual");
    cmd.arg("--disable-smb");
    cmd.arg("--disable-sspi");

    run(&mut cmd, "sh");
    run(Command::new(make())
                .arg(&format!("-j{}", env::var("NUM_JOBS").unwrap()))
                .current_dir(&dst.join("build")), "make");
    run(Command::new(make())
                .arg("install")
                .current_dir(&dst.join("build")), "make");
}

fn run(cmd: &mut Command, program: &str) {
    println!("running: {:?}", cmd);
    let status = match cmd.status() {
        Ok(status) => status,
        Err(ref e) if e.kind() == ErrorKind::NotFound => {
            fail(&format!("failed to execute command: {}\nis `{}` not installed?",
                          e, program));
        }
        Err(e) => fail(&format!("failed to execute command: {}", e)),
    };
    if !status.success() {
        fail(&format!("command did not execute successfully, got: {}", status));
    }
}

fn fail(s: &str) -> ! {
    panic!("\n{}\n\nbuild script failed, must exit now", s)
}

fn make() -> &'static str {
    if cfg!(target_os = "freebsd") {"gmake"} else {"make"}
}

fn which(cmd: &str) -> Option<PathBuf> {
    let cmd = format!("{}{}", cmd, env::consts::EXE_SUFFIX);
    let paths = env::var_os("PATH").unwrap();
    env::split_paths(&paths).map(|p| p.join(&cmd)).find(|p| {
        fs::metadata(p).is_ok()
    })
}

fn msys_compatible(path: &Path) -> String {
    let path = path.to_str().unwrap();
    if !cfg!(windows) {
        return path.to_string()
    }
    path.replace("C:\\", "/c/")
        .replace("\\", "/")
}

fn register_dep(dep: &str) -> Option<PathBuf> {
    if let Some(s) = env::var_os(&format!("DEP_{}_ROOT", dep)) {
        prepend("PKG_CONFIG_PATH", Path::new(&s).join("lib/pkgconfig"));
        return Some(s.into())
    }
    if let Some(s) = env::var_os(&format!("DEP_{}_INCLUDE", dep)) {
        let root = Path::new(&s).parent().unwrap();
        env::set_var(&format!("DEP_{}_ROOT", dep), root);
        let path = root.join("lib/pkgconfig");
        if path.exists() {
            prepend("PKG_CONFIG_PATH", path);
            return Some(root.to_path_buf())
        }
    }

    return None;

    fn prepend(var: &str, val: PathBuf) {
        let prefix = env::var(var).unwrap_or(String::new());
        let mut v = vec![val];
        v.extend(env::split_paths(&prefix));
        env::set_var(var, &env::join_paths(v).unwrap());
    }
}

fn build_msvc(target: &str) {
    let cmd = gcc::windows_registry::find(target, "nmake.exe");
    let mut cmd = cmd.unwrap_or(Command::new("nmake.exe"));
    let src = env::current_dir().unwrap();
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let machine = if target.starts_with("x86_64") {
        "x64"
    } else if target.starts_with("i686") {
        "x86"
    } else {
        panic!("unknown msvc target: {}", target);
    };

    t!(fs::create_dir_all(dst.join("include/curl")));
    t!(fs::create_dir_all(dst.join("lib")));

    cmd.current_dir(src.join("curl/winbuild"));
    cmd.arg("/f").arg("Makefile.vc")
       .arg("MODE=static")
       .arg("ENABLE_IDN=yes")
       .arg("DEBUG=no")
       .arg("GEN_PDB=no")
       .arg("ENABLE_WINSSL=yes")
       .arg("ENABLE_SSPI=yes")
       .arg(format!("MACHINE={}", machine));

    let features = env::var("CARGO_CFG_TARGET_FEATURE")
                      .unwrap_or(String::new());
    if features.contains("crt-static") {
        cmd.arg("RTLIBCFG=static");
    }

    if let Some(inc) = env::var_os("DEP_Z_ROOT") {
        let inc = PathBuf::from(inc);
        let mut s = OsString::from("WITH_DEVEL=");
        s.push(&inc);
        cmd.arg("WITH_ZLIB=static").arg(s);

        // the build system for curl expects this library to be called
        // zlib_a.lib, so make sure it's named correctly (where libz-sys just
        // produces zlib.lib)
        let _ = fs::remove_file(&inc.join("lib/zlib_a.lib"));
        t!(fs::hard_link(inc.join("lib/zlib.lib"), inc.join("lib/zlib_a.lib")));
    }
    run(&mut cmd, "nmake");

    let name = format!("libcurl-vc-{}-release-static-zlib-static-\
                        ipv6-sspi-winssl", machine);
    let libs = src.join("curl/builds").join(name);

    t!(fs::copy(libs.join("lib/libcurl_a.lib"), dst.join("lib/curl.lib")));
    for f in t!(fs::read_dir(libs.join("include/curl"))) {
        let path = t!(f).path();
        let dst = dst.join("include/curl").join(path.file_name().unwrap());
        t!(fs::copy(path, dst));
    }
    t!(fs::remove_dir_all(src.join("curl/builds")));
    println!("cargo:rustc-link-lib=wldap32");
    println!("cargo:rustc-link-lib=advapi32");
    println!("cargo:rustc-link-lib=normaliz");
}
<|endoftext|>


<commit_before>
use std::ffi::CString;
use std::os::raw::c_char;

#[link( name = "ncurses" )]
extern {
    pub fn initscr();
    pub fn refresh();
    pub fn endwin();
    pub fn getch() -> i32;
    pub fn printw( format : *const c_char, ... );
    pub fn cbreak();
    pub fn noecho();
    pub fn keypad();
    pub fn clear();
    pub fn mvprintw( y : i32, x : i32, format : *const c_char, ... );
}

extern {
    pub static error : i32;
    fn move_wrapper( y : i32, x : i32 );
}

pub unsafe fn cursor_move( y : i32, x : i32 ) {
    move_wrapper( y, x );
}

<commit_msg>removed unused using<commit_after>
use std::os::raw::c_char;

#[link( name = "ncurses" )]
extern {
    pub fn initscr();
    pub fn refresh();
    pub fn endwin();
    pub fn getch() -> i32;
    pub fn printw( format : *const c_char, ... );
    pub fn cbreak();
    pub fn noecho();
    pub fn keypad();
    pub fn clear();
    pub fn mvprintw( y : i32, x : i32, format : *const c_char, ... );
}

extern {
    pub static error : i32;
    fn move_wrapper( y : i32, x : i32 );
}

pub unsafe fn cursor_move( y : i32, x : i32 ) {
    move_wrapper( y, x );
}

<|endoftext|>


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

use anyhow::{bail, format_err, Result};
use diem_types::{
    account_address::AccountAddress,
    chain_id::ChainId,
    transaction::{Transaction, WriteSetPayload},
};

use compiled_stdlib::{stdlib_modules, StdLibOptions};
use diem_writeset_generator::{
    create_release, encode_custom_script, encode_halt_network_payload,
    encode_remove_validators_payload, verify_release,
};
use std::path::PathBuf;
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
struct Opt {
    /// Path to the output serialized bytes
    #[structopt(long, short, parse(from_os_str))]
    output: Option<PathBuf>,
    /// Output as serialized WriteSet payload. Set this flag if this payload is submitted to AOS portal.
    #[structopt(long)]
    output_payload: bool,
    #[structopt(subcommand)]
    cmd: Command,
}

#[derive(Debug, StructOpt)]
enum Command {
    /// List of addresses to remove from validator set
    #[structopt(name = "remove-validators")]
    RemoveValidators { addresses: Vec<AccountAddress> },
    /// Block the execution of any transaction in the network
    #[structopt(name = "halt-network")]
    HaltNetwork,
    /// Build a custom file in templates into admin script
    #[structopt(name = "build-custom-script")]
    BuildCustomScript {
        script_name: String,
        args: String,
        execute_as: Option<AccountAddress>,
    },
    /// Create a release writeset by comparing local Diem Framework against a remote blockchain state.
    #[structopt(name = "create-release")]
    CreateDiemFrameworkRelease {
        /// ChainID to distinguish the diem network. e.g: PREMAINNET
        chain_id: ChainId,
        /// Public JSON-rpc endpoint URL.
        // TODO: Get rid of this URL argument once we have a stable mapping from ChainId to its url.
        url: String,
        /// Blockchain height
        version: u64,
        /// Set the flag to true in the first release. This will manually create the first release artifact on disk.
        #[structopt(long)]
        first_release: bool,
    },
    /// Verify if a blob is generated by the checked-in artifact.
    #[structopt(name = "verify-release")]
    VerifyDiemFrameworkRelease {
        /// ChainID to distinguish the diem network. e.g: PREMAINNET
        chain_id: ChainId,
        /// Public JSON-rpc endpoint URL.
        url: String,
        /// Path to the serialized bytes of WriteSet.
        #[structopt(parse(from_os_str))]
        writeset_path: PathBuf,
    },
}

fn save_bytes(bytes: Vec<u8>, path: PathBuf) -> Result<()> {
    std::fs::write(path.as_path(), bytes.as_slice())
        .map_err(|_| format_err!("Unable to write to path"))
}

fn main() -> Result<()> {
    let opt = Opt::from_args();
    let payload = match opt.cmd {
        Command::RemoveValidators { addresses } => encode_remove_validators_payload(addresses),
        Command::HaltNetwork => encode_halt_network_payload(),
        Command::BuildCustomScript {
            script_name,
            args,
            execute_as,
        } => encode_custom_script(
            &script_name,
            &serde_json::from_str::<serde_json::Value>(args.as_str())?,
            execute_as,
        ),
        Command::CreateDiemFrameworkRelease {
            chain_id,
            url,
            version,
            first_release,
        } => {
            let release_modules = stdlib_modules(StdLibOptions::Compiled);
            create_release(chain_id, url, version, first_release, release_modules)?
        }
        Command::VerifyDiemFrameworkRelease {
            url,
            chain_id,
            writeset_path,
        } => {
            let writeset_payload = {
                let raw_bytes = std::fs::read(writeset_path.as_path()).unwrap();
                bcs::from_bytes::<WriteSetPayload>(raw_bytes.as_slice()).or_else(|_| {
                    let txn: Transaction = bcs::from_bytes(raw_bytes.as_slice())?;
                    match txn {
                        Transaction::GenesisTransaction(ws) => Ok(ws),
                        _ => bail!("Unexpected transacton type"),
                    }
                })?
            };
            let release_modules = stdlib_modules(StdLibOptions::Compiled);
            verify_release(chain_id, url, &writeset_payload, release_modules)?;
            return Ok(());
        }
    };
    let output_path = if let Some(p) = opt.output {
        p
    } else {
        bail!("Empty output path provided");
    };
    if opt.output_payload {
        save_bytes(
            bcs::to_bytes(&payload).map_err(|_| format_err!("Transaction Serialize Error"))?,
            output_path,
        )
    } else {
        save_bytes(
            bcs::to_bytes(&Transaction::GenesisTransaction(payload))
                .map_err(|_| format_err!("Transaction Serialize Error"))?,
            output_path,
        )
    }
}
<commit_msg>[writeset-generator] Filter out Genesis module from release process.<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use anyhow::{bail, format_err, Result};
use diem_types::{
    account_address::AccountAddress,
    chain_id::ChainId,
    transaction::{Transaction, WriteSetPayload},
};

use compiled_stdlib::{stdlib_modules as stdlib, StdLibOptions};
use diem_writeset_generator::{
    create_release, encode_custom_script, encode_halt_network_payload,
    encode_remove_validators_payload, verify_release,
};
use std::path::PathBuf;
use structopt::StructOpt;
use vm::CompiledModule;

const GENESIS_MODULE_NAME: &str = "Genesis";

#[derive(Debug, StructOpt)]
struct Opt {
    /// Path to the output serialized bytes
    #[structopt(long, short, parse(from_os_str))]
    output: Option<PathBuf>,
    /// Output as serialized WriteSet payload. Set this flag if this payload is submitted to AOS portal.
    #[structopt(long)]
    output_payload: bool,
    #[structopt(subcommand)]
    cmd: Command,
}

#[derive(Debug, StructOpt)]
enum Command {
    /// List of addresses to remove from validator set
    #[structopt(name = "remove-validators")]
    RemoveValidators { addresses: Vec<AccountAddress> },
    /// Block the execution of any transaction in the network
    #[structopt(name = "halt-network")]
    HaltNetwork,
    /// Build a custom file in templates into admin script
    #[structopt(name = "build-custom-script")]
    BuildCustomScript {
        script_name: String,
        args: String,
        execute_as: Option<AccountAddress>,
    },
    /// Create a release writeset by comparing local Diem Framework against a remote blockchain state.
    #[structopt(name = "create-release")]
    CreateDiemFrameworkRelease {
        /// ChainID to distinguish the diem network. e.g: PREMAINNET
        chain_id: ChainId,
        /// Public JSON-rpc endpoint URL.
        // TODO: Get rid of this URL argument once we have a stable mapping from ChainId to its url.
        url: String,
        /// Blockchain height
        version: u64,
        /// Set the flag to true in the first release. This will manually create the first release artifact on disk.
        #[structopt(long)]
        first_release: bool,
    },
    /// Verify if a blob is generated by the checked-in artifact.
    #[structopt(name = "verify-release")]
    VerifyDiemFrameworkRelease {
        /// ChainID to distinguish the diem network. e.g: PREMAINNET
        chain_id: ChainId,
        /// Public JSON-rpc endpoint URL.
        url: String,
        /// Path to the serialized bytes of WriteSet.
        #[structopt(parse(from_os_str))]
        writeset_path: PathBuf,
    },
}

fn save_bytes(bytes: Vec<u8>, path: PathBuf) -> Result<()> {
    std::fs::write(path.as_path(), bytes.as_slice())
        .map_err(|_| format_err!("Unable to write to path"))
}

fn stdlib_modules() -> Vec<CompiledModule> {
    // Need to filter out Genesis module similiar to what is done in vmgenesis to make sure Genesis
    // module isn't published on-chain.
    stdlib(StdLibOptions::Compiled)
        .iter()
        .filter(|module| module.self_id().name().as_str() != GENESIS_MODULE_NAME)
        .cloned()
        .collect()
}

fn main() -> Result<()> {
    let opt = Opt::from_args();
    let payload = match opt.cmd {
        Command::RemoveValidators { addresses } => encode_remove_validators_payload(addresses),
        Command::HaltNetwork => encode_halt_network_payload(),
        Command::BuildCustomScript {
            script_name,
            args,
            execute_as,
        } => encode_custom_script(
            &script_name,
            &serde_json::from_str::<serde_json::Value>(args.as_str())?,
            execute_as,
        ),
        Command::CreateDiemFrameworkRelease {
            chain_id,
            url,
            version,
            first_release,
        } => {
            let release_modules = stdlib_modules();
            create_release(chain_id, url, version, first_release, &release_modules)?
        }
        Command::VerifyDiemFrameworkRelease {
            url,
            chain_id,
            writeset_path,
        } => {
            let writeset_payload = {
                let raw_bytes = std::fs::read(writeset_path.as_path()).unwrap();
                bcs::from_bytes::<WriteSetPayload>(raw_bytes.as_slice()).or_else(|_| {
                    let txn: Transaction = bcs::from_bytes(raw_bytes.as_slice())?;
                    match txn {
                        Transaction::GenesisTransaction(ws) => Ok(ws),
                        _ => bail!("Unexpected transacton type"),
                    }
                })?
            };
            let release_modules = stdlib_modules();
            verify_release(chain_id, url, &writeset_payload, &release_modules)?;
            return Ok(());
        }
    };
    let output_path = if let Some(p) = opt.output {
        p
    } else {
        bail!("Empty output path provided");
    };
    if opt.output_payload {
        save_bytes(
            bcs::to_bytes(&payload).map_err(|_| format_err!("Transaction Serialize Error"))?,
            output_path,
        )
    } else {
        save_bytes(
            bcs::to_bytes(&Transaction::GenesisTransaction(payload))
                .map_err(|_| format_err!("Transaction Serialize Error"))?,
            output_path,
        )
    }
}
<|endoftext|>