<commit_before>use std::collections::BTreeMap;
use ::model::{MessageId, UserId};

/// An indicator of the type of sorting mode to use when searching for
/// [`Message`]s via the [`Search`] builder.
///
/// [`Message`]: ../../model/struct.Message.html
/// [`Search`]: struct.Search.html
pub enum SortingMode {
    /// Search by messages' relevance to parameters.
    Relevance,
    /// Search by messages' timestamp, where results will match according to
    /// parameters. This is used in conjunction in the [`Search::sort_order`]
    /// method, and is used in conjunction with [`SortingOrder`].
    ///
    /// [`Search::sort_order`]: struct.Search.html#method.sort_order
    /// [`SortingOrder`]: enum.SortingOrder.html
    Timestamp,
}

impl SortingMode {
    /// Retrieves the name of the sorting mode. This is equivalent to a
    /// lowercase string version of each variant.
    pub fn name(&self) -> &str {
        match *self {
            SortingMode::Relevance => "relevance",
            SortingMode::Timestamp => "timestamp",
        }
    }
}

/// An indicator of how to sort results when searching for [`Message`]s via the
/// [`Search`] builder.
///
/// [`Message`]: ../../model/struct.Message.html
/// [`Search`]: struct.Search.html
pub enum SortingOrder {
    /// Search message results in ascending order.
    ///
    /// In the case of [`SortingMode::Relevance`], this will search from the
    /// least relevant to the most relevant.
    ///
    /// In the case of [`SortingMode::Timestamp`], this will indicate to search
    /// from the least recent to the most recent.
    ///
    /// [`SortingMode::Relevance`]: enum.SortingMode.html#variant.Relevance
    /// [`SortingMode::Timestamp`]: enum.SortingMode.html#variant.Timestamp
    Ascending,
    /// Search message results in descending order.
    ///
    /// In the case of [`SortingMode::Relevance`], this will search from the
    /// most relevant to least relevant.
    ///
    /// In the case of [`SortingMode::Timestamp`], this will search from the
    /// most recent to least recent.
    ///
    /// [`SortingMode::Relevance`]: enum.SortingMode.html#variant.Relevance
    /// [`SortingMode::Timestamp`]: enum.SortingMode.html#variant.Timestamp
    Descending,
}

impl SortingOrder {
    /// Retrieves the name of the sorting order. This is equivalent to a
    /// lowercase string version of each variant.
    pub fn name(&self) -> &str {
        match *self {
            SortingOrder::Ascending => "asc",
            SortingOrder::Descending => "desc",
        }
    }
}

/// A builder used to query a [`Channel`] or [`Guild`] for its [`Message`]s,
/// specifying certain parameters to narrow down the returned messages.
///
/// Many methods are provided to narrow down the results, such as [`sort_by`] -
/// which is used with the [`SortingMode`] enum to sort the results - or
/// [`limit`], which can be used in conjunction with [`offset`] to paginate
/// results.
///
/// # Examples
///
/// Provided are multiple in-depth examples for searching through different
/// means. Also see [example 08] for a fully runnable bot.
///
/// ### Searching a Channel
///
/// Search for messages via [`Context::search_channel`] with the content
/// `"rust"`, which have no embed, no attachment, searching by relevance in
/// ascending order, and limiting to 5 results:
///
/// ```rust,ignore
/// // assuming you are in a context
///
/// let res = context.search_channel(message.channel_id, |s| s
///     .content("rust")
///     .has_embed(false)
///     .has_attachment(false)
///     .limit(5)
///     .sort_by(SortingMode::Relevance)
///     .sort_order(SortingOrder::Ascending));
/// ```
///
/// ### Searching a Guild's Channels
///
/// Search for messages with a query provided by a user, which have an
/// embed, have no attachment, searching by timestamp in descending order,
/// limiting to 2 results, and only searching channels that have a name
/// prefixed with `"search-"`:
///
/// ```rust,ignore
/// use serenity::client::{Client, Context};
/// use serenity::model::Message;
/// use serenity::utils::builder::{SortingMode, SortingOrder};
/// use std::env;
///
/// let mut client = Client::login_bot(&env::var("DISCORD_BOT_TOKEN").unwrap());
///
/// client.with_framework(|f| f
///     .configure(|c| c.prefix("~").on_mention(true))
///     .on("search", search));
///
/// command!(search(context, message, args) {
///     let query = args.join(" ");
///
///     if query.is_empty() {
///         let _ = context.say("You must provide a query");
///
///         return Ok(());
///     }
///
///     let guild = message.guild().unwrap();
///
///     let channel_ids = guild
///         .channels
///         .values()
///         .filter(|c| c.name.starts_with("search-"))
///         .map(|c| c.id)
///         .collect();
///
///     let search = context.search_guild(guild.id, channel_ids, |s| s
///         .content(&query)
///         .context_size(0)
///         .has_attachment(true)
///         .has_embed(true)
///         .max_id(message.id.0 - 1)
///         .sort_by(SortingMode::Timestamp)
///         .sort_order(SortingOrder::Descending));
///
///     let mut messages = match search {
///         Ok(messages) => messages,
///         Err(why) => {
///             println!("Error performing search '{}': {:?}", query, why);
///
///             let _ = context.say("Error occurred while searching");
///
///             return Ok(());
///         },
///     };
///
///     let _ = context.send_message(message.channel_id, |m| m
///         .content(&format!("Found {} total results", messages.total))
///         .embed(|mut e| {
///             for (i, messages) in messages.results.iter_mut().enumerate() {
///                 let mut message = match messages.get_mut(i) {
///                     Some(message) => message,
///                     None => break,
///                 };
///
///                 message.content.truncate(1000);
///
///                 e = e.field(|f| f
///                     .name(&format!("Result {}", i))
///                     .value(&message.content));
///              }
///
///              e
///         }));
/// });
/// ```
///
/// [`Channel`]: ../../model/enum.Channel.html
/// [`Context::search_channel`]: ../../client/struct.Context.html#method.search_channel
/// [`Guild`]: ../../model/struct.Guild.html
/// [`Message`]: ../../model/struct.Message.html
/// [`SortingMode`]: enum.SortingMode.html
/// [`limit`]: #method.limit
/// [`offset`]: #method.offset
/// [`sort_by`]: #method.sort_by
/// [example 08]: https://github.com/zeyla/serenity/tree/master/examples/08_search
pub struct Search<'a>(pub BTreeMap<&'a str, String>);

impl<'a> Search<'a> {
    /// Sets the list of attachment extensions to search by.
    ///
    /// When providing a vector of extensions, do _not_ include the period (`.`)
    /// character as part of the search.
    ///
    /// This is sent to Discord as a comma-separated value list of extension
    /// names.
    pub fn attachment_extensions(mut self, attachment_extensions: &[&str]) -> Self {
        let list = attachment_extensions.join(" ");

        self.0.insert("attachment_extensions", list);

        self
    }

    /// Sets the filename of the attachments to search for.
    pub fn attachment_filename(mut self, attachment_filename: &str) -> Self {
        self.0.insert("attachment_filename", attachment_filename.to_owned());

        self
    }

    /// Sets the Id of the author of [`Message`]s to search for. This excludes
    /// all messages by other [`User`]s.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    /// [`User`]: ../../model/struct.User.html
    pub fn author_id<U: Into<UserId>>(mut self, author_id: U) -> Self {
        self.0.insert("author_id", author_id.into().0.to_string());

        self
    }

    /// Sets the content of the [`Message`] to search for. This is a fuzzy
    /// search, and can partially match the given query content.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    pub fn content(mut self, content: &str) -> Self {
        self.0.insert("content", content.to_owned());

        self
    }

    /// Sets the amount of "context" [`Message`]s to provide, at maximum. This
    /// is the number of messages to provide around each side
    /// (ascending+descending) of the "hit" (aka found) message.
    ///
    /// The default value is `2`. The minimum value is `0`. The maximum value is
    /// `2`.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    pub fn context_size(mut self, context_size: u8) -> Self {
        self.0.insert("context_size", context_size.to_string());

        self
    }

    /// Sets the embed providers to search by.
    ///
    /// This is a list of the providers' names.
    ///
    /// This is sent to Discord as a comma-separated value list of provider
    /// names.
    pub fn embed_providers(mut self, embed_providers: &[&str]) -> Self {
        self.0.insert("embed_providers", embed_providers.join(" "));

        self
    }

    /// Sets the type of [`Embed`]s to search by.
    ///
    /// An example of an [embed type][`Embed::kind`] is `"rich"`.
    ///
    /// [`Embed`]: ../../model/struct.Embed.html
    /// [`Embed::kind`]: ../../model/struct.Embed.html#structfield.kind
    pub fn embed_types(mut self, embed_types: &[&str]) -> Self {
        self.0.insert("embed_types", embed_types.join(" "));

        self
    }

    /// Sets whether to search for methods that do - or do not - have an
    /// attachment.
    ///
    /// Do not specify to search for both.
    pub fn has_attachment(mut self, has_attachment: bool) -> Self {
        self.0.insert("has_attachment", has_attachment.to_string());

        self
    }

    /// Sets whether to search for methods that do - or do not - have an embed.
    ///
    /// Do not specify to search for both.
    pub fn has_embed(mut self, has_embed: bool) -> Self {
        self.0.insert("has_embed", has_embed.to_string());

        self
    }

    /// Sets the number of messages to retrieve _at maximum_. This can be used
    /// in conjunction with [`offset`].
    ///
    /// The minimum value is `1`. The maximum value is `25`.
    ///
    /// [`offset`]: #method.offset
    pub fn limit(mut self, limit: u8) -> Self {
        self.0.insert("limit", limit.to_string());

        self
    }

    /// Set the maximum [`Message`] Id to search up to. All messages with an Id
    /// greater than the given value will be ignored.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    pub fn max_id<M: Into<MessageId>>(mut self, message_id: M) -> Self {
        self.0.insert("max_id", message_id.into().0.to_string());

        self
    }

    /// Set the minimum [`Message`]s Id to search down to. All messages with an
    /// Id less than the given value will be ignored.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    pub fn min_id<M: Into<MessageId>>(mut self, message_id: M) -> Self {
        self.0.insert("min_id", message_id.into().0.to_string());

        self
    }

    /// Set the offset of [`Message`]s to return. This can be used in
    /// conjunction with [`limit`].
    ///
    /// The minimum value is `0`. The maximum value is `5000`.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    /// [`limit`]: #method.limit
    pub fn offset(mut self, offset: u16) -> Self {
        self.0.insert("offset", offset.to_string());

        self
    }

    /// The sorting mode to use.
    ///
    /// Refer to [`SortingMode`] for more information.
    ///
    /// [`SortingMode`]: enum.SortingMode.html
    pub fn sort_by(mut self, sorting_mode: SortingMode) -> Self {
        self.0.insert("sort_by", sorting_mode.name().to_string());

        self
    }

    /// The order to sort results by.
    ///
    /// Refer to the documentation for [`SortingOrder`] for more information.
    ///
    /// [`SortingOrder`]: enum.SortingOrder.html
    pub fn sort_order(mut self, sorting_order: SortingOrder) -> Self {
        self.0.insert("sort_order", sorting_order.name().to_string());

        self
    }
}

impl<'a> Default for Search<'a> {
    /// Creates a new builder for searching for [`Message`]s. Refer to each
    /// method to learn what minimum and maximum values are available for each
    /// field, as well as restrictions and other useful information.
    ///
    /// The library does not provide defaults differently than what Discord
    /// itself defaults to.
    ///
    /// This list of defaults is:
    ///
    /// - [`context_size`]: 2
    /// - [`limit`]: 25
    /// - [`offset`]: 0
    /// - [`sort_by`]: [`SortingMode::Timestamp`]
    ///
    /// [`SortingMode::Timestamp`]: enum.SortingMode.html#variant.Timestamp
    /// [`context_size`]: #method.context_size
    /// [`limit`]: #method.limit
    /// [`offset`]: #method.offset
    /// [`sort_by`]: #method.sort_by
    fn default<'b>() -> Search<'b> {
        Search(BTreeMap::default())
    }
}
<commit_msg>Remove lifetime on Search<commit_after>use std::collections::BTreeMap;
use ::model::{MessageId, UserId};

/// An indicator of the type of sorting mode to use when searching for
/// [`Message`]s via the [`Search`] builder.
///
/// [`Message`]: ../../model/struct.Message.html
/// [`Search`]: struct.Search.html
pub enum SortingMode {
    /// Search by messages' relevance to parameters.
    Relevance,
    /// Search by messages' timestamp, where results will match according to
    /// parameters. This is used in conjunction in the [`Search::sort_order`]
    /// method, and is used in conjunction with [`SortingOrder`].
    ///
    /// [`Search::sort_order`]: struct.Search.html#method.sort_order
    /// [`SortingOrder`]: enum.SortingOrder.html
    Timestamp,
}

impl SortingMode {
    /// Retrieves the name of the sorting mode. This is equivalent to a
    /// lowercase string version of each variant.
    pub fn name(&self) -> &str {
        match *self {
            SortingMode::Relevance => "relevance",
            SortingMode::Timestamp => "timestamp",
        }
    }
}

/// An indicator of how to sort results when searching for [`Message`]s via the
/// [`Search`] builder.
///
/// [`Message`]: ../../model/struct.Message.html
/// [`Search`]: struct.Search.html
pub enum SortingOrder {
    /// Search message results in ascending order.
    ///
    /// In the case of [`SortingMode::Relevance`], this will search from the
    /// least relevant to the most relevant.
    ///
    /// In the case of [`SortingMode::Timestamp`], this will indicate to search
    /// from the least recent to the most recent.
    ///
    /// [`SortingMode::Relevance`]: enum.SortingMode.html#variant.Relevance
    /// [`SortingMode::Timestamp`]: enum.SortingMode.html#variant.Timestamp
    Ascending,
    /// Search message results in descending order.
    ///
    /// In the case of [`SortingMode::Relevance`], this will search from the
    /// most relevant to least relevant.
    ///
    /// In the case of [`SortingMode::Timestamp`], this will search from the
    /// most recent to least recent.
    ///
    /// [`SortingMode::Relevance`]: enum.SortingMode.html#variant.Relevance
    /// [`SortingMode::Timestamp`]: enum.SortingMode.html#variant.Timestamp
    Descending,
}

impl SortingOrder {
    /// Retrieves the name of the sorting order. This is equivalent to a
    /// lowercase string version of each variant.
    pub fn name(&self) -> &str {
        match *self {
            SortingOrder::Ascending => "asc",
            SortingOrder::Descending => "desc",
        }
    }
}

/// A builder used to query a [`Channel`] or [`Guild`] for its [`Message`]s,
/// specifying certain parameters to narrow down the returned messages.
///
/// Many methods are provided to narrow down the results, such as [`sort_by`] -
/// which is used with the [`SortingMode`] enum to sort the results - or
/// [`limit`], which can be used in conjunction with [`offset`] to paginate
/// results.
///
/// # Examples
///
/// Provided are multiple in-depth examples for searching through different
/// means. Also see [example 08] for a fully runnable bot.
///
/// ### Searching a Channel
///
/// Search for messages via [`Context::search_channel`] with the content
/// `"rust"`, which have no embed, no attachment, searching by relevance in
/// ascending order, and limiting to 5 results:
///
/// ```rust,ignore
/// // assuming you are in a context
///
/// let res = context.search_channel(message.channel_id, |s| s
///     .content("rust")
///     .has_embed(false)
///     .has_attachment(false)
///     .limit(5)
///     .sort_by(SortingMode::Relevance)
///     .sort_order(SortingOrder::Ascending));
/// ```
///
/// ### Searching a Guild's Channels
///
/// Search for messages with a query provided by a user, which have an
/// embed, have no attachment, searching by timestamp in descending order,
/// limiting to 2 results, and only searching channels that have a name
/// prefixed with `"search-"`:
///
/// ```rust,ignore
/// use serenity::client::{Client, Context};
/// use serenity::model::Message;
/// use serenity::utils::builder::{SortingMode, SortingOrder};
/// use std::env;
///
/// let mut client = Client::login_bot(&env::var("DISCORD_BOT_TOKEN").unwrap());
///
/// client.with_framework(|f| f
///     .configure(|c| c.prefix("~").on_mention(true))
///     .on("search", search));
///
/// command!(search(context, message, args) {
///     let query = args.join(" ");
///
///     if query.is_empty() {
///         let _ = context.say("You must provide a query");
///
///         return Ok(());
///     }
///
///     let guild = message.guild().unwrap();
///
///     let channel_ids = guild
///         .channels
///         .values()
///         .filter(|c| c.name.starts_with("search-"))
///         .map(|c| c.id)
///         .collect();
///
///     let search = context.search_guild(guild.id, channel_ids, |s| s
///         .content(&query)
///         .context_size(0)
///         .has_attachment(true)
///         .has_embed(true)
///         .max_id(message.id.0 - 1)
///         .sort_by(SortingMode::Timestamp)
///         .sort_order(SortingOrder::Descending));
///
///     let mut messages = match search {
///         Ok(messages) => messages,
///         Err(why) => {
///             println!("Error performing search '{}': {:?}", query, why);
///
///             let _ = context.say("Error occurred while searching");
///
///             return Ok(());
///         },
///     };
///
///     let _ = context.send_message(message.channel_id, |m| m
///         .content(&format!("Found {} total results", messages.total))
///         .embed(|mut e| {
///             for (i, messages) in messages.results.iter_mut().enumerate() {
///                 let mut message = match messages.get_mut(i) {
///                     Some(message) => message,
///                     None => break,
///                 };
///
///                 message.content.truncate(1000);
///
///                 e = e.field(|f| f
///                     .name(&format!("Result {}", i))
///                     .value(&message.content));
///              }
///
///              e
///         }));
/// });
/// ```
///
/// [`Channel`]: ../../model/enum.Channel.html
/// [`Context::search_channel`]: ../../client/struct.Context.html#method.search_channel
/// [`Guild`]: ../../model/struct.Guild.html
/// [`Message`]: ../../model/struct.Message.html
/// [`SortingMode`]: enum.SortingMode.html
/// [`limit`]: #method.limit
/// [`offset`]: #method.offset
/// [`sort_by`]: #method.sort_by
/// [example 08]: https://github.com/zeyla/serenity/tree/master/examples/08_search
pub struct Search(pub BTreeMap<&'static str, String>);

impl Search {
    /// Sets the list of attachment extensions to search by.
    ///
    /// When providing a vector of extensions, do _not_ include the period (`.`)
    /// character as part of the search.
    ///
    /// This is sent to Discord as a comma-separated value list of extension
    /// names.
    pub fn attachment_extensions(mut self, attachment_extensions: &[&str]) -> Self {
        let list = attachment_extensions.join(" ");

        self.0.insert("attachment_extensions", list);

        self
    }

    /// Sets the filename of the attachments to search for.
    pub fn attachment_filename(mut self, attachment_filename: &str) -> Self {
        self.0.insert("attachment_filename", attachment_filename.to_owned());

        self
    }

    /// Sets the Id of the author of [`Message`]s to search for. This excludes
    /// all messages by other [`User`]s.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    /// [`User`]: ../../model/struct.User.html
    pub fn author_id<U: Into<UserId>>(mut self, author_id: U) -> Self {
        self.0.insert("author_id", author_id.into().0.to_string());

        self
    }

    /// Sets the content of the [`Message`] to search for. This is a fuzzy
    /// search, and can partially match the given query content.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    pub fn content(mut self, content: &str) -> Self {
        self.0.insert("content", content.to_owned());

        self
    }

    /// Sets the amount of "context" [`Message`]s to provide, at maximum. This
    /// is the number of messages to provide around each side
    /// (ascending+descending) of the "hit" (aka found) message.
    ///
    /// The default value is `2`. The minimum value is `0`. The maximum value is
    /// `2`.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    pub fn context_size(mut self, context_size: u8) -> Self {
        self.0.insert("context_size", context_size.to_string());

        self
    }

    /// Sets the embed providers to search by.
    ///
    /// This is a list of the providers' names.
    ///
    /// This is sent to Discord as a comma-separated value list of provider
    /// names.
    pub fn embed_providers(mut self, embed_providers: &[&str]) -> Self {
        self.0.insert("embed_providers", embed_providers.join(" "));

        self
    }

    /// Sets the type of [`Embed`]s to search by.
    ///
    /// An example of an [embed type][`Embed::kind`] is `"rich"`.
    ///
    /// [`Embed`]: ../../model/struct.Embed.html
    /// [`Embed::kind`]: ../../model/struct.Embed.html#structfield.kind
    pub fn embed_types(mut self, embed_types: &[&str]) -> Self {
        self.0.insert("embed_types", embed_types.join(" "));

        self
    }

    /// Sets whether to search for methods that do - or do not - have an
    /// attachment.
    ///
    /// Do not specify to search for both.
    pub fn has_attachment(mut self, has_attachment: bool) -> Self {
        self.0.insert("has_attachment", has_attachment.to_string());

        self
    }

    /// Sets whether to search for methods that do - or do not - have an embed.
    ///
    /// Do not specify to search for both.
    pub fn has_embed(mut self, has_embed: bool) -> Self {
        self.0.insert("has_embed", has_embed.to_string());

        self
    }

    /// Sets the number of messages to retrieve _at maximum_. This can be used
    /// in conjunction with [`offset`].
    ///
    /// The minimum value is `1`. The maximum value is `25`.
    ///
    /// [`offset`]: #method.offset
    pub fn limit(mut self, limit: u8) -> Self {
        self.0.insert("limit", limit.to_string());

        self
    }

    /// Set the maximum [`Message`] Id to search up to. All messages with an Id
    /// greater than the given value will be ignored.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    pub fn max_id<M: Into<MessageId>>(mut self, message_id: M) -> Self {
        self.0.insert("max_id", message_id.into().0.to_string());

        self
    }

    /// Set the minimum [`Message`]s Id to search down to. All messages with an
    /// Id less than the given value will be ignored.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    pub fn min_id<M: Into<MessageId>>(mut self, message_id: M) -> Self {
        self.0.insert("min_id", message_id.into().0.to_string());

        self
    }

    /// Set the offset of [`Message`]s to return. This can be used in
    /// conjunction with [`limit`].
    ///
    /// The minimum value is `0`. The maximum value is `5000`.
    ///
    /// [`Message`]: ../../model/struct.Message.html
    /// [`limit`]: #method.limit
    pub fn offset(mut self, offset: u16) -> Self {
        self.0.insert("offset", offset.to_string());

        self
    }

    /// The sorting mode to use.
    ///
    /// Refer to [`SortingMode`] for more information.
    ///
    /// [`SortingMode`]: enum.SortingMode.html
    pub fn sort_by(mut self, sorting_mode: SortingMode) -> Self {
        self.0.insert("sort_by", sorting_mode.name().to_string());

        self
    }

    /// The order to sort results by.
    ///
    /// Refer to the documentation for [`SortingOrder`] for more information.
    ///
    /// [`SortingOrder`]: enum.SortingOrder.html
    pub fn sort_order(mut self, sorting_order: SortingOrder) -> Self {
        self.0.insert("sort_order", sorting_order.name().to_string());

        self
    }
}

impl Default for Search {
    /// Creates a new builder for searching for [`Message`]s. Refer to each
    /// method to learn what minimum and maximum values are available for each
    /// field, as well as restrictions and other useful information.
    ///
    /// The library does not provide defaults differently than what Discord
    /// itself defaults to.
    ///
    /// This list of defaults is:
    ///
    /// - [`context_size`]: 2
    /// - [`limit`]: 25
    /// - [`offset`]: 0
    /// - [`sort_by`]: [`SortingMode::Timestamp`]
    ///
    /// [`SortingMode::Timestamp`]: enum.SortingMode.html#variant.Timestamp
    /// [`context_size`]: #method.context_size
    /// [`limit`]: #method.limit
    /// [`offset`]: #method.offset
    /// [`sort_by`]: #method.sort_by
    fn default() -> Search {
        Search(BTreeMap::default())
    }
}
<|endoftext|>


<commit_before>type Deadlock = Option<uint>;

static mut lock: Deadlock = None;
static mut anotherLock: Deadlock = None;

fn grab_lock(id: uint) {
    unsafe {
	while (lock.is_some()) {
	    ;
	}
	lock = Some(id);
    }
}

fn grab_anotherLock(id: uint) {
    unsafe {
	while (anotherLock.is_some()) {
	    ;
	}
	anotherLock = Some(id);
    }
}

fn release_lock() {
    unsafe {
	lock = None;
    }
}

fn release_anotherLock() {
    unsafe {
	anotherLock = None;
    }
}

fn update_process_1(id: uint) {
    grab_lock(id);
    println("Process 1 grabbed lock 1");
    grab_anotherLock(id);
    println("Process 1 grabbed lock 2");
    release_lock();
    release_anotherLock();
}

fn update_process_2(id: uint) {
    grab_anotherLock(id);
    println("Process 2 grabbed lock 2");
    grab_lock(id);
    println("Process 2 grabbed lock 1");
    release_anotherLock();
    release_lock();
}

fn main() {
    let mut i: uint = 0;
    while i < 10000 {
	do spawn {
	    update_process_1(1);
	}
	do spawn {
	    update_process_2(2);
	}
	i += 1;
    }
}
<commit_msg>with sleep<commit_after>type Deadlock = Option<uint>;

static mut lock: Deadlock = None;
static mut anotherLock: Deadlock = None;

fn grab_lock(id: uint) {
    unsafe {
	while (lock.is_some()) {
	    ;
	}
	lock = Some(id);
    }
}

fn grab_anotherLock(id: uint) {
    unsafe {
	while (anotherLock.is_some()) {
	    ;
	}
	anotherLock = Some(id);
    }
}

fn release_lock() {
    unsafe {
	lock = None;
    }
}

fn release_anotherLock() {
    unsafe {
	anotherLock = None;
    }
}

fn update_process_1(id: uint) {
    grab_lock(id);
    println("Process 1 grabbed lock 1");
    std::rt::io::timer::sleep(1000);
    grab_anotherLock(id);
    println("Process 1 grabbed lock 2");
    release_lock();
    release_anotherLock();
}

fn update_process_2(id: uint) {
    grab_anotherLock(id);
    println("Process 2 grabbed lock 2");
    grab_lock(id);
    println("Process 2 grabbed lock 1");
    release_anotherLock();
    release_lock();
}

fn main() {
    do spawn {
	update_process_1(1);
    }
    do spawn {
	update_process_2(2);
    }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

extern crate regex;

use crate::common::util::*;

extern crate stat;
pub use self::stat::*;

#[test]
fn test_scanners() {
    assert_eq!(Some((-5, 2)), "-5zxc".scan_num::<i32>());
    assert_eq!(Some((51, 2)), "51zxc".scan_num::<u32>());
    assert_eq!(Some((192, 4)), "+192zxc".scan_num::<i32>());
    assert_eq!(None, "z192zxc".scan_num::<i32>());

    assert_eq!(Some(('a', 3)), "141zxc".scan_char(8));
    assert_eq!(Some(('\n', 2)), "12qzxc".scan_char(8)); // spell-checker:disable-line
    assert_eq!(Some(('\r', 1)), "dqzxc".scan_char(16)); // spell-checker:disable-line
    assert_eq!(None, "z2qzxc".scan_char(8)); // spell-checker:disable-line
}

#[test]
fn test_group_num() {
    assert_eq!("12,379,821,234", group_num("12379821234"));
    assert_eq!("21,234", group_num("21234"));
    assert_eq!("821,234", group_num("821234"));
    assert_eq!("1,821,234", group_num("1821234"));
    assert_eq!("1,234", group_num("1234"));
    assert_eq!("234", group_num("234"));
    assert_eq!("24", group_num("24"));
    assert_eq!("4", group_num("4"));
    assert_eq!("", group_num(""));
    assert_eq!("-5", group_num("-5"));
    assert_eq!("-1,234", group_num("-1234"));
}

#[test]
#[should_panic]
fn test_group_num_panic_if_invalid_numeric_characters() {
    group_num("³³³³³");
}

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

    #[test]
    fn normal_format() {
        let s = "%'010.2ac%-#5.w\n";
        let expected = vec![
            Token::Directive {
                flag: F_GROUP | F_ZERO,
                width: 10,
                precision: 2,
                format: 'a',
            },
            Token::Char('c'),
            Token::Directive {
                flag: F_LEFT | F_ALTER,
                width: 5,
                precision: 0,
                format: 'w',
            },
            Token::Char('\n'),
        ];
        assert_eq!(&expected, &Stater::generate_tokens(s, false).unwrap());
    }

    #[test]
    fn printf_format() {
        let s = "%-# 15a\\t\\r\\\"\\\\\\a\\b\\e\\f\\v%+020.-23w\\x12\\167\\132\\112\\n";
        let expected = vec![
            Token::Directive {
                flag: F_LEFT | F_ALTER | F_SPACE,
                width: 15,
                precision: -1,
                format: 'a',
            },
            Token::Char('\t'),
            Token::Char('\r'),
            Token::Char('"'),
            Token::Char('\\'),
            Token::Char('\x07'),
            Token::Char('\x08'),
            Token::Char('\x1B'),
            Token::Char('\x0C'),
            Token::Char('\x0B'),
            Token::Directive {
                flag: F_SIGN | F_ZERO,
                width: 20,
                precision: -1,
                format: 'w',
            },
            Token::Char('\x12'),
            Token::Char('w'),
            Token::Char('Z'),
            Token::Char('J'),
            Token::Char('\n'),
        ];
        assert_eq!(&expected, &Stater::generate_tokens(s, true).unwrap());
    }
}

#[test]
fn test_invalid_option() {
    new_ucmd!().arg("-w").arg("-q").arg("/").fails();
}

#[cfg(unix)]
const NORMAL_FORMAT_STR: &str =
    "%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s %u %U %x %X %y %Y %z %Z"; // avoid "%w %W" (birth/creation) due to `stat` limitations and linux kernel & rust version capability variations
#[cfg(any(target_os = "linux", target_os = "android"))]
const DEV_FORMAT_STR: &str =
    "%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s (%t/%T) %u %U %w %W %x %X %y %Y %z %Z";
#[cfg(target_os = "linux")]
const FS_FORMAT_STR: &str = "%b %c %i %l %n %s %S %t %T"; // avoid "%a %d %f" which can cause test failure due to race conditions

#[test]
#[cfg(any(target_os = "linux", target_os = "android"))]
fn test_terse_fs_format() {
    let args = ["-f", "-t", "/proc"];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).run().stdout_is(expected_stdout);
}

#[test]
#[cfg(target_os = "linux")]
fn test_fs_format() {
    let args = ["-f", "-c", FS_FORMAT_STR, "/dev/shm"];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).run().stdout_is(expected_stdout);
}

#[cfg(unix)]
#[test]
fn test_terse_normal_format() {
    // note: contains birth/creation date which increases test fragility
    // * results may vary due to built-in `stat` limitations as well as linux kernel and rust version capability variations
    let args = ["-t", "/"];
    let ts = TestScenario::new(util_name!());
    let actual = ts.ucmd().args(&args).succeeds().stdout_move_str();
    let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    let v_actual: Vec<&str> = actual.trim().split(' ').collect();
    let mut v_expect: Vec<&str> = expect.trim().split(' ').collect();
    assert!(!v_expect.is_empty());

    // uu_stat does not support selinux
    if v_actual.len() == v_expect.len() - 1 && v_expect[v_expect.len() - 1].contains(':') {
        // assume last element contains: `SELinux security context string`
        v_expect.pop();
    }

    // * allow for inequality if `stat` (aka, expect) returns "0" (unknown value)
    assert!(
        expect == "0"
            || expect == "0\n"
            || v_actual
                .iter()
                .zip(v_expect.iter())
                .all(|(a, e)| a == e || *e == "0" || *e == "0\n")
    );
}

#[cfg(unix)]
#[test]
fn test_format_created_time() {
    let args = ["-c", "%w", "/bin"];
    let ts = TestScenario::new(util_name!());
    let actual = ts.ucmd().args(&args).succeeds().stdout_move_str();
    let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    // note: using a regex instead of `split_whitespace()` in order to detect whitespace differences
    let re = regex::Regex::new(r"\s").unwrap();
    let v_actual: Vec<&str> = re.split(&actual).collect();
    let v_expect: Vec<&str> = re.split(&expect).collect();
    assert!(!v_expect.is_empty());
    // * allow for inequality if `stat` (aka, expect) returns "-" (unknown value)
    assert!(
        expect == "-"
            || expect == "-\n"
            || v_actual
                .iter()
                .zip(v_expect.iter())
                .all(|(a, e)| a == e || *e == "-" || *e == "-\n")
    );
}

#[cfg(unix)]
#[test]
fn test_format_created_seconds() {
    let args = ["-c", "%W", "/bin"];
    let ts = TestScenario::new(util_name!());
    let actual = ts.ucmd().args(&args).succeeds().stdout_move_str();
    let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    // note: using a regex instead of `split_whitespace()` in order to detect whitespace differences
    let re = regex::Regex::new(r"\s").unwrap();
    let v_actual: Vec<&str> = re.split(&actual).collect();
    let v_expect: Vec<&str> = re.split(&expect).collect();
    assert!(!v_expect.is_empty());
    // * allow for inequality if `stat` (aka, expect) returns "0" (unknown value)
    assert!(
        expect == "0"
            || expect == "0\n"
            || v_actual
                .iter()
                .zip(v_expect.iter())
                .all(|(a, e)| a == e || *e == "0" || *e == "0\n")
    );
}

#[cfg(unix)]
#[test]
fn test_normal_format() {
    let args = ["-c", NORMAL_FORMAT_STR, "/bin"];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
}

#[cfg(unix)]
#[test]
fn test_symlinks() {
    let ts = TestScenario::new(util_name!());
    let at = &ts.fixtures;

    let mut tested: bool = false;
    // arbitrarily chosen symlinks with hope that the CI environment provides at least one of them
    for file in [
        "/bin/sh",
        "/data/data/com.termux/files/usr/bin/sh", // spell-checker:disable-line
        "/bin/sudoedit",
        "/usr/bin/ex",
        "/etc/localtime",
        "/etc/aliases",
    ] {
        if at.file_exists(file) && at.is_symlink(file) {
            tested = true;
            let args = ["-c", NORMAL_FORMAT_STR, file];
            let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
            ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
            // -L, --dereference    follow links
            let args = ["-L", "-c", NORMAL_FORMAT_STR, file];
            let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
            ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
        }
    }
    if !tested {
        panic!("No symlink found to test in this environment");
    }
}

#[cfg(any(target_os = "linux", target_os = "android", target_vendor = "apple"))]
#[test]
fn test_char() {
    // TODO: "(%t) (%x) (%w)" deviate from GNU stat for `character special file` on macOS
    // Diff < left / right > :
    // <"(f0000) (2021-05-20 23:08:03.442555000 +0200) (1970-01-01 01:00:00.000000000 +0100)\n"
    // >"(f) (2021-05-20 23:08:03.455598000 +0200) (-)\n"
    let args = [
        "-c",
        #[cfg(any(target_os = "linux", target_os = "android"))]
        DEV_FORMAT_STR,
        #[cfg(target_os = "linux")]
        "/dev/pts/ptmx",
        #[cfg(any(target_vendor = "apple"))]
        "%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s (/%T) %u %U %W %X %y %Y %z %Z",
        #[cfg(any(target_os = "android", target_vendor = "apple"))]
        "/dev/ptmx",
    ];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
}

#[cfg(unix)]
#[test]
fn test_multi_files() {
    let args = [
        "-c",
        NORMAL_FORMAT_STR,
        "/dev",
        "/usr/lib",
        #[cfg(target_os = "linux")]
        "/etc/fstab",
        "/var",
    ];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
}

#[cfg(unix)]
#[test]
fn test_printf() {
    let args = [
        "--printf=123%-# 15q\\r\\\"\\\\\\a\\b\\e\\f\\v%+020.23m\\x12\\167\\132\\112\\n",
        "/",
    ];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
}
<commit_msg>stat: add a test to verify time easily<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

extern crate regex;

use crate::common::util::*;

extern crate stat;
pub use self::stat::*;

#[test]
fn test_scanners() {
    assert_eq!(Some((-5, 2)), "-5zxc".scan_num::<i32>());
    assert_eq!(Some((51, 2)), "51zxc".scan_num::<u32>());
    assert_eq!(Some((192, 4)), "+192zxc".scan_num::<i32>());
    assert_eq!(None, "z192zxc".scan_num::<i32>());

    assert_eq!(Some(('a', 3)), "141zxc".scan_char(8));
    assert_eq!(Some(('\n', 2)), "12qzxc".scan_char(8)); // spell-checker:disable-line
    assert_eq!(Some(('\r', 1)), "dqzxc".scan_char(16)); // spell-checker:disable-line
    assert_eq!(None, "z2qzxc".scan_char(8)); // spell-checker:disable-line
}

#[test]
fn test_group_num() {
    assert_eq!("12,379,821,234", group_num("12379821234"));
    assert_eq!("21,234", group_num("21234"));
    assert_eq!("821,234", group_num("821234"));
    assert_eq!("1,821,234", group_num("1821234"));
    assert_eq!("1,234", group_num("1234"));
    assert_eq!("234", group_num("234"));
    assert_eq!("24", group_num("24"));
    assert_eq!("4", group_num("4"));
    assert_eq!("", group_num(""));
    assert_eq!("-5", group_num("-5"));
    assert_eq!("-1,234", group_num("-1234"));
}

#[test]
#[should_panic]
fn test_group_num_panic_if_invalid_numeric_characters() {
    group_num("³³³³³");
}

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

    #[test]
    fn normal_format() {
        let s = "%'010.2ac%-#5.w\n";
        let expected = vec![
            Token::Directive {
                flag: F_GROUP | F_ZERO,
                width: 10,
                precision: 2,
                format: 'a',
            },
            Token::Char('c'),
            Token::Directive {
                flag: F_LEFT | F_ALTER,
                width: 5,
                precision: 0,
                format: 'w',
            },
            Token::Char('\n'),
        ];
        assert_eq!(&expected, &Stater::generate_tokens(s, false).unwrap());
    }

    #[test]
    fn printf_format() {
        let s = "%-# 15a\\t\\r\\\"\\\\\\a\\b\\e\\f\\v%+020.-23w\\x12\\167\\132\\112\\n";
        let expected = vec![
            Token::Directive {
                flag: F_LEFT | F_ALTER | F_SPACE,
                width: 15,
                precision: -1,
                format: 'a',
            },
            Token::Char('\t'),
            Token::Char('\r'),
            Token::Char('"'),
            Token::Char('\\'),
            Token::Char('\x07'),
            Token::Char('\x08'),
            Token::Char('\x1B'),
            Token::Char('\x0C'),
            Token::Char('\x0B'),
            Token::Directive {
                flag: F_SIGN | F_ZERO,
                width: 20,
                precision: -1,
                format: 'w',
            },
            Token::Char('\x12'),
            Token::Char('w'),
            Token::Char('Z'),
            Token::Char('J'),
            Token::Char('\n'),
        ];
        assert_eq!(&expected, &Stater::generate_tokens(s, true).unwrap());
    }
}

#[test]
fn test_invalid_option() {
    new_ucmd!().arg("-w").arg("-q").arg("/").fails();
}

#[cfg(unix)]
const NORMAL_FORMAT_STR: &str =
    "%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s %u %U %x %X %y %Y %z %Z"; // avoid "%w %W" (birth/creation) due to `stat` limitations and linux kernel & rust version capability variations
#[cfg(any(target_os = "linux", target_os = "android"))]
const DEV_FORMAT_STR: &str =
    "%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s (%t/%T) %u %U %w %W %x %X %y %Y %z %Z";
#[cfg(target_os = "linux")]
const FS_FORMAT_STR: &str = "%b %c %i %l %n %s %S %t %T"; // avoid "%a %d %f" which can cause test failure due to race conditions

#[test]
#[cfg(any(target_os = "linux", target_os = "android"))]
fn test_terse_fs_format() {
    let args = ["-f", "-t", "/proc"];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).run().stdout_is(expected_stdout);
}

#[test]
#[cfg(target_os = "linux")]
fn test_fs_format() {
    let args = ["-f", "-c", FS_FORMAT_STR, "/dev/shm"];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).run().stdout_is(expected_stdout);
}

#[cfg(unix)]
#[test]
fn test_terse_normal_format() {
    // note: contains birth/creation date which increases test fragility
    // * results may vary due to built-in `stat` limitations as well as linux kernel and rust version capability variations
    let args = ["-t", "/"];
    let ts = TestScenario::new(util_name!());
    let actual = ts.ucmd().args(&args).succeeds().stdout_move_str();
    let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    let v_actual: Vec<&str> = actual.trim().split(' ').collect();
    let mut v_expect: Vec<&str> = expect.trim().split(' ').collect();
    assert!(!v_expect.is_empty());

    // uu_stat does not support selinux
    if v_actual.len() == v_expect.len() - 1 && v_expect[v_expect.len() - 1].contains(':') {
        // assume last element contains: `SELinux security context string`
        v_expect.pop();
    }

    // * allow for inequality if `stat` (aka, expect) returns "0" (unknown value)
    assert!(
        expect == "0"
            || expect == "0\n"
            || v_actual
                .iter()
                .zip(v_expect.iter())
                .all(|(a, e)| a == e || *e == "0" || *e == "0\n")
    );
}

#[cfg(unix)]
#[test]
fn test_format_created_time() {
    let args = ["-c", "%w", "/bin"];
    let ts = TestScenario::new(util_name!());
    let actual = ts.ucmd().args(&args).succeeds().stdout_move_str();
    let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    // note: using a regex instead of `split_whitespace()` in order to detect whitespace differences
    let re = regex::Regex::new(r"\s").unwrap();
    let v_actual: Vec<&str> = re.split(&actual).collect();
    let v_expect: Vec<&str> = re.split(&expect).collect();
    assert!(!v_expect.is_empty());
    // * allow for inequality if `stat` (aka, expect) returns "-" (unknown value)
    assert!(
        expect == "-"
            || expect == "-\n"
            || v_actual
                .iter()
                .zip(v_expect.iter())
                .all(|(a, e)| a == e || *e == "-" || *e == "-\n")
    );
}

#[cfg(unix)]
#[test]
fn test_format_created_seconds() {
    let args = ["-c", "%W", "/bin"];
    let ts = TestScenario::new(util_name!());
    let actual = ts.ucmd().args(&args).succeeds().stdout_move_str();
    let expect = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    // note: using a regex instead of `split_whitespace()` in order to detect whitespace differences
    let re = regex::Regex::new(r"\s").unwrap();
    let v_actual: Vec<&str> = re.split(&actual).collect();
    let v_expect: Vec<&str> = re.split(&expect).collect();
    assert!(!v_expect.is_empty());
    // * allow for inequality if `stat` (aka, expect) returns "0" (unknown value)
    assert!(
        expect == "0"
            || expect == "0\n"
            || v_actual
                .iter()
                .zip(v_expect.iter())
                .all(|(a, e)| a == e || *e == "0" || *e == "0\n")
    );
}

#[cfg(unix)]
#[test]
fn test_normal_format() {
    let args = ["-c", NORMAL_FORMAT_STR, "/bin"];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
}

#[cfg(unix)]
#[test]
fn test_symlinks() {
    let ts = TestScenario::new(util_name!());
    let at = &ts.fixtures;

    let mut tested: bool = false;
    // arbitrarily chosen symlinks with hope that the CI environment provides at least one of them
    for file in [
        "/bin/sh",
        "/data/data/com.termux/files/usr/bin/sh", // spell-checker:disable-line
        "/bin/sudoedit",
        "/usr/bin/ex",
        "/etc/localtime",
        "/etc/aliases",
    ] {
        if at.file_exists(file) && at.is_symlink(file) {
            tested = true;
            let args = ["-c", NORMAL_FORMAT_STR, file];
            let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
            ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
            // -L, --dereference    follow links
            let args = ["-L", "-c", NORMAL_FORMAT_STR, file];
            let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
            ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
        }
    }
    if !tested {
        panic!("No symlink found to test in this environment");
    }
}

#[cfg(any(target_os = "linux", target_os = "android", target_vendor = "apple"))]
#[test]
fn test_char() {
    // TODO: "(%t) (%x) (%w)" deviate from GNU stat for `character special file` on macOS
    // Diff < left / right > :
    // <"(f0000) (2021-05-20 23:08:03.442555000 +0200) (1970-01-01 01:00:00.000000000 +0100)\n"
    // >"(f) (2021-05-20 23:08:03.455598000 +0200) (-)\n"
    let args = [
        "-c",
        #[cfg(any(target_os = "linux", target_os = "android"))]
        DEV_FORMAT_STR,
        #[cfg(target_os = "linux")]
        "/dev/pts/ptmx",
        #[cfg(any(target_vendor = "apple"))]
        "%a %A %b %B %d %D %f %F %g %G %h %i %m %n %o %s (/%T) %u %U %W %X %y %Y %z %Z",
        #[cfg(any(target_os = "android", target_vendor = "apple"))]
        "/dev/ptmx",
    ];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
}

#[cfg(any(target_os = "linux", target_os = "android", target_vendor = "apple"))]
#[test]
fn test_date() {
    // Just test the date for the time 0.3 change
    let args = [
        "-c",
        #[cfg(any(target_os = "linux", target_os = "android"))]
        "%z",
        #[cfg(target_os = "linux")]
        "/dev/pts/ptmx",
        #[cfg(any(target_vendor = "apple"))]
        "%z",
        #[cfg(any(target_os = "android", target_vendor = "apple"))]
        "/dev/ptmx",
    ];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
}
#[cfg(unix)]
#[test]
fn test_multi_files() {
    let args = [
        "-c",
        NORMAL_FORMAT_STR,
        "/dev",
        "/usr/lib",
        #[cfg(target_os = "linux")]
        "/etc/fstab",
        "/var",
    ];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
}

#[cfg(unix)]
#[test]
fn test_printf() {
    let args = [
        "--printf=123%-# 15q\\r\\\"\\\\\\a\\b\\e\\f\\v%+020.23m\\x12\\167\\132\\112\\n",
        "/",
    ];
    let ts = TestScenario::new(util_name!());
    let expected_stdout = unwrap_or_return!(expected_result(&ts, &args)).stdout_move_str();
    ts.ucmd().args(&args).succeeds().stdout_is(expected_stdout);
}
<|endoftext|>


<commit_before>#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum Foo {
    A(&'static str),
    _B,
    _C,
}

pub fn main() {
    let mut b = std::collections::BTreeSet::new();
    b.insert(Foo::A("\'"));
    b.insert(Foo::A("/="));
    b.insert(Foo::A("#"));
    b.insert(Foo::A("0o"));
}
<commit_msg>Mir validation can't cope with `mem::uninitialized::<SomeEnum>()`<commit_after>// mir validation can't cope with `mem::uninitialized::<SomeEnum>()`
// compile-flags: -Zmir-emit-validate=0

#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum Foo {
    A(&'static str),
    _B,
    _C,
}

pub fn main() {
    let mut b = std::collections::BTreeSet::new();
    b.insert(Foo::A("\'"));
    b.insert(Foo::A("/="));
    b.insert(Foo::A("#"));
    b.insert(Foo::A("0o"));
}
<|endoftext|>


<commit_before>use std::str::raw::c_str_to_static_slice;
use libc::{c_char, c_void, ptrdiff_t, size_t};

pub enum Object { }

pub struct Sel {
	ptr: *const c_void,
}

pub struct Ivar {
	ptr: *const c_void,
}

pub struct Class {
	ptr: *mut Object,
}

pub type Imp = extern fn(*mut Object, Sel, ...) -> *mut Object;

#[link(name = "Foundation", kind = "framework")]
extern {
	pub fn sel_registerName(name: *const c_char) -> Sel;
	pub fn sel_getName(sel: Sel) -> *const c_char;

	pub fn objc_getClass(name: *const c_char) -> Class;
	pub fn class_getName(cls: Class) -> *const c_char;
	pub fn class_getInstanceSize(cls: Class) -> size_t;
	pub fn class_getInstanceVariable(cls: Class, name: *const c_char) -> Ivar;
	pub fn class_addMethod(cls: Class, name: Sel, imp: Imp, types: *const c_char) -> bool;
	pub fn class_addIvar(cls: Class, name: *const c_char, size: size_t, alignment: u8, types: *const c_char) -> bool;

	pub fn objc_allocateClassPair(superclass: Class, name: *const c_char, extraBytes: size_t) -> Class;
	pub fn objc_disposeClassPair(cls: Class);
	pub fn objc_registerClassPair(cls: Class);

	pub fn object_setInstanceVariable(obj: *mut Object, name: *const c_char, value: *mut c_void) -> Ivar;
	pub fn object_getInstanceVariable(obj: *mut Object, name: *const c_char, outValue: *mut *mut c_void) -> Ivar;
	pub fn object_setIvar(obj: *mut Object, ivar: Ivar, value: *mut Object);
	pub fn object_getIvar(obj: *mut Object, ivar: Ivar) -> *mut Object;
	pub fn object_getClass(obj: *mut Object) -> Class;

	pub fn ivar_getName(ivar: Ivar) -> *const c_char;
	pub fn ivar_getOffset(ivar: Ivar) -> ptrdiff_t;
	pub fn ivar_getTypeEncoding(ivar: Ivar) -> *const c_char;

	pub fn objc_msgSend(obj: *mut Object, op: Sel, ...) -> *mut Object;
}

impl Sel {
	pub fn register(name: &str) -> Sel {
		name.with_c_str(|name| unsafe {
			sel_registerName(name)
		})
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = sel_getName(*self);
			c_str_to_static_slice(name)
		}
	}
}

impl PartialEq for Sel {
	fn eq(&self, other: &Sel) -> bool {
		self.ptr == other.ptr
	}
}

impl Eq for Sel { }

impl Ivar {
	pub fn name(&self) -> &str {
		unsafe {
			let name = ivar_getName(*self);
			c_str_to_static_slice(name)
		}
	}

	pub fn offset(&self) -> int {
		let offset = unsafe {
			ivar_getOffset(*self)
		};
		offset as int
	}

	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = ivar_getName(*self);
			c_str_to_static_slice(encoding)
		}
	}
}

impl Object {
	unsafe fn get_ivar_ptr<T>(obj: *mut Object, name: &str) -> *mut T {
		if obj.is_null() {
			RawPtr::null()
		} else {
			let ivar = name.with_c_str(|name| {
				object_getInstanceVariable(obj, name, RawPtr::null())
			});
			let bytes = obj as *mut u8;
			let offset = ivar.offset();
			bytes.offset(offset) as *mut T
		}
	}

	pub unsafe fn get_ivar<T>(&self, name: &str) -> &T {
		let obj = self as *const Object as *mut Object;
		&*Object::get_ivar_ptr(obj, name)
	}

	pub unsafe fn get_mut_ivar<T>(&mut self, name: &str) -> &mut T {
		&mut *Object::get_ivar_ptr(self, name)
	}

	pub unsafe fn set_ivar<T>(&mut self, name: &str, value: T) {
		*self.get_mut_ivar::<T>(name) = value;
	}
}

impl Class {
	pub fn get(name: &str) -> Option<Class> {
		let cls = name.with_c_str(|name| unsafe {
			objc_getClass(name)
		});
		if cls.ptr.is_null() {
			None
		} else {
			Some(cls)
		}
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = class_getName(*self);
			c_str_to_static_slice(name)
		}
	}

	pub fn instance_size(&self) -> uint {
		unsafe {
			class_getInstanceSize(*self) as uint
		}
	}

	pub fn instance_variable(&self, name: &str) -> Option<Ivar> {
		let ivar = name.with_c_str(|name| unsafe {
			class_getInstanceVariable(*self, name)
		});
		if ivar.ptr.is_null() {
			None
		} else {
			Some(ivar)
		}
	}
}

pub trait Message { }

impl Message for Object { }

pub trait ToMessage {
	fn as_ptr(&self) -> *mut Object;

	fn is_nil(&self) -> bool {
		self.as_ptr().is_null()
	}
}

impl<T: Message> ToMessage for *mut T {
	fn as_ptr(&self) -> *mut Object {
		*self as *mut Object
	}
}

impl<'a, T: Message> ToMessage for &'a T {
	fn as_ptr(&self) -> *mut Object {
		(*self as *const T as *mut T).as_ptr()
	}
}

impl ToMessage for Class {
	fn as_ptr(&self) -> *mut Object {
		self.ptr
	}
}
<commit_msg>Added instance_variables method to Class.<commit_after>use std::slice::raw::buf_as_slice;
use std::str::raw::c_str_to_static_slice;
use libc::{c_char, c_uint, c_void, ptrdiff_t, size_t};
use libc;

pub enum Object { }

pub struct Sel {
	ptr: *const c_void,
}

pub struct Ivar {
	ptr: *const c_void,
}

pub struct Class {
	ptr: *mut Object,
}

pub type Imp = extern fn(*mut Object, Sel, ...) -> *mut Object;

#[link(name = "Foundation", kind = "framework")]
extern {
	pub fn sel_registerName(name: *const c_char) -> Sel;
	pub fn sel_getName(sel: Sel) -> *const c_char;

	pub fn objc_getClass(name: *const c_char) -> Class;
	pub fn class_getName(cls: Class) -> *const c_char;
	pub fn class_getInstanceSize(cls: Class) -> size_t;
	pub fn class_getInstanceVariable(cls: Class, name: *const c_char) -> Ivar;
	pub fn class_copyIvarList(cls: Class, outCount: *mut c_uint) -> *mut Ivar;
	pub fn class_addMethod(cls: Class, name: Sel, imp: Imp, types: *const c_char) -> bool;
	pub fn class_addIvar(cls: Class, name: *const c_char, size: size_t, alignment: u8, types: *const c_char) -> bool;

	pub fn objc_allocateClassPair(superclass: Class, name: *const c_char, extraBytes: size_t) -> Class;
	pub fn objc_disposeClassPair(cls: Class);
	pub fn objc_registerClassPair(cls: Class);

	pub fn object_setInstanceVariable(obj: *mut Object, name: *const c_char, value: *mut c_void) -> Ivar;
	pub fn object_getInstanceVariable(obj: *mut Object, name: *const c_char, outValue: *mut *mut c_void) -> Ivar;
	pub fn object_setIvar(obj: *mut Object, ivar: Ivar, value: *mut Object);
	pub fn object_getIvar(obj: *mut Object, ivar: Ivar) -> *mut Object;
	pub fn object_getClass(obj: *mut Object) -> Class;

	pub fn ivar_getName(ivar: Ivar) -> *const c_char;
	pub fn ivar_getOffset(ivar: Ivar) -> ptrdiff_t;
	pub fn ivar_getTypeEncoding(ivar: Ivar) -> *const c_char;

	pub fn objc_msgSend(obj: *mut Object, op: Sel, ...) -> *mut Object;
}

impl Sel {
	pub fn register(name: &str) -> Sel {
		name.with_c_str(|name| unsafe {
			sel_registerName(name)
		})
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = sel_getName(*self);
			c_str_to_static_slice(name)
		}
	}
}

impl PartialEq for Sel {
	fn eq(&self, other: &Sel) -> bool {
		self.ptr == other.ptr
	}
}

impl Eq for Sel { }

impl Clone for Sel {
	fn clone(&self) -> Sel { *self }
}

impl Ivar {
	pub fn name(&self) -> &str {
		unsafe {
			let name = ivar_getName(*self);
			c_str_to_static_slice(name)
		}
	}

	pub fn offset(&self) -> int {
		let offset = unsafe {
			ivar_getOffset(*self)
		};
		offset as int
	}

	pub fn type_encoding(&self) -> &str {
		unsafe {
			let encoding = ivar_getName(*self);
			c_str_to_static_slice(encoding)
		}
	}
}

impl Clone for Ivar {
	fn clone(&self) -> Ivar { *self }
}

impl Object {
	unsafe fn get_ivar_ptr<T>(obj: *mut Object, name: &str) -> *mut T {
		if obj.is_null() {
			RawPtr::null()
		} else {
			let ivar = name.with_c_str(|name| {
				object_getInstanceVariable(obj, name, RawPtr::null())
			});
			let bytes = obj as *mut u8;
			let offset = ivar.offset();
			bytes.offset(offset) as *mut T
		}
	}

	pub unsafe fn get_ivar<T>(&self, name: &str) -> &T {
		let obj = self as *const Object as *mut Object;
		&*Object::get_ivar_ptr(obj, name)
	}

	pub unsafe fn get_mut_ivar<T>(&mut self, name: &str) -> &mut T {
		&mut *Object::get_ivar_ptr(self, name)
	}

	pub unsafe fn set_ivar<T>(&mut self, name: &str, value: T) {
		*self.get_mut_ivar::<T>(name) = value;
	}
}

impl Class {
	pub fn get(name: &str) -> Option<Class> {
		let cls = name.with_c_str(|name| unsafe {
			objc_getClass(name)
		});
		if cls.ptr.is_null() {
			None
		} else {
			Some(cls)
		}
	}

	pub fn name(&self) -> &str {
		unsafe {
			let name = class_getName(*self);
			c_str_to_static_slice(name)
		}
	}

	pub fn instance_size(&self) -> uint {
		unsafe {
			class_getInstanceSize(*self) as uint
		}
	}

	pub fn instance_variable(&self, name: &str) -> Option<Ivar> {
		let ivar = name.with_c_str(|name| unsafe {
			class_getInstanceVariable(*self, name)
		});
		if ivar.ptr.is_null() {
			None
		} else {
			Some(ivar)
		}
	}

	pub fn instance_variables(&self) -> Vec<Ivar> {
		unsafe {
			let mut count: c_uint = 0;
			let ivars = class_copyIvarList(*self, &mut count) as *const Ivar;
			let vec = buf_as_slice(ivars, count as uint, |ivars| {
				ivars.to_vec()
			});
			libc::free(ivars as *mut c_void);
			vec
		}
	}
}

impl Clone for Class {
	fn clone(&self) -> Class { *self }
}

pub trait Message { }

impl Message for Object { }

pub trait ToMessage {
	fn as_ptr(&self) -> *mut Object;

	fn is_nil(&self) -> bool {
		self.as_ptr().is_null()
	}
}

impl<T: Message> ToMessage for *mut T {
	fn as_ptr(&self) -> *mut Object {
		*self as *mut Object
	}
}

impl<'a, T: Message> ToMessage for &'a T {
	fn as_ptr(&self) -> *mut Object {
		(*self as *const T as *mut T).as_ptr()
	}
}

impl ToMessage for Class {
	fn as_ptr(&self) -> *mut Object {
		self.ptr
	}
}
<|endoftext|>


<commit_before>use std::fmt;
use std::mem;

use itertools::Itertools;

use rows::{Page, MiniPage, FMiniPage};
use str::StrSlice;

// globally unique id
#[derive(Clone, PartialEq, Debug)]
pub struct TypeId {
  name: &'static str
}

pub trait HashFn<T> {
  fn hash(v: &MiniPage, keys: &mut [T]);
}

pub trait HashFnFactory
{
  fn hash32_fn() -> Box<FnMut(i32, &mut [i32])>;
  fn create_hash32_block() -> Box<Fn() -> Box<MiniPage>>;
}

pub trait Type
{
  fn type_id           (&self) -> &TypeId;
  fn display_name      (&self) -> &str;
  fn is_comparable     (&self) -> bool;
  fn is_orderable      (&self) -> bool;
  fn type_params       (&self) -> Vec<&Type>;
  //fn hash32_fn         (&self) -> Box<FnMut(&MiniPage, &mut [u32])>;
  fn create_minipage   (&self) -> Box<MiniPage>;
}

#[derive(Clone, PartialEq, Debug)]
pub struct Int4Type;

pub static INT4: TypeId = TypeId {name: "int4"};

impl Type for Int4Type {
  #[inline]
  fn type_id(&self) -> &TypeId { &INT4 }
  #[inline]
  fn display_name(&self) -> &str { &INT4.name }
  #[inline]
  fn is_comparable(&self) -> bool { true }
  #[inline]
  fn is_orderable(&self) -> bool { true }
  #[inline]
  fn type_params(&self) -> Vec<&Type> { Vec::new() }
//  #[inline]
//  fn hash_fn(&self) -> Box<FnMut(&Vector, &mut [u32])>;
  #[inline]
  fn create_minipage (&self) -> Box<MiniPage> {
    Box::new(FMiniPage::new(Box::new(Int4Type)))
  }
}

#[derive(Clone, PartialEq, Debug)]
pub enum Ty
{
  Bool,
  Int1,
  Int2,
  Int4,
  Int8,
  Float4,
  Float8,
  Numeric(u8, Option<u8>), // precision (1~38), scale (0 <= scale <= precision)
  Date,
  Time,
  Timez,
  Timestamp,
  Timestampz,
  Interval,
  Char(u8),                // its maximum length is 127
  Binary(u8),              // its maximum length is 127
  Clob,
  Blob,
  Array(Box<Ty>),
  Struct(Vec<Ty>),
  Map(Box<Ty>, Box<Ty>)
}

impl Ty
{
  #[allow(unused_variables)]
  pub fn size_of(&self) -> u32 {
    match *self {
      Ty::Bool                  => 1,
      Ty::Int1                  => 1,
      Ty::Int2                  => 2,
      Ty::Int4                  => 4,
      Ty::Int8                  => 8,
      Ty::Float4                => 4,
      Ty::Float8                => 8,
      Ty::Numeric(ref p, ref s) => panic!("numeric is not supported yet"),
      Ty::Date                  => 4,
      Ty::Time                  => 8,
      Ty::Timez                 => 12,
      Ty::Timestamp             => 8,
      Ty::Timestampz            => 12,
      Ty::Interval              => 12,
      Ty::Char(len)             => len as u32,
      Ty::Binary(len)           => len as u32,
      Ty::Clob                  => mem::size_of::<TEXT>() as u32,
      Ty::Blob                  => mem::size_of::<TEXT>() as u32,
      Ty::Array(ref ty)         => panic!("array is not supported yet"),
      Ty::Struct(ref tys)       => panic!("array is not supported yet"),
      Ty::Map(ref kt, ref vt)   => panic!("map is not supported yet"),
    }
  }

  #[allow(unused_variables)]
  pub fn is_variable(&self) -> bool {
    match *self {
      Ty::Char(len) | Ty::Binary(len) => true,
      _ => false
    }
  }
}

impl fmt::Display for Ty {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Ty::Bool                    => write!(f, "bool"),
      Ty::Int1                    => write!(f, "int1"),
      Ty::Int2                    => write!(f, "int2"),
      Ty::Int4                    => write!(f, "int4"),
      Ty::Int8                    => write!(f, "int8"),
      Ty::Float4                  => write!(f, "float4"),
      Ty::Float8                  => write!(f, "float8"),
      Ty::Numeric(ref p,ref s)    => {
        match *s {
          Some(ref scale) => write!(f, "numeric ({}, {})", p, scale),
          None            => write!(f, "numeric ({})", p)
        }
      }
      Ty::Date                    => write!(f, "date"),
      Ty::Time                    => write!(f, "time"),
      Ty::Timez                   => write!(f, "time with timezone"),
      Ty::Timestamp               => write!(f, "timestamp"),
      Ty::Timestampz              => write!(f, "timeztamp with timezone"),
      Ty::Interval                => write!(f, "interval"),
      Ty::Char(ref len)           => write!(f, "char({})", len),
      Ty::Binary(ref len)         => write!(f, "binary({})", len),
      Ty::Clob                    => write!(f, "clob"),
      Ty::Blob                    => write!(f, "blob"),
      Ty::Array(ref ty)           => write!(f, "array<{}>", ty),
      Ty::Struct(ref tys)         => {
        write!(f, "struct({})", tys.iter().map(|f| format!("{}", f)).join(", "))
      },
      Ty::Map (ref kty, ref vty)  => write!(f, "map<{},{}>", kty, vty)
    }
  }
}

#[allow(non_camel_case_types)]
pub type BOOL      = bool;
#[allow(non_camel_case_types)]
pub type INT1      = i8;
#[allow(non_camel_case_types)]
pub type INT2      = i16;
#[allow(non_camel_case_types)]
pub type INT4      = i32;
#[allow(non_camel_case_types)]
pub type INT8      = i64;
#[allow(non_camel_case_types)]
pub type FLOAT4    = f32;
#[allow(non_camel_case_types)]
pub type FLOAT8    = f64;
#[allow(non_camel_case_types)]
pub type DATE      = i32;
#[allow(non_camel_case_types)]
pub type TIME      = i64;
#[allow(non_camel_case_types)]
pub type TIMESTAMP = i64;
#[allow(non_camel_case_types)]
pub type TEXT      = StrSlice;

/// Determine a result data type from two expression data types.
#[allow(unused_variables)]
pub fn result_data_ty(lhs_ty: &Ty, rhs_ty: &Ty) -> Ty {
  match *lhs_ty {
    Ty::Bool => {
      match *rhs_ty {
        Ty::Bool => rhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Int1 => {
      match *rhs_ty {
        Ty::Int1   |
        Ty::Int2   |
        Ty::Int4   |
        Ty::Int8   |
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Int2 => {
      match *rhs_ty {
        Ty::Int2   |
        Ty::Int4   |
        Ty::Int8   |
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1   => lhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Int4 => {
      match *rhs_ty {
        Ty::Int4   |
        Ty::Int8   |
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1 |
        Ty::Int2 => lhs_ty.clone(),

        _ => panic!("Undefined Operator")
      }
    },

    Ty::Int8 => {
      match *rhs_ty {
        Ty::Int8   |
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1 |
        Ty::Int2 |
        Ty::Int4 => lhs_ty.clone(),

        _ => panic!("Undefined Operator")
      }
    },

    Ty::Float4 => {
      match *rhs_ty {
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1 |
        Ty::Int2 |
        Ty::Int4 |
        Ty::Int8 => lhs_ty.clone(),

        _ => panic!("Undefined Operator")
      }
    },

    Ty::Float8 => {
      match *rhs_ty {
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1   |
        Ty::Int2   |
        Ty::Int4   |
        Ty::Int8   |
        Ty::Float4 => lhs_ty.clone(),

        _ => panic!("Undefined Operator")
      }
    },

    Ty::Numeric(ref p, ref s) => {
      panic!("Undefined operator")
    },

    Ty::Date => {
      panic!("Undefined Operator")
    },

    Ty::Time => {
      panic!("Undefined Operator")
    },

    Ty::Timez => {
      panic!("Undefined Operator")
    },

    Ty::Timestamp => {
      panic!("Undefined Operator")
    },

    Ty::Timestampz => {
      panic!("Undefined Operator")
    },

    Ty::Interval => {
      panic!("Undefined Operator")
    },

    Ty::Char(ref len) => {
      panic!("Undefined Operator")
    },

    Ty::Binary(ref len) => {
      panic!("Undefined Operator")
    },

    Ty::Clob => {
      match *rhs_ty {
        Ty::Clob => rhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Blob => {
      match *rhs_ty {
        Ty::Blob => rhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Array(ref ty) => {
      panic!("Undefined Operator")
    }

    Ty::Struct(ref tys) => {
      panic!("Undefined Operator")
    },

    Ty::Map(ref kty, ref vty) => {
      panic!("Undefined Operator")
    }
  }
}
<commit_msg>Implement TypeManager and TypeRegistry.<commit_after>use std::collections::BTreeMap;
use std::fmt;
use std::mem;

use itertools::Itertools;

use rows::{MiniPage, FMiniPage};
use str::StrSlice;

// globally unique id
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct TypeId {
  name: &'static str
}

pub trait TypeManager
{
  fn get(&self, id: &TypeId) -> Option<&Type>;
  fn types(&self) -> Vec<&Type>;
}

pub struct TypeRegistry
{
  types: BTreeMap<TypeId, Box<Type>>
}

impl TypeRegistry
{
  fn new(types: Vec<Box<Type>>) -> TypeRegistry
  {
    TypeRegistry {
      types: types.into_iter()
        .map(|ty: Box<Type>| {
            return (*ty.id(), ty)
        })
        .collect::<BTreeMap<TypeId, Box<Type>>>()
    }
  }
}

impl TypeManager for TypeRegistry {
  fn get(&self, id: &TypeId) -> Option<&Type> {
    match self.types.get(id) {
      Some(x) => Some(&**x),
      None    => None
    }
  }

  fn types(&self) -> Vec<&Type> {
    self.types.values().map(|t| &**t).collect::<Vec<&Type>>()
  }
}

const BOOL_STR       : &'static str = "bool";
const INT1_STR       : &'static str = "int1";
const INT2_STR       : &'static str = "int2";
const INT4_STR       : &'static str = "int4";
const INT8_STR       : &'static str = "int8";
const FLOAT4_STR     : &'static str = "float4";
const FLOAT8_STR     : &'static str = "float8";
const NUMERIC_STR    : &'static str = "numeric";
const DATE_STR       : &'static str = "date";
const TIME_STR       : &'static str = "time";
const TIMEZ_STR      : &'static str = "time with timezone";
const TIMESTAMP_STR  : &'static str = "timestamp";
const TIMESTAMPZ_STR : &'static str = "timestamp with timezone";
const INTERVAL_STR   : &'static str = "interval";
const CHAR_STR       : &'static str = "char";
const BINARY_STR     : &'static str = "binary";
const CLOB_STR       : &'static str = "clob";
const BLOB_STR       : &'static str = "blob";

pub static BOOL:       TypeId = TypeId {name: BOOL_STR};
pub static INT1:       TypeId = TypeId {name: INT1_STR};
pub static INT2:       TypeId = TypeId {name: INT2_STR};
pub static INT4:       TypeId = TypeId {name: INT4_STR};
pub static INT8:       TypeId = TypeId {name: INT8_STR};
pub static FLOAT4:     TypeId = TypeId {name: FLOAT4_STR};
pub static FLOAT8:     TypeId = TypeId {name: FLOAT8_STR};
pub static NUMERIC:    TypeId = TypeId {name: NUMERIC_STR};
pub static DATE:       TypeId = TypeId {name: DATE_STR};
pub static TIME:       TypeId = TypeId {name: TIME_STR};
pub static TIMEZ:      TypeId = TypeId {name: TIMEZ_STR};
pub static TIMESTAMP:  TypeId = TypeId {name: TIMESTAMP_STR};
pub static TIMESTAMPZ: TypeId = TypeId {name: TIMESTAMPZ_STR};
pub static INTERVAL:   TypeId = TypeId {name: INTERVAL_STR};
pub static CHAR:       TypeId = TypeId {name: CHAR_STR};
pub static BINARY:     TypeId = TypeId {name: BINARY_STR};
pub static CLOB:       TypeId = TypeId {name: CLOB_STR};
pub static BLOB:       TypeId = TypeId {name: BLOB_STR};

pub trait HashFn<T> {
  fn hash(v: &MiniPage, keys: &mut [T]);
}

pub trait HashFnFactory
{
  fn hash32_fn() -> Box<FnMut(i32, &mut [i32])>;
  fn create_hash32_block() -> Box<Fn() -> Box<MiniPage>>;
}

pub trait Type
{
  fn id                (&self) -> &TypeId;
  fn display_name      (&self) -> &str;
  fn is_comparable     (&self) -> bool;
  fn is_orderable      (&self) -> bool;
  fn type_params       (&self) -> Vec<&Type>;
  //fn hash32_fn         (&self) -> Box<FnMut(&MiniPage, &mut [u32])>;
  fn create_minipage   (&self) -> Box<MiniPage>;
}

#[derive(Clone, PartialEq, Debug)]
pub struct Int4Type;

impl Type for Int4Type {
  #[inline]
  fn id(&self) -> &TypeId { &INT4 }
  #[inline]
  fn display_name(&self) -> &str { &INT4.name }
  #[inline]
  fn is_comparable(&self) -> bool { true }
  #[inline]
  fn is_orderable(&self) -> bool { true }
  #[inline]
  fn type_params(&self) -> Vec<&Type> { Vec::new() }
//  #[inline]
//  fn hash_fn(&self) -> Box<FnMut(&Vector, &mut [u32])>;
  #[inline]
  fn create_minipage (&self) -> Box<MiniPage> {
    Box::new(FMiniPage::new(Box::new(Int4Type)))
  }
}

#[derive(Clone, PartialEq, Debug)]
pub enum Ty
{
  Bool,
  Int1,
  Int2,
  Int4,
  Int8,
  Float4,
  Float8,
  Numeric(u8, Option<u8>), // precision (1~38), scale (0 <= scale <= precision)
  Date,
  Time,
  Timez,
  Timestamp,
  Timestampz,
  Interval,
  Char(u8),                // its maximum length is 127
  Binary(u8),              // its maximum length is 127
  Clob,
  Blob,
  Array(Box<Ty>),
  Struct(Vec<Ty>),
  Map(Box<Ty>, Box<Ty>)
}

impl Ty
{
  #[allow(unused_variables)]
  pub fn size_of(&self) -> u32 {
    match *self {
      Ty::Bool                  => 1,
      Ty::Int1                  => 1,
      Ty::Int2                  => 2,
      Ty::Int4                  => 4,
      Ty::Int8                  => 8,
      Ty::Float4                => 4,
      Ty::Float8                => 8,
      Ty::Numeric(ref p, ref s) => panic!("numeric is not supported yet"),
      Ty::Date                  => 4,
      Ty::Time                  => 8,
      Ty::Timez                 => 12,
      Ty::Timestamp             => 8,
      Ty::Timestampz            => 12,
      Ty::Interval              => 12,
      Ty::Char(len)             => len as u32,
      Ty::Binary(len)           => len as u32,
      Ty::Clob                  => mem::size_of::<TEXT>() as u32,
      Ty::Blob                  => mem::size_of::<TEXT>() as u32,
      Ty::Array(ref ty)         => panic!("array is not supported yet"),
      Ty::Struct(ref tys)       => panic!("array is not supported yet"),
      Ty::Map(ref kt, ref vt)   => panic!("map is not supported yet"),
    }
  }

  #[allow(unused_variables)]
  pub fn is_variable(&self) -> bool {
    match *self {
      Ty::Char(len) | Ty::Binary(len) => true,
      _ => false
    }
  }
}

impl fmt::Display for Ty {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      Ty::Bool                    => write!(f, "bool"),
      Ty::Int1                    => write!(f, "int1"),
      Ty::Int2                    => write!(f, "int2"),
      Ty::Int4                    => write!(f, "int4"),
      Ty::Int8                    => write!(f, "int8"),
      Ty::Float4                  => write!(f, "float4"),
      Ty::Float8                  => write!(f, "float8"),
      Ty::Numeric(ref p,ref s)    => {
        match *s {
          Some(ref scale) => write!(f, "numeric ({}, {})", p, scale),
          None            => write!(f, "numeric ({})", p)
        }
      }
      Ty::Date                    => write!(f, "date"),
      Ty::Time                    => write!(f, "time"),
      Ty::Timez                   => write!(f, "time with timezone"),
      Ty::Timestamp               => write!(f, "timestamp"),
      Ty::Timestampz              => write!(f, "timeztamp with timezone"),
      Ty::Interval                => write!(f, "interval"),
      Ty::Char(ref len)           => write!(f, "char({})", len),
      Ty::Binary(ref len)         => write!(f, "binary({})", len),
      Ty::Clob                    => write!(f, "clob"),
      Ty::Blob                    => write!(f, "blob"),
      Ty::Array(ref ty)           => write!(f, "array<{}>", ty),
      Ty::Struct(ref tys)         => {
        write!(f, "struct({})", tys.iter().map(|f| format!("{}", f)).join(", "))
      },
      Ty::Map (ref kty, ref vty)  => write!(f, "map<{},{}>", kty, vty)
    }
  }
}

#[allow(non_camel_case_types)]
pub type BOOL      = bool;
#[allow(non_camel_case_types)]
pub type INT1      = i8;
#[allow(non_camel_case_types)]
pub type INT2      = i16;
#[allow(non_camel_case_types)]
pub type INT4      = i32;
#[allow(non_camel_case_types)]
pub type INT8      = i64;
#[allow(non_camel_case_types)]
pub type FLOAT4    = f32;
#[allow(non_camel_case_types)]
pub type FLOAT8    = f64;
#[allow(non_camel_case_types)]
pub type DATE      = i32;
#[allow(non_camel_case_types)]
pub type TIME      = i64;
#[allow(non_camel_case_types)]
pub type TIMESTAMP = i64;
#[allow(non_camel_case_types)]
pub type TEXT      = StrSlice;

/// Determine a result data type from two expression data types.
#[allow(unused_variables)]
pub fn result_data_ty(lhs_ty: &Ty, rhs_ty: &Ty) -> Ty {
  match *lhs_ty {
    Ty::Bool => {
      match *rhs_ty {
        Ty::Bool => rhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Int1 => {
      match *rhs_ty {
        Ty::Int1   |
        Ty::Int2   |
        Ty::Int4   |
        Ty::Int8   |
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Int2 => {
      match *rhs_ty {
        Ty::Int2   |
        Ty::Int4   |
        Ty::Int8   |
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1   => lhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Int4 => {
      match *rhs_ty {
        Ty::Int4   |
        Ty::Int8   |
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1 |
        Ty::Int2 => lhs_ty.clone(),

        _ => panic!("Undefined Operator")
      }
    },

    Ty::Int8 => {
      match *rhs_ty {
        Ty::Int8   |
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1 |
        Ty::Int2 |
        Ty::Int4 => lhs_ty.clone(),

        _ => panic!("Undefined Operator")
      }
    },

    Ty::Float4 => {
      match *rhs_ty {
        Ty::Float4 |
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1 |
        Ty::Int2 |
        Ty::Int4 |
        Ty::Int8 => lhs_ty.clone(),

        _ => panic!("Undefined Operator")
      }
    },

    Ty::Float8 => {
      match *rhs_ty {
        Ty::Float8 => rhs_ty.clone(),

        Ty::Int1   |
        Ty::Int2   |
        Ty::Int4   |
        Ty::Int8   |
        Ty::Float4 => lhs_ty.clone(),

        _ => panic!("Undefined Operator")
      }
    },

    Ty::Numeric(ref p, ref s) => {
      panic!("Undefined operator")
    },

    Ty::Date => {
      panic!("Undefined Operator")
    },

    Ty::Time => {
      panic!("Undefined Operator")
    },

    Ty::Timez => {
      panic!("Undefined Operator")
    },

    Ty::Timestamp => {
      panic!("Undefined Operator")
    },

    Ty::Timestampz => {
      panic!("Undefined Operator")
    },

    Ty::Interval => {
      panic!("Undefined Operator")
    },

    Ty::Char(ref len) => {
      panic!("Undefined Operator")
    },

    Ty::Binary(ref len) => {
      panic!("Undefined Operator")
    },

    Ty::Clob => {
      match *rhs_ty {
        Ty::Clob => rhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Blob => {
      match *rhs_ty {
        Ty::Blob => rhs_ty.clone(),
        _ => panic!("Undefined Operator")
      }
    },

    Ty::Array(ref ty) => {
      panic!("Undefined Operator")
    }

    Ty::Struct(ref tys) => {
      panic!("Undefined Operator")
    },

    Ty::Map(ref kty, ref vty) => {
      panic!("Undefined Operator")
    }
  }
}
<|endoftext|>


<commit_before>use ::ast::*;
use ::ast::ExprNode::*;
use super::*;
use super::parser_combinators::{Parser,parser};
use std::char;

#[test]
fn test_basic_ident() {
    assert_eq!(
        parser(expr).parse("ident"),
        Ok((Name(NameNode { name: "ident".to_string() }), ""))
        );
    assert_eq!(
        parser(expr).parse("a"),
        Ok((Name(NameNode { name: "a".to_string() }), ""))
        );
    assert_eq!(
        parser(expr).parse("ident_With\\special!Chars:~-+"),
        Ok((Name(NameNode { name: "ident_With\\special!Chars:~-+".to_string() }), ""))
        );
}

#[test]
fn test_basic_sexpr() {
    assert_eq!(
        parser(expr).parse("(ident arg1 arg2)"),
        Ok((SExpr(SExprNode {
            operator: NameNode { name: "ident".to_string() },
            operands: vec![
                Name(NameNode { name: "arg1".to_string() }),
                Name(NameNode { name: "arg2".to_string() })
            ]
        }), ""))
        );
}

#[test]
fn test_lex_sint_pos() {
    assert_eq!(
        parser(number).parse("1234"),
        Ok((NumNode::IntConst(IntNode { value: 1234isize }), ""))
        );
    assert_eq!(
        parser(number).parse("#d1234"),
        Ok((NumNode::IntConst(IntNode { value: 1234isize }), ""))
        );
    assert_eq!(
        parser(number).parse("#D1234"),
        Ok((NumNode::IntConst(IntNode { value: 1234isize }), ""))
        );
}

#[test]
fn test_lex_sint_neg() {
    assert_eq!(
        parser(number).parse("-1234"),
        Ok((NumNode::IntConst(IntNode { value: -1234isize }), ""))
        );
}

#[test]
fn test_lex_sint_hex() {
    assert_eq!(
        parser(number).parse("#x0ff"),
        Ok((NumNode::IntConst(IntNode { value: 0x0ffisize }), ""))
        );
    assert_eq!(
        parser(number).parse("#X0FF"),
        Ok((NumNode::IntConst(IntNode { value: 0x0ffisize }), ""))
        );
}
/* // Currently unsupported
#[test]
fn test_parse_sint_bin_upper() {
    assert_eq!(
        parser(number).parse("0B01"),
        Ok((NumNode::IntConst(IntNode { value: 0b01isize }), ""))
        );
    assert_eq!(
        parser(number).parse("0b01"),
        Ok((NumNode::IntConst(IntNode { value: 0b01isize }), ""))
        );
}*/

#[test]
fn test_lex_uint() {
    assert_eq!(
        parser(number).parse("1234u"),
        Ok((NumNode::UIntConst(UIntNode { value: 1234usize }), ""))
        );
    assert_eq!(
        parser(number).parse("4321U"),
        Ok((NumNode::UIntConst(UIntNode { value: 4321usize }), ""))
        );
}

#[test]
fn test_lex_uint_hex() {
    assert_eq!(
        parser(number).parse("#x0ffu"),
        Ok((NumNode::UIntConst(UIntNode { value: 0x0ffusize }), ""))
        );
    assert_eq!(
        parser(number).parse("#X0FFu"),
        Ok((NumNode::UIntConst(UIntNode { value: 0x0ffusize }), ""))
        );
}

#[test]
fn test_lex_float() {
    assert_eq!(
        parser(number).parse("1.0"),
        Ok((NumNode::FloatConst(FloatNode { value: 1.0f64 }), ""))
        );/* // Unsupported
    assert_eq!(
        parser(number).parse("1f").unwrap(),
        (NumNode::FloatConst(FloatNode { value: 1.0f64 }), "")
        );
    assert_eq!(
        parser(number).parse("22.2222").unwrap(),
        (NumNode::FloatConst(FloatNode { value: 22.2222f64 }), "")
        );
    assert_eq!(
        parser(number).parse("22.2222f").unwrap(),
        (NumNode::FloatConst(FloatNode { value: 22.2222f64 }), "")
        );*/
}

#[test]
fn test_lex_bool() {
    assert_eq!(
        parser(bool_const).parse("#t"),
        Ok((BoolNode { value: true}, ""))
        );
    assert_eq!(
        parser(bool_const).parse("#T"),
        Ok((BoolNode { value: true}, ""))
        );
    assert_eq!(
        parser(bool_const).parse("true"),
        Ok((BoolNode { value: true}, ""))
        );
    assert_eq!(
        parser(bool_const).parse("#f"),
        Ok((BoolNode { value: false}, ""))
        );
    assert_eq!(
        parser(bool_const).parse("#F"),
        Ok((BoolNode { value: false}, ""))
        );
    assert_eq!(
        parser(bool_const).parse("false"),
        Ok((BoolNode { value: false}, ""))
        );
}

#[test]
fn test_lex_char() {
    assert_eq!(
        parser(character).parse("#\\c"),
        Ok((CharNode { value: 'c'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\A"),
        Ok((CharNode { value: 'A'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\tab"),
        Ok((CharNode { value: '\t'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\newline"),
        Ok((CharNode { value: '\n'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\nul"),
        Ok((CharNode { value: char::from_u32(0x0000).unwrap()}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\backspace"),
        Ok((CharNode { value: char::from_u32(0x0008).unwrap()}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\vtab"),
        Ok((CharNode { value: char::from_u32(0x000B).unwrap()}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\page"),
        Ok((CharNode { value: char::from_u32(0x000C).unwrap()}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\return"),
        Ok((CharNode { value: char::from_u32(0x000D).unwrap()}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\esc"),
        Ok((CharNode { value: char::from_u32(0x001B).unwrap()}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\delete"),
        Ok((CharNode { value: char::from_u32(0x007F).unwrap()}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\alarm"),
        Ok((CharNode { value: char::from_u32(0x0007).unwrap()}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\linefeed"),
        Ok((CharNode { value: '\n'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\space"),
        Ok((CharNode { value: ' '}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\x0020"),
        Ok((CharNode { value: ' '}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\x001B"),
        Ok((CharNode { value: char::from_u32(0x001B).unwrap()}, ""))
        );
}

#[test]
fn test_lex_string() {
    assert_eq!(
        parser(string_const).parse("\"a string\""),
        Ok((StringNode { value: "a string".to_string() }, ""))
    );
    assert_eq!(
        parser(string_const).parse("\"a string with a\\ttab\""),
        Ok((StringNode { value: "a string with a\ttab".to_string() },""))
    );
    assert_eq!(
        parser(string_const).parse("\"a string with an \\\"escaped\\\" quote\""),
        Ok((StringNode { value: "a string with an \"escaped\" quote".to_string() },""))
    );
    assert_eq!(
        parser(string_const).parse("\"the\\worst string ever\\\"\""),
        Ok((StringNode { value: "the\\worst string ever\"".to_string() }, ""))
    );
}
<commit_msg>Implement lexer for string constants<commit_after>use ::ast::*;
use ::ast::ExprNode::*;
use super::*;
use super::parser_combinators::{Parser,parser};
use std::char;

#[test]
fn test_basic_ident() {
    assert_eq!(
        parser(expr).parse("ident"),
        Ok((Name(NameNode { name: "ident".to_string() }), ""))
        );
    assert_eq!(
        parser(expr).parse("a"),
        Ok((Name(NameNode { name: "a".to_string() }), ""))
        );
    assert_eq!(
        parser(expr).parse("ident_With\\special!Chars:~-+"),
        Ok((Name(NameNode { name: "ident_With\\special!Chars:~-+".to_string() }), ""))
        );
}

#[test]
fn test_basic_sexpr() {
    assert_eq!(
        parser(expr).parse("(ident arg1 arg2)"),
        Ok((SExpr(SExprNode {
            operator: NameNode { name: "ident".to_string() },
            operands: vec![
                Name(NameNode { name: "arg1".to_string() }),
                Name(NameNode { name: "arg2".to_string() })
            ]
        }), ""))
        );
}

#[test]
fn test_lex_sint_pos() {
    assert_eq!(
        parser(number).parse("1234"),
        Ok((NumNode::IntConst(IntNode { value: 1234isize }), ""))
        );
    assert_eq!(
        parser(number).parse("#d1234"),
        Ok((NumNode::IntConst(IntNode { value: 1234isize }), ""))
        );
    assert_eq!(
        parser(number).parse("#D1234"),
        Ok((NumNode::IntConst(IntNode { value: 1234isize }), ""))
        );
}

#[test]
fn test_lex_sint_neg() {
    assert_eq!(
        parser(number).parse("-1234"),
        Ok((NumNode::IntConst(IntNode { value: -1234isize }), ""))
        );
}

#[test]
fn test_lex_sint_hex() {
    assert_eq!(
        parser(number).parse("#x0ff"),
        Ok((NumNode::IntConst(IntNode { value: 0x0ffisize }), ""))
        );
    assert_eq!(
        parser(number).parse("#X0FF"),
        Ok((NumNode::IntConst(IntNode { value: 0x0ffisize }), ""))
        );
}
/* // Currently unsupported
#[test]
fn test_parse_sint_bin_upper() {
    assert_eq!(
        parser(number).parse("0B01"),
        Ok((NumNode::IntConst(IntNode { value: 0b01isize }), ""))
        );
    assert_eq!(
        parser(number).parse("0b01"),
        Ok((NumNode::IntConst(IntNode { value: 0b01isize }), ""))
        );
}*/

#[test]
fn test_lex_uint() {
    assert_eq!(
        parser(number).parse("1234u"),
        Ok((NumNode::UIntConst(UIntNode { value: 1234usize }), ""))
        );
    assert_eq!(
        parser(number).parse("4321U"),
        Ok((NumNode::UIntConst(UIntNode { value: 4321usize }), ""))
        );
}

#[test]
fn test_lex_uint_hex() {
    assert_eq!(
        parser(number).parse("#x0ffu"),
        Ok((NumNode::UIntConst(UIntNode { value: 0x0ffusize }), ""))
        );
    assert_eq!(
        parser(number).parse("#X0FFu"),
        Ok((NumNode::UIntConst(UIntNode { value: 0x0ffusize }), ""))
        );
}

#[test]
fn test_lex_float() {
    assert_eq!(
        parser(number).parse("1.0"),
        Ok((NumNode::FloatConst(FloatNode { value: 1.0f64 }), ""))
        );/* // Unsupported
    assert_eq!(
        parser(number).parse("1f").unwrap(),
        (NumNode::FloatConst(FloatNode { value: 1.0f64 }), "")
        );
    assert_eq!(
        parser(number).parse("22.2222").unwrap(),
        (NumNode::FloatConst(FloatNode { value: 22.2222f64 }), "")
        );
    assert_eq!(
        parser(number).parse("22.2222f").unwrap(),
        (NumNode::FloatConst(FloatNode { value: 22.2222f64 }), "")
        );*/
}

#[test]
fn test_lex_bool() {
    assert_eq!(
        parser(bool_const).parse("#t"),
        Ok((BoolNode { value: true}, ""))
        );
    assert_eq!(
        parser(bool_const).parse("#T"),
        Ok((BoolNode { value: true}, ""))
        );
    assert_eq!(
        parser(bool_const).parse("true"),
        Ok((BoolNode { value: true}, ""))
        );
    assert_eq!(
        parser(bool_const).parse("#f"),
        Ok((BoolNode { value: false}, ""))
        );
    assert_eq!(
        parser(bool_const).parse("#F"),
        Ok((BoolNode { value: false}, ""))
        );
    assert_eq!(
        parser(bool_const).parse("false"),
        Ok((BoolNode { value: false}, ""))
        );
}

#[test]
fn test_lex_char() {
    assert_eq!(
        parser(character).parse("#\\c"),
        Ok((CharNode { value: 'c'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\A"),
        Ok((CharNode { value: 'A'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\tab"),
        Ok((CharNode { value: '\t'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\newline"),
        Ok((CharNode { value: '\n'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\nul"),
        Ok((CharNode { value: char::from_u32(0x0000).unwrap()}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\backspace"),
        Ok((CharNode { value: char::from_u32(0x0008).unwrap()}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\vtab"),
        Ok((CharNode { value: char::from_u32(0x000B).unwrap()}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\page"),
        Ok((CharNode { value: char::from_u32(0x000C).unwrap()}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\return"),
        Ok((CharNode { value: char::from_u32(0x000D).unwrap()}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\esc"),
        Ok((CharNode { value: char::from_u32(0x001B).unwrap()}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\delete"),
        Ok((CharNode { value: char::from_u32(0x007F).unwrap()}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\alarm"),
        Ok((CharNode { value: char::from_u32(0x0007).unwrap()}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\linefeed"),
        Ok((CharNode { value: '\n'}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\space"),
        Ok((CharNode { value: ' '}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\x0020"),
        Ok((CharNode { value: ' '}, ""))
        );
    assert_eq!(
        parser(character).parse("#\\x001B"),
        Ok((CharNode { value: char::from_u32(0x001B).unwrap()}, ""))
        );
}

#[test]
fn test_lex_string() {
    assert_eq!(
        parser(string_const).parse("\"a string\""),
        Ok((StringNode { value: "a string".to_string() }, ""))
    );
    assert_eq!(
        parser(string_const).parse("\"a string with a\\ttab\""),
        Ok((StringNode { value: "a string with a\ttab".to_string() },""))
    );
    assert_eq!(
        parser(string_const).parse("\"a string with an \\\"escaped\\\" quote\""),
        Ok((StringNode { value: "a string with an \"escaped\" quote".to_string() },""))
    );
    assert_eq!(
        parser(string_const).parse("\"the\\\\worst string ever\\\"\""),
        Ok((StringNode { value: "the\\worst string ever\"".to_string() }, ""))
    );
}
<|endoftext|>