<commit_before>
// https://users.rust-lang.org/t/what-am-i-doing-wrong-go-program-is-12x-faster-than-rust/5692/13
// https://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/index.html
// https://serde.rs/codegen-hybrid.html

// FIXME: Use https://github.com/nox/serde_urlencoded
// FIXME: Make sure that all structs above Issue are not using `String`s instead of `Enum`s.
// FIXME: Harmonize the different state enums (e.g. IssueState, MergeRequestState, Authors)
// FIXME: Move all enums here (ListingOrderBy, ListingSort, etc.)
// FIXME: Use a type for sha1
// FIXME: Use chrono crate for dates
// FIXME: Use unsigned integers where it makes sense (id, iid, etc.)
// FIXME: Verify all `match` in push_str() in build_query(): They should contain all members.
// FIXME: Get rid of build_query(), use serde's Serialize instead.
// FIXME: Write nicer wrappers, getting rid of Listing.
// FIXME: Rename GitLab::new_https() to new() and new_http() to new_insecure()

#[derive(Debug, Serialize, Deserialize)]
pub struct Version {
    pub version: String,
    pub revision: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Group {
    pub id: i64,
    pub name: String,
    pub path: String,
    pub description: String,
    pub visibility_level: i64,
    pub lfs_enabled: bool,
    pub avatar_url: Option<String>,
    pub web_url: String,
    pub request_access_enabled: bool,
}

pub type Groups = Vec<Group>;

#[derive(Debug, Serialize, Deserialize)]
pub struct ProjectOwner {
    pub name: String,
    pub username: String,
    pub id: i64,
    pub state: String,
    pub avatar_url: String,
    pub web_url: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectNamespaceAvatar {
    url: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectNamespace {
    id: i64,
    name: String,
    path: String,
    owner_id: Option<i64>,  // FIXME: Why would a project not have this?
    created_at: String,  // FIXME: Date instead?
    updated_at: String,  // FIXME: Date instead?
    description: String,
    avatar: Option<ProjectNamespaceAvatar>,
    membership_lock: Option<bool>,
    share_with_group_lock: bool,
    visibility_level: i64,
    request_access_enabled: bool,
    ldap_sync_status: Option<String>,
    ldap_sync_error: Option<String>,  // FIXME: Is String the proper type?
    ldap_sync_last_update_at: Option<String>,  // FIXME: Is String the proper type?
    ldap_sync_last_successful_update_at: Option<String>,  // FIXME: Is String the proper type?
    ldap_sync_last_sync_at: Option<String>,  // FIXME: Is String the proper type?
    deleted_at: Option<String>,  // FIXME: Is String the proper type?
    lfs_enabled: Option<String>,  // FIXME: Is String the proper type?
    repository_size_limit: Option<String>  // FIXME: Is String the proper type?
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectForkedFrom {
    id: i64,
    http_url_to_repo: String,
    web_url: String,
    name: String,
    name_with_namespace: String,
    path: String,
    path_with_namespace: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectAccess {
    access_level: i64,
    notification_level: i64,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectPermissions {
    project_access: Option<ProjectAccess>,
    group_access: Option<ProjectAccess>,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectSharedWithGroup {
    group_id: i64,
    group_name: String,
    group_access_level: i64,
}

// https://users.rust-lang.org/t/what-am-i-doing-wrong-go-program-is-12x-faster-than-rust/5692/13
// https://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/index.html
#[derive(Debug, Serialize, Deserialize)]
pub struct Project {
    id: i64,
    description: String,
    default_branch: Option<String>,
    tag_list: Vec<String>,
    public: bool,
    archived: bool,
    visibility_level: i64,
    ssh_url_to_repo: String,
    http_url_to_repo: String,
    web_url: String,
    // owner: Option<ProjectOwner>,  // FIXME: Why would a project not have an owner?
    name: String,
    name_with_namespace: String,
    path: String,
    path_with_namespace: String,
    container_registry_enabled: Option<bool>,
    issues_enabled: bool,
    merge_requests_enabled: bool,
    wiki_enabled: bool,
    builds_enabled: bool,
    snippets_enabled: bool,
    created_at: String,  // FIXME: Date instead?
    last_activity_at: String,  // FIXME: Date instead?
    shared_runners_enabled: bool,
    lfs_enabled: bool,
    creator_id: i64,
    namespace: ProjectNamespace,
    forked_from_project: Option<ProjectForkedFrom>,
    avatar_url: Option<String>,
    star_count: i64,
    forks_count: i64,
    open_issues_count: i64,
    runners_token: Option<String>,
    public_builds: bool,
    shared_with_groups: Vec<ProjectSharedWithGroup>,
    only_allow_merge_if_build_succeeds: bool,
    request_access_enabled: bool,
    only_allow_merge_if_all_discussions_are_resolved: Option<bool>,  // FIXME: Is bool the proper type?
    approvals_before_merge: Option<i64>,
    permissions: ProjectPermissions,
}

pub type Projects = Vec<Project>;

#[derive(Debug, Serialize, Deserialize)]
enum IssueState {
    #[serde(rename = "opened")]
    Opened,

    #[serde(rename = "closed")]
    Closed,
}

#[derive(Debug, Serialize, Deserialize)]
enum UserState {
    #[serde(rename = "active")]
    Active,

    #[serde(rename = "blocked")]
    Blocked,
}

#[derive(Debug, Serialize, Deserialize)]
enum MilestoneState {
    #[serde(rename = "active")]
    Active,

    #[serde(rename = "closed")]
    Closed,
}

#[derive(Debug, Serialize, Deserialize)]
struct Milestone {
    id: i64,
    iid: i64,
    project_id: i64,
    title: String,
    description: String,
    state: MilestoneState,
    created_at: String,  // FIXME: Use date type?
    updated_at: String,  // FIXME: Use date type?
    due_date: Option<String>  // FIXME: Use date type?
}

#[derive(Debug, Serialize, Deserialize)]
struct User {
    name: String,
    username: String,
    id: i64,
    state: UserState,
    avatar_url: Option<String>,
    web_url: Option<String>
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Issue {
    id: i64,
    iid: i64,
    project_id: i64,
    title: String,
    description: String,
    state: IssueState,
    created_at: String,  // FIXME: Use date type?
    updated_at: String,  // FIXME: Use date type?
    labels: Vec<String>,
    milestone: Option<Milestone>,
    assignee: Option<User>,
    author: User,
    subscribed: bool,
    user_notes_count: i64,
    upvotes: i64,
    downvotes: i64,
    due_date: Option<String>,  // FIXME: Use date type?
    confidential: bool,
    web_url: Option<String>
}

pub type Issues = Vec<Issue>;

#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub enum MergeRequestState {
    #[serde(rename = "merged")]
    Merged,
    #[serde(rename = "opened")]
    Opened,
    #[serde(rename = "closed")]
    Closed,
    #[serde(rename = "all")]
    All,
}

#[derive(Debug, Serialize, Deserialize)]
enum MergeRequestStatus {
    #[serde(rename = "can_be_merged")]
    CanBeMerged,
    #[serde(rename = "cannot_be_merged")]
    CannotBeMerged,
    #[serde(rename = "unchecked")]
    Unchecked,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct MergeRequest {
    id: i64,
    iid: i64,
    project_id: i64,
    title: String,
    description: String,
    state: MergeRequestState,
    created_at: String,  // FIXME: Use chrono crate
    updated_at: String,  // FIXME: Use chrono crate
    target_branch: String,
    source_branch: String,
    upvotes: i64,
    downvotes: i64,
    author: User,
    assignee: Option<User>,
    source_project_id: i64,
    target_project_id: i64,
    labels: Vec<String>,
    work_in_progress: bool,
    milestone: Option<Milestone>,
    merge_when_build_succeeds: bool,
    merge_status: MergeRequestStatus,
    sha: String,
    merge_commit_sha: Option<String>,
    subscribed: bool,
    user_notes_count: i64,
    should_remove_source_branch: Option<bool>,
    force_remove_source_branch: Option<bool>,
    web_url: String
}

pub type MergeRequests = Vec<MergeRequest>;
<commit_msg>Methods were renamed, delete FIXME<commit_after>
// https://users.rust-lang.org/t/what-am-i-doing-wrong-go-program-is-12x-faster-than-rust/5692/13
// https://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/index.html
// https://serde.rs/codegen-hybrid.html

// FIXME: Use https://github.com/nox/serde_urlencoded
// FIXME: Make sure that all structs above Issue are not using `String`s instead of `Enum`s.
// FIXME: Harmonize the different state enums (e.g. IssueState, MergeRequestState, Authors)
// FIXME: Move all enums here (ListingOrderBy, ListingSort, etc.)
// FIXME: Use a type for sha1
// FIXME: Use chrono crate for dates
// FIXME: Use unsigned integers where it makes sense (id, iid, etc.)
// FIXME: Verify all `match` in push_str() in build_query(): They should contain all members.
// FIXME: Get rid of build_query(), use serde's Serialize instead.
// FIXME: Write nicer wrappers, getting rid of Listing.

#[derive(Debug, Serialize, Deserialize)]
pub struct Version {
    pub version: String,
    pub revision: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Group {
    pub id: i64,
    pub name: String,
    pub path: String,
    pub description: String,
    pub visibility_level: i64,
    pub lfs_enabled: bool,
    pub avatar_url: Option<String>,
    pub web_url: String,
    pub request_access_enabled: bool,
}

pub type Groups = Vec<Group>;

#[derive(Debug, Serialize, Deserialize)]
pub struct ProjectOwner {
    pub name: String,
    pub username: String,
    pub id: i64,
    pub state: String,
    pub avatar_url: String,
    pub web_url: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectNamespaceAvatar {
    url: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectNamespace {
    id: i64,
    name: String,
    path: String,
    owner_id: Option<i64>,  // FIXME: Why would a project not have this?
    created_at: String,  // FIXME: Date instead?
    updated_at: String,  // FIXME: Date instead?
    description: String,
    avatar: Option<ProjectNamespaceAvatar>,
    membership_lock: Option<bool>,
    share_with_group_lock: bool,
    visibility_level: i64,
    request_access_enabled: bool,
    ldap_sync_status: Option<String>,
    ldap_sync_error: Option<String>,  // FIXME: Is String the proper type?
    ldap_sync_last_update_at: Option<String>,  // FIXME: Is String the proper type?
    ldap_sync_last_successful_update_at: Option<String>,  // FIXME: Is String the proper type?
    ldap_sync_last_sync_at: Option<String>,  // FIXME: Is String the proper type?
    deleted_at: Option<String>,  // FIXME: Is String the proper type?
    lfs_enabled: Option<String>,  // FIXME: Is String the proper type?
    repository_size_limit: Option<String>  // FIXME: Is String the proper type?
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectForkedFrom {
    id: i64,
    http_url_to_repo: String,
    web_url: String,
    name: String,
    name_with_namespace: String,
    path: String,
    path_with_namespace: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectAccess {
    access_level: i64,
    notification_level: i64,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectPermissions {
    project_access: Option<ProjectAccess>,
    group_access: Option<ProjectAccess>,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectSharedWithGroup {
    group_id: i64,
    group_name: String,
    group_access_level: i64,
}

// https://users.rust-lang.org/t/what-am-i-doing-wrong-go-program-is-12x-faster-than-rust/5692/13
// https://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/index.html
#[derive(Debug, Serialize, Deserialize)]
pub struct Project {
    id: i64,
    description: String,
    default_branch: Option<String>,
    tag_list: Vec<String>,
    public: bool,
    archived: bool,
    visibility_level: i64,
    ssh_url_to_repo: String,
    http_url_to_repo: String,
    web_url: String,
    // owner: Option<ProjectOwner>,  // FIXME: Why would a project not have an owner?
    name: String,
    name_with_namespace: String,
    path: String,
    path_with_namespace: String,
    container_registry_enabled: Option<bool>,
    issues_enabled: bool,
    merge_requests_enabled: bool,
    wiki_enabled: bool,
    builds_enabled: bool,
    snippets_enabled: bool,
    created_at: String,  // FIXME: Date instead?
    last_activity_at: String,  // FIXME: Date instead?
    shared_runners_enabled: bool,
    lfs_enabled: bool,
    creator_id: i64,
    namespace: ProjectNamespace,
    forked_from_project: Option<ProjectForkedFrom>,
    avatar_url: Option<String>,
    star_count: i64,
    forks_count: i64,
    open_issues_count: i64,
    runners_token: Option<String>,
    public_builds: bool,
    shared_with_groups: Vec<ProjectSharedWithGroup>,
    only_allow_merge_if_build_succeeds: bool,
    request_access_enabled: bool,
    only_allow_merge_if_all_discussions_are_resolved: Option<bool>,  // FIXME: Is bool the proper type?
    approvals_before_merge: Option<i64>,
    permissions: ProjectPermissions,
}

pub type Projects = Vec<Project>;

#[derive(Debug, Serialize, Deserialize)]
enum IssueState {
    #[serde(rename = "opened")]
    Opened,

    #[serde(rename = "closed")]
    Closed,
}

#[derive(Debug, Serialize, Deserialize)]
enum UserState {
    #[serde(rename = "active")]
    Active,

    #[serde(rename = "blocked")]
    Blocked,
}

#[derive(Debug, Serialize, Deserialize)]
enum MilestoneState {
    #[serde(rename = "active")]
    Active,

    #[serde(rename = "closed")]
    Closed,
}

#[derive(Debug, Serialize, Deserialize)]
struct Milestone {
    id: i64,
    iid: i64,
    project_id: i64,
    title: String,
    description: String,
    state: MilestoneState,
    created_at: String,  // FIXME: Use date type?
    updated_at: String,  // FIXME: Use date type?
    due_date: Option<String>  // FIXME: Use date type?
}

#[derive(Debug, Serialize, Deserialize)]
struct User {
    name: String,
    username: String,
    id: i64,
    state: UserState,
    avatar_url: Option<String>,
    web_url: Option<String>
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Issue {
    id: i64,
    iid: i64,
    project_id: i64,
    title: String,
    description: String,
    state: IssueState,
    created_at: String,  // FIXME: Use date type?
    updated_at: String,  // FIXME: Use date type?
    labels: Vec<String>,
    milestone: Option<Milestone>,
    assignee: Option<User>,
    author: User,
    subscribed: bool,
    user_notes_count: i64,
    upvotes: i64,
    downvotes: i64,
    due_date: Option<String>,  // FIXME: Use date type?
    confidential: bool,
    web_url: Option<String>
}

pub type Issues = Vec<Issue>;

#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub enum MergeRequestState {
    #[serde(rename = "merged")]
    Merged,
    #[serde(rename = "opened")]
    Opened,
    #[serde(rename = "closed")]
    Closed,
    #[serde(rename = "all")]
    All,
}

#[derive(Debug, Serialize, Deserialize)]
enum MergeRequestStatus {
    #[serde(rename = "can_be_merged")]
    CanBeMerged,
    #[serde(rename = "cannot_be_merged")]
    CannotBeMerged,
    #[serde(rename = "unchecked")]
    Unchecked,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct MergeRequest {
    id: i64,
    iid: i64,
    project_id: i64,
    title: String,
    description: String,
    state: MergeRequestState,
    created_at: String,  // FIXME: Use chrono crate
    updated_at: String,  // FIXME: Use chrono crate
    target_branch: String,
    source_branch: String,
    upvotes: i64,
    downvotes: i64,
    author: User,
    assignee: Option<User>,
    source_project_id: i64,
    target_project_id: i64,
    labels: Vec<String>,
    work_in_progress: bool,
    milestone: Option<Milestone>,
    merge_when_build_succeeds: bool,
    merge_status: MergeRequestStatus,
    sha: String,
    merge_commit_sha: Option<String>,
    subscribed: bool,
    user_notes_count: i64,
    should_remove_source_branch: Option<bool>,
    force_remove_source_branch: Option<bool>,
    web_url: String
}

pub type MergeRequests = Vec<MergeRequest>;
<|endoftext|>


<commit_before>mod expand;

use std::{fmt::Write, iter};

use syntax::{ast, AstNode, NodeOrToken, SyntaxNode, WalkEvent};
use test_utils::assert_eq_text;

use crate::ParserEntryPoint;

use super::*;

pub(crate) struct MacroFixture {
    rules: MacroRules,
}

pub(crate) struct MacroFixture2 {
    rules: MacroDef,
}

macro_rules! impl_fixture {
    ($name:ident) => {
        impl $name {
            pub(crate) fn expand_tt(&self, invocation: &str) -> tt::Subtree {
                self.try_expand_tt(invocation).unwrap()
            }

            fn try_expand_tt(&self, invocation: &str) -> Result<tt::Subtree, ExpandError> {
                let source_file = ast::SourceFile::parse(invocation).tree();
                let macro_invocation =
                    source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();

                let (invocation_tt, _) =
                    syntax_node_to_token_tree(macro_invocation.token_tree().unwrap().syntax());

                self.rules.expand(&invocation_tt).result()
            }

            #[allow(unused)]
            fn assert_expand_err(&self, invocation: &str, err: &ExpandError) {
                assert_eq!(self.try_expand_tt(invocation).as_ref(), Err(err));
            }

            #[allow(unused)]
            fn expand_items(&self, invocation: &str) -> SyntaxNode {
                let expanded = self.expand_tt(invocation);
                token_tree_to_syntax_node(&expanded, ParserEntryPoint::Items)
                    .unwrap()
                    .0
                    .syntax_node()
            }

            #[allow(unused)]
            fn expand_statements(&self, invocation: &str) -> SyntaxNode {
                let expanded = self.expand_tt(invocation);
                token_tree_to_syntax_node(&expanded, ParserEntryPoint::Statements)
                    .unwrap()
                    .0
                    .syntax_node()
            }

            #[allow(unused)]
            fn expand_expr(&self, invocation: &str) -> SyntaxNode {
                let expanded = self.expand_tt(invocation);
                token_tree_to_syntax_node(&expanded, ParserEntryPoint::Expr)
                    .unwrap()
                    .0
                    .syntax_node()
            }

            #[allow(unused)]
            fn assert_expand_tt(&self, invocation: &str, expected: &str) {
                let expansion = self.expand_tt(invocation);
                assert_eq!(expansion.to_string(), expected);
            }

            #[allow(unused)]
            fn assert_expand(&self, invocation: &str, expected: &str) {
                let expansion = self.expand_tt(invocation);
                let actual = format!("{:?}", expansion);
                test_utils::assert_eq_text!(&expected.trim(), &actual.trim());
            }

            fn assert_expand_items(&self, invocation: &str, expected: &str) -> &$name {
                self.assert_expansion(ParserEntryPoint::Items, invocation, expected);
                self
            }

            #[allow(unused)]
            fn assert_expand_statements(&self, invocation: &str, expected: &str) -> &$name {
                self.assert_expansion(ParserEntryPoint::Statements, invocation, expected);
                self
            }

            fn assert_expansion(&self, kind: ParserEntryPoint, invocation: &str, expected: &str) {
                let expanded = self.expand_tt(invocation);
                assert_eq!(expanded.to_string(), expected);

                let expected = expected.replace("$crate", "C_C__C");

                // wrap the given text to a macro call
                let expected = {
                    let wrapped = format!("wrap_macro!( {} )", expected);
                    let wrapped = ast::SourceFile::parse(&wrapped);
                    let wrapped = wrapped
                        .tree()
                        .syntax()
                        .descendants()
                        .find_map(ast::TokenTree::cast)
                        .unwrap();
                    let mut wrapped = syntax_node_to_token_tree(wrapped.syntax()).0;
                    wrapped.delimiter = None;
                    wrapped
                };

                let expanded_tree =
                    token_tree_to_syntax_node(&expanded, kind).unwrap().0.syntax_node();
                let expanded_tree = debug_dump_ignore_spaces(&expanded_tree).trim().to_string();

                let expected_tree =
                    token_tree_to_syntax_node(&expected, kind).unwrap().0.syntax_node();
                let expected_tree = debug_dump_ignore_spaces(&expected_tree).trim().to_string();

                let expected_tree = expected_tree.replace("C_C__C", "$crate");
                assert_eq!(
                    expanded_tree, expected_tree,
                    "\nleft:\n{}\nright:\n{}",
                    expanded_tree, expected_tree,
                );
            }
        }
    };
}

impl_fixture!(MacroFixture);
impl_fixture!(MacroFixture2);

pub(crate) fn parse_macro(ra_fixture: &str) -> MacroFixture {
    let definition_tt = parse_macro_rules_to_tt(ra_fixture);
    let rules = MacroRules::parse(&definition_tt).unwrap();
    MacroFixture { rules }
}

pub(crate) fn parse_macro2(ra_fixture: &str) -> MacroFixture2 {
    let definition_tt = parse_macro_def_to_tt(ra_fixture);
    let rules = MacroDef::parse(&definition_tt).unwrap();
    MacroFixture2 { rules }
}

pub(crate) fn parse_macro_error(ra_fixture: &str) -> ParseError {
    let definition_tt = parse_macro_rules_to_tt(ra_fixture);

    match MacroRules::parse(&definition_tt) {
        Ok(_) => panic!("Expect error"),
        Err(err) => err,
    }
}

pub(crate) fn parse_to_token_tree_by_syntax(ra_fixture: &str) -> tt::Subtree {
    let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap();
    let tt = syntax_node_to_token_tree(source_file.syntax()).0;

    let parsed = parse_to_token_tree(ra_fixture).unwrap().0;
    assert_eq!(tt, parsed);

    parsed
}

fn parse_macro_rules_to_tt(ra_fixture: &str) -> tt::Subtree {
    let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap();
    let macro_definition =
        source_file.syntax().descendants().find_map(ast::MacroRules::cast).unwrap();

    let (definition_tt, _) =
        syntax_node_to_token_tree(macro_definition.token_tree().unwrap().syntax());

    let parsed = parse_to_token_tree(
        &ra_fixture[macro_definition.token_tree().unwrap().syntax().text_range()],
    )
    .unwrap()
    .0;
    assert_eq!(definition_tt, parsed);

    definition_tt
}

fn parse_macro_def_to_tt(ra_fixture: &str) -> tt::Subtree {
    let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap();
    let macro_definition =
        source_file.syntax().descendants().find_map(ast::MacroDef::cast).unwrap();

    let (definition_tt, _) = syntax_node_to_token_tree(macro_definition.body().unwrap().syntax());

    let parsed =
        parse_to_token_tree(&ra_fixture[macro_definition.body().unwrap().syntax().text_range()])
            .unwrap()
            .0;
    assert_eq!(definition_tt, parsed);

    definition_tt
}

fn debug_dump_ignore_spaces(node: &syntax::SyntaxNode) -> String {
    let mut level = 0;
    let mut buf = String::new();
    macro_rules! indent {
        () => {
            for _ in 0..level {
                buf.push_str("  ");
            }
        };
    }

    for event in node.preorder_with_tokens() {
        match event {
            WalkEvent::Enter(element) => {
                match element {
                    NodeOrToken::Node(node) => {
                        indent!();
                        writeln!(buf, "{:?}", node.kind()).unwrap();
                    }
                    NodeOrToken::Token(token) => match token.kind() {
                        syntax::SyntaxKind::WHITESPACE => {}
                        _ => {
                            indent!();
                            writeln!(buf, "{:?}", token.kind()).unwrap();
                        }
                    },
                }
                level += 1;
            }
            WalkEvent::Leave(_) => level -= 1,
        }
    }

    buf
}

#[test]
fn test_node_to_tt_censor() {
    use syntax::ast::{HasAttrs, HasModuleItem};

    let source = r##"
#[attr0]
#[attr1]
#[attr2]
struct Struct {
    field: ()
}
"##;
    let source_file = ast::SourceFile::parse(source).ok().unwrap();
    let item = source_file.items().next().unwrap();
    let attr = item.attrs().nth(1).unwrap();

    let (tt, _) = syntax_node_to_token_tree_censored(
        item.syntax(),
        &iter::once(attr.syntax().clone()).collect(),
    );
    expect_test::expect![[r##"# [attr0] # [attr2] struct Struct {field : ()}"##]]
        .assert_eq(&tt.to_string());

    let source = r##"
#[attr0]
#[derive(Derive0)]
#[attr1]
#[derive(Derive1)]
#[attr2]
#[derive(Derive2)]
#[attr3]
struct Struct {
    field: ()
}
"##;
    let source_file = ast::SourceFile::parse(source).ok().unwrap();
    let item = source_file.items().next().unwrap();
    let derive_attr_index = 3;
    let censor = item
        .attrs()
        .take(derive_attr_index as usize + 1)
        .filter(|attr| attr.simple_name().as_deref() == Some("derive"))
        .map(|it| it.syntax().clone())
        .collect();

    let (tt, _) = syntax_node_to_token_tree_censored(item.syntax(), &censor);
    expect_test::expect![[r##"# [attr0] # [attr1] # [attr2] # [derive (Derive2)] # [attr3] struct Struct {field : ()}"##]]
        .assert_eq(&tt.to_string());
}
<commit_msg>dead code<commit_after>mod expand;

use std::{fmt::Write, iter};

use syntax::{ast, AstNode, NodeOrToken, SyntaxNode, WalkEvent};
use test_utils::assert_eq_text;

use crate::ParserEntryPoint;

use super::*;

pub(crate) struct MacroFixture {
    rules: MacroRules,
}

pub(crate) struct MacroFixture2 {
    rules: MacroDef,
}

macro_rules! impl_fixture {
    ($name:ident) => {
        impl $name {
            pub(crate) fn expand_tt(&self, invocation: &str) -> tt::Subtree {
                self.try_expand_tt(invocation).unwrap()
            }

            fn try_expand_tt(&self, invocation: &str) -> Result<tt::Subtree, ExpandError> {
                let source_file = ast::SourceFile::parse(invocation).tree();
                let macro_invocation =
                    source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();

                let (invocation_tt, _) =
                    syntax_node_to_token_tree(macro_invocation.token_tree().unwrap().syntax());

                self.rules.expand(&invocation_tt).result()
            }

            #[allow(unused)]
            fn assert_expand_err(&self, invocation: &str, err: &ExpandError) {
                assert_eq!(self.try_expand_tt(invocation).as_ref(), Err(err));
            }

            #[allow(unused)]
            fn expand_items(&self, invocation: &str) -> SyntaxNode {
                let expanded = self.expand_tt(invocation);
                token_tree_to_syntax_node(&expanded, ParserEntryPoint::Items)
                    .unwrap()
                    .0
                    .syntax_node()
            }

            #[allow(unused)]
            fn expand_statements(&self, invocation: &str) -> SyntaxNode {
                let expanded = self.expand_tt(invocation);
                token_tree_to_syntax_node(&expanded, ParserEntryPoint::Statements)
                    .unwrap()
                    .0
                    .syntax_node()
            }

            #[allow(unused)]
            fn expand_expr(&self, invocation: &str) -> SyntaxNode {
                let expanded = self.expand_tt(invocation);
                token_tree_to_syntax_node(&expanded, ParserEntryPoint::Expr)
                    .unwrap()
                    .0
                    .syntax_node()
            }

            #[allow(unused)]
            fn assert_expand_tt(&self, invocation: &str, expected: &str) {
                let expansion = self.expand_tt(invocation);
                assert_eq!(expansion.to_string(), expected);
            }

            #[allow(unused)]
            fn assert_expand(&self, invocation: &str, expected: &str) {
                let expansion = self.expand_tt(invocation);
                let actual = format!("{:?}", expansion);
                test_utils::assert_eq_text!(&expected.trim(), &actual.trim());
            }

            #[allow(unused)]
            fn assert_expand_items(&self, invocation: &str, expected: &str) -> &$name {
                self.assert_expansion(ParserEntryPoint::Items, invocation, expected);
                self
            }

            #[allow(unused)]
            fn assert_expand_statements(&self, invocation: &str, expected: &str) -> &$name {
                self.assert_expansion(ParserEntryPoint::Statements, invocation, expected);
                self
            }

            fn assert_expansion(&self, kind: ParserEntryPoint, invocation: &str, expected: &str) {
                let expanded = self.expand_tt(invocation);
                assert_eq!(expanded.to_string(), expected);

                let expected = expected.replace("$crate", "C_C__C");

                // wrap the given text to a macro call
                let expected = {
                    let wrapped = format!("wrap_macro!( {} )", expected);
                    let wrapped = ast::SourceFile::parse(&wrapped);
                    let wrapped = wrapped
                        .tree()
                        .syntax()
                        .descendants()
                        .find_map(ast::TokenTree::cast)
                        .unwrap();
                    let mut wrapped = syntax_node_to_token_tree(wrapped.syntax()).0;
                    wrapped.delimiter = None;
                    wrapped
                };

                let expanded_tree =
                    token_tree_to_syntax_node(&expanded, kind).unwrap().0.syntax_node();
                let expanded_tree = debug_dump_ignore_spaces(&expanded_tree).trim().to_string();

                let expected_tree =
                    token_tree_to_syntax_node(&expected, kind).unwrap().0.syntax_node();
                let expected_tree = debug_dump_ignore_spaces(&expected_tree).trim().to_string();

                let expected_tree = expected_tree.replace("C_C__C", "$crate");
                assert_eq!(
                    expanded_tree, expected_tree,
                    "\nleft:\n{}\nright:\n{}",
                    expanded_tree, expected_tree,
                );
            }
        }
    };
}

impl_fixture!(MacroFixture);
impl_fixture!(MacroFixture2);

pub(crate) fn parse_macro(ra_fixture: &str) -> MacroFixture {
    let definition_tt = parse_macro_rules_to_tt(ra_fixture);
    let rules = MacroRules::parse(&definition_tt).unwrap();
    MacroFixture { rules }
}

pub(crate) fn parse_macro_error(ra_fixture: &str) -> ParseError {
    let definition_tt = parse_macro_rules_to_tt(ra_fixture);

    match MacroRules::parse(&definition_tt) {
        Ok(_) => panic!("Expect error"),
        Err(err) => err,
    }
}

pub(crate) fn parse_to_token_tree_by_syntax(ra_fixture: &str) -> tt::Subtree {
    let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap();
    let tt = syntax_node_to_token_tree(source_file.syntax()).0;

    let parsed = parse_to_token_tree(ra_fixture).unwrap().0;
    assert_eq!(tt, parsed);

    parsed
}

fn parse_macro_rules_to_tt(ra_fixture: &str) -> tt::Subtree {
    let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap();
    let macro_definition =
        source_file.syntax().descendants().find_map(ast::MacroRules::cast).unwrap();

    let (definition_tt, _) =
        syntax_node_to_token_tree(macro_definition.token_tree().unwrap().syntax());

    let parsed = parse_to_token_tree(
        &ra_fixture[macro_definition.token_tree().unwrap().syntax().text_range()],
    )
    .unwrap()
    .0;
    assert_eq!(definition_tt, parsed);

    definition_tt
}

fn debug_dump_ignore_spaces(node: &syntax::SyntaxNode) -> String {
    let mut level = 0;
    let mut buf = String::new();
    macro_rules! indent {
        () => {
            for _ in 0..level {
                buf.push_str("  ");
            }
        };
    }

    for event in node.preorder_with_tokens() {
        match event {
            WalkEvent::Enter(element) => {
                match element {
                    NodeOrToken::Node(node) => {
                        indent!();
                        writeln!(buf, "{:?}", node.kind()).unwrap();
                    }
                    NodeOrToken::Token(token) => match token.kind() {
                        syntax::SyntaxKind::WHITESPACE => {}
                        _ => {
                            indent!();
                            writeln!(buf, "{:?}", token.kind()).unwrap();
                        }
                    },
                }
                level += 1;
            }
            WalkEvent::Leave(_) => level -= 1,
        }
    }

    buf
}

#[test]
fn test_node_to_tt_censor() {
    use syntax::ast::{HasAttrs, HasModuleItem};

    let source = r##"
#[attr0]
#[attr1]
#[attr2]
struct Struct {
    field: ()
}
"##;
    let source_file = ast::SourceFile::parse(source).ok().unwrap();
    let item = source_file.items().next().unwrap();
    let attr = item.attrs().nth(1).unwrap();

    let (tt, _) = syntax_node_to_token_tree_censored(
        item.syntax(),
        &iter::once(attr.syntax().clone()).collect(),
    );
    expect_test::expect![[r##"# [attr0] # [attr2] struct Struct {field : ()}"##]]
        .assert_eq(&tt.to_string());

    let source = r##"
#[attr0]
#[derive(Derive0)]
#[attr1]
#[derive(Derive1)]
#[attr2]
#[derive(Derive2)]
#[attr3]
struct Struct {
    field: ()
}
"##;
    let source_file = ast::SourceFile::parse(source).ok().unwrap();
    let item = source_file.items().next().unwrap();
    let derive_attr_index = 3;
    let censor = item
        .attrs()
        .take(derive_attr_index as usize + 1)
        .filter(|attr| attr.simple_name().as_deref() == Some("derive"))
        .map(|it| it.syntax().clone())
        .collect();

    let (tt, _) = syntax_node_to_token_tree_censored(item.syntax(), &censor);
    expect_test::expect![[r##"# [attr0] # [attr1] # [attr2] # [derive (Derive2)] # [attr3] struct Struct {field : ()}"##]]
        .assert_eq(&tt.to_string());
}
<|endoftext|>


<commit_before>/// Represents a value in Forth's stack
#[derive(Clone, Copy)]
pub struct ForthNum {
    value: i32,
}

impl From<i32> for ForthNum {
    fn from(value: i32) -> ForthNum {
        ForthNum { value: value }
    }
}

impl From<ForthNum> for i32 {
    fn from(num: ForthNum) -> i32 {
        num.value
    }
}

impl From<bool> for ForthNum {
    fn from(value: bool) -> ForthNum {
        ForthNum { value: if value { -1 } else { 0 } }
    }
}

impl From<ForthNum> for bool {
    fn from(num: ForthNum) -> bool {
        num.value != 0
    }
}

impl From<char> for ForthNum {
    fn from(value: char) -> ForthNum {
        ForthNum { value: value as i32 }
    }
}

impl From<ForthNum> for char {
    fn from(num: ForthNum) -> char {
        num.value as u8 as char
    }
}
<commit_msg>Run "cargo fmt"<commit_after>/// Represents a value in Forth's stack
#[derive(Clone, Copy)]
pub struct ForthNum {
    value: i32,
}

impl From<i32> for ForthNum {
    fn from(value: i32) -> ForthNum {
        ForthNum { value: value }
    }
}

impl From<ForthNum> for i32 {
    fn from(num: ForthNum) -> i32 {
        num.value
    }
}

impl From<bool> for ForthNum {
    fn from(value: bool) -> ForthNum {
        ForthNum {
            value: if value {
                -1
            } else {
                0
            },
        }
    }
}

impl From<ForthNum> for bool {
    fn from(num: ForthNum) -> bool {
        num.value != 0
    }
}

impl From<char> for ForthNum {
    fn from(value: char) -> ForthNum {
        ForthNum { value: value as i32 }
    }
}

impl From<ForthNum> for char {
    fn from(num: ForthNum) -> char {
        num.value as u8 as char
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use syntax::{ast, ast_util, ext};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic;
use syntax::codemap;
use syntax::parse::token;
use syntax::ptr::P;

#[deriving(PartialEq, Show)]
enum ParamType {
    ParamUniform,
    ParamBlock,
    ParamTexture,
}

#[deriving(Show)]
enum ParamError {
    ErrorDeprecatedTexture,
    ErrorUnknown,
}

/// Classify variable types (`i32`, `TextureParam`, etc) into the `ParamType`
fn classify(node: &ast::Ty_) -> Result<ParamType, ParamError> {
    match *node {
        ast::TyPath(ref path, _, _) => match path.segments.last() {
            Some(segment) => match segment.identifier.name.as_str() {
                "RawBufferHandle" => Ok(ParamBlock),
                "TextureParam" => Ok(ParamTexture),
                "TextureHandle" => Err(ErrorDeprecatedTexture),
                _ => Ok(ParamUniform),
            },
            None => Ok(ParamUniform),
        },
        _ => Ok(ParamUniform),
    }
}

/// Generates the the method body for `gfx::shade::ParamValues::create_link`
fn method_create(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
                 substr: &generic::Substructure,
                 link_name: &str,
                 path_root: ast::Ident) -> P<ast::Expr> {
    let link_ident = cx.ident_of(link_name);
    match *substr.fields {
        generic::StaticStruct(definition, generic::Named(ref fields)) => {
            let init_expr = cx.expr_struct_ident(
                span, link_ident,
                fields.iter().map(|&(fname, fspan)| {
                    cx.field_imm(fspan, fname, cx.expr_none(fspan))
                }).collect()
            );
            let class_info: Vec<(ParamType, P<ast::Expr>)> = definition.fields.iter()
                    .zip(fields.iter()).scan((), |_, (def, &(fname, fspan))|
                match classify(&def.node.ty.node) {
                    Ok(c) => {
                        let name = match super::find_name(cx, span, def.node.attrs.as_slice()) {
                            Some(name) => name,
                            None => token::get_ident(fname),
                        };
                        Some((c, cx.expr_str(fspan, name)))
                    },
                    Err(e) => {
                        cx.span_err(fspan, format!(
                            "Unrecognized parameter ({}) type {}",
                            fname.as_str(), e
                            ).as_slice()
                        );
                        None
                    },
                }
            ).collect();
            let gen_arms = |ptype: ParamType, var: ast::Ident| -> Vec<ast::Arm> {
                class_info.iter().zip(fields.iter())
                          .filter(|&(&(class, _), _)| class == ptype)
                          .map(|(&(_, ref name_expr), &(fname, fspan))|
                    cx.arm(fspan,
                        vec![cx.pat_lit(fspan, name_expr.clone())],
                        quote_expr!(cx,
                            out.$fname = Some(i as $path_root::gfx::shade::$var)
                        )
                    )
                ).collect()
            };
            let uniform_arms = gen_arms(ParamUniform, cx.ident_of("VarUniform"));
            let block_arms = gen_arms(ParamBlock, cx.ident_of("VarBlock"));
            let texture_arms = gen_arms(ParamTexture, cx.ident_of("VarTexture"));
            let input = &substr.nonself_args[1];
            quote_expr!(cx, {
                let mut out = $init_expr;
                for (i, u) in $input.uniforms.iter().enumerate() {
                    match u.name.as_slice() {
                        $uniform_arms
                        _ => return Err($path_root::gfx::shade::MissingUniform(u.name.clone())),
                    }
                }
                for (i, b) in $input.blocks.iter().enumerate() {
                    match b.name.as_slice() {
                        $block_arms
                        _ => return Err($path_root::gfx::shade::MissingBlock(b.name.clone())),
                    }
                }
                for (i, t) in $input.textures.iter().enumerate() {
                    match t.name.as_slice() {
                        $texture_arms
                        _ => return Err($path_root::gfx::shade::MissingTexture(t.name.clone())),
                    }
                }
                Ok(out)
            })
        },
        _ => {
            cx.span_err(span, "Unable to implement `ShaderParam::create_link()` on a non-structure");
            cx.expr_lit(span, ast::LitNil)
        },
    }
}

/// Generates the the method body for `gfx::shade::ParamValues::fill_params`
fn method_fill(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
               substr: &generic::Substructure,
               definition: P<ast::StructDef>,
               path_root: ast::Ident)
               -> P<ast::Expr> {
    match *substr.fields {
        generic::Struct(ref fields) => {
            let out = &substr.nonself_args[1];
            let max_num = cx.expr_uint(span, fields.len());
            let mut calls = vec![
                quote_stmt!(cx, $out.uniforms.reserve($max_num);),
                quote_stmt!(cx, $out.blocks.reserve($max_num);),
                quote_stmt!(cx, $out.textures.reserve($max_num);),
            ];
            calls.push_all_move(definition.fields.iter().zip(fields.iter())
                                .map(|(def, f)| {
                let value_id = &f.self_;
                let var_id = cx.expr_field_access(
                    span,
                    substr.nonself_args[0].clone(),
                    f.name.unwrap()
                    );
                match classify(&def.node.ty.node) {
                    Ok(ParamUniform) => quote_stmt!(cx,
                        $var_id.map_or((), |id| {
                            if $out.uniforms.len() <= id as uint {
                                unsafe { $out.uniforms.set_len(id as uint + 1) }
                            }
                            *$out.uniforms.get_mut(id as uint) = $value_id.to_uniform()
                        })
                    ),
                    Ok(ParamBlock)   => quote_stmt!(cx,
                        $var_id.map_or((), |id| {
                            if $out.blocks.len() <= id as uint {
                                unsafe { $out.blocks.set_len(id as uint + 1) }
                            }
                            *$out.blocks.get_mut(id as uint) = {$value_id}
                        })
                    ),
                    Ok(ParamTexture) => quote_stmt!(cx,
                        $var_id.map_or((), |id| {
                            if $out.textures.len() <= id as uint {
                                unsafe { $out.textures.set_len(id as uint + 1) }
                            }
                            *$out.textures.get_mut(id as uint) = {$value_id}
                        })
                    ),
                    Err(_) => {
                        cx.span_err(span, format!(
                            "Invalid uniform: {}",
                            f.name.unwrap().as_str(),
                            ).as_slice()
                        );
                        cx.stmt_expr(cx.expr_uint(span, 0))
                    },
                }
            }).collect());
            let view = cx.view_use_simple(
                span,
                ast::Inherited,
                cx.path(span, vec![
                    cx.ident_of("self"),
                    path_root,
                    cx.ident_of("gfx"),
                    cx.ident_of("shade"),
                    cx.ident_of("ToUniform"),
                ])
            );
            cx.expr_block(cx.block_all(span, vec![view], calls, None))
        },
        _ => {
            cx.span_err(span, "Unable to implement `ShaderParam::bind()` on a non-structure");
            cx.expr_lit(span, ast::LitNil)
        }
    }
}

/// A helper function that translates variable type (`i32`, `TextureHandle`, etc)
/// into the corresponding shader var id type (`VarUniform`, `VarBlock`, or `VarTexture`)
fn node_to_var_type(cx: &mut ext::base::ExtCtxt,
                    span: codemap::Span, node: &ast::Ty_,
                    path_root: ast::Ident) -> P<ast::Ty> {
    let id = match classify(node) {
        Ok(ParamUniform) => "VarUniform",
        Ok(ParamBlock)   => "VarBlock",
        Ok(ParamTexture) => "VarTexture",
        Err(ErrorDeprecatedTexture) => {
            cx.span_err(span, "Use gfx::shade::TextureParam for texture vars instead of gfx::shade::TextureHandle");
            ""
        },
        Err(ErrorUnknown) => {
            cx.span_err(span, format!("Unknown node: {}", node).as_slice());
            ""
        },
    };
    cx.ty_option(cx.ty_path(
        cx.path(span, vec![
            path_root,
            cx.ident_of("gfx"),
            cx.ident_of("shade"),
            cx.ident_of(id),
        ]),
        None
    ))
}

/// Extract all deriving() attributes into a separate array
fn copy_deriving(attribs: &[ast::Attribute]) -> Vec<ast::Attribute> {
    attribs.iter().filter(|at| {
        match at.node.value.node {
            ast::MetaList(ref s, _) => s.get() == "deriving",
            _ => false,
        }
    }).map(|at| at.clone()).collect()
}

/// Decorator for `shader_param` attribute
pub fn expand(context: &mut ext::base::ExtCtxt, span: codemap::Span,
              meta_item: &ast::MetaItem, item: &ast::Item,
              push: |P<ast::Item>|) {
    // Insert the `gfx` reexport module
    let path_root = super::extern_crate_hack(context, span, |i| push(i));

    // constructing the Link struct
    let (base_def, link_def) = match item.node {
        ast::ItemStruct(ref definition, ref generics) => {
            if generics.lifetimes.len() > 0 {
                context.bug("Generics are not allowed in ShaderParam struct");
            }
            (definition, ast::StructDef {
                fields: definition.fields.iter()
                    .map(|f| codemap::Spanned {
                        node: ast::StructField_ {
                            kind: f.node.kind,
                            id: f.node.id,
                            ty: node_to_var_type(context, f.span, &f.node.ty.node, path_root),
                            attrs: Vec::new(),
                        },
                        span: f.span,
                    }).collect(),
                ctor_id: None,
                super_struct: None,
                is_virtual: false,
            })
        },
        _ => {
            context.span_err(span, "Only free-standing named structs allowed to derive ShaderParam");
            return;
        }
    };
    let link_name = format!("_{}Link", item.ident.as_str());
    let link_ident = context.ident_of(link_name.as_slice());
    let link_ty = box generic::ty::Literal(
        generic::ty::Path::new_local(link_name.as_slice())
    );
    // Almost `context.item_struct(span, link_ident, link_def)` but with visibility
    push(P(ast::Item {
        ident: link_ident,
        attrs: copy_deriving(item.attrs.as_slice()),
        id: ast::DUMMY_NODE_ID,
        node: ast::ItemStruct(
            P(link_def),
            ast_util::empty_generics()
        ),
        vis: item.vis,
        span: span,
    }));
    // constructing the `Batch` implementation typedef
    match meta_item.node {
        ast::MetaList(_, ref items) if items.len() <= 2 => {
            let batch_names = ["RefBatch", "OwnedBatch"];
            for (&batch, param) in batch_names.iter().zip(items.iter()) {
                match param.node {
                    ast::MetaWord(ref shell_name) => {
                        // pub type $shell_ident = hack::gfx::batch::RefBatch<$link_ident, $self_ident>
                        let path = context.ty_path(
                            context.path_all(span, false,
                                vec![
                                    path_root,
                                    context.ident_of("gfx"),
                                    context.ident_of("batch"),
                                    context.ident_of(batch),
                                ],
                                Vec::new(),
                                vec![
                                    context.ty_ident(span, link_ident),
                                    context.ty_ident(span, item.ident)
                                ]
                            ), None
                        );
                        push(P(ast::Item {
                            ident: context.ident_of(shell_name.get()),
                            attrs: Vec::new(),
                            id: ast::DUMMY_NODE_ID,
                            node: ast::ItemTy(path, ast_util::empty_generics()),
                            vis: item.vis,
                            span: span,
                        }))
                    },
                    _ => {
                        context.span_err(meta_item.span,
                            "The new batch name has to be a word")
                    }
                }
            }
        },
        _ => {
            context.span_err(meta_item.span,
                "Invalid argument. Please specify the typedef for your `Program`\n\
                as `#[shader_param(MyLightBatch, MyHeavyBatch)]`")
        }
    }
    // deriving ShaderParam
    let trait_def = generic::TraitDef {
        span: span,
        attributes: Vec::new(),
        path: generic::ty::Path {
            path: vec![super::EXTERN_CRATE_HACK, "gfx", "shade", "ShaderParam"],
            lifetime: None,
            params: vec![link_ty.clone()],
            global: false,
        },
        additional_bounds: Vec::new(),
        generics: generic::ty::LifetimeBounds::empty(),
        methods: vec![
            generic::MethodDef {
                name: "create_link",
                generics: generic::ty::LifetimeBounds::empty(),
                explicit_self: None,
                args: vec![
                    generic::ty::Literal(generic::ty::Path {
                        path: vec!["Option"],
                        lifetime: None,
                        params: vec![
                            box generic::ty::Ptr(
                                box generic::ty::Self,
                                generic::ty::Borrowed(None, ast::MutImmutable)
                            ),
                        ],
                        global: false,
                    }),
                    generic::ty::Ptr(
                        box generic::ty::Literal(generic::ty::Path::new(
                            vec![super::EXTERN_CRATE_HACK, "gfx", "ProgramInfo"])),
                        generic::ty::Borrowed(None, ast::MutImmutable)
                    ),
                ],
                ret_ty: generic::ty::Literal(
                    generic::ty::Path {
                        path: vec!["Result"],
                        lifetime: None,
                        params: vec![
                            link_ty.clone(),
                            box generic::ty::Literal(generic::ty::Path::new(
                                vec![super::EXTERN_CRATE_HACK, "gfx", "shade", "ParameterError"]
                            ))
                        ],
                        global: false,
                    },
                ),
                attributes: Vec::new(),
                combine_substructure: generic::combine_substructure(|cx, span, sub|
                    method_create(cx, span, sub, link_name.as_slice(), path_root)
                ),
            },
            generic::MethodDef {
                name: "fill_params",
                generics: generic::ty::LifetimeBounds::empty(),
                explicit_self: Some(Some(generic::ty::Borrowed(
                    None, ast::MutImmutable
                ))),
                args: vec![
                    generic::ty::Ptr(
                        link_ty.clone(),
                        generic::ty::Borrowed(None, ast::MutImmutable)
                    ),
                    generic::ty::Literal(
                        generic::ty::Path::new(vec![super::EXTERN_CRATE_HACK, "gfx", "shade", "ParamValues"]),
                    ),
                ],
                ret_ty: generic::ty::Tuple(Vec::new()),
                attributes: Vec::new(),
                combine_substructure: generic::combine_substructure(|cx, span, sub|
                    method_fill(cx, span, sub, base_def.clone(), path_root)
                ),
            },
        ],
    };
    let fixup = |item| {
        push(super::fixup_extern_crate_paths(item, path_root))
    };
    trait_def.expand(context, meta_item, item, fixup);
}
<commit_msg>Suppress unused warning when using shader_param<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use syntax::{ast, ast_util, ext};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic;
use syntax::codemap;
use syntax::parse::token;
use syntax::ptr::P;

#[deriving(PartialEq, Show)]
enum ParamType {
    ParamUniform,
    ParamBlock,
    ParamTexture,
}

#[deriving(Show)]
enum ParamError {
    ErrorDeprecatedTexture,
    ErrorUnknown,
}

/// Classify variable types (`i32`, `TextureParam`, etc) into the `ParamType`
fn classify(node: &ast::Ty_) -> Result<ParamType, ParamError> {
    match *node {
        ast::TyPath(ref path, _, _) => match path.segments.last() {
            Some(segment) => match segment.identifier.name.as_str() {
                "RawBufferHandle" => Ok(ParamBlock),
                "TextureParam" => Ok(ParamTexture),
                "TextureHandle" => Err(ErrorDeprecatedTexture),
                _ => Ok(ParamUniform),
            },
            None => Ok(ParamUniform),
        },
        _ => Ok(ParamUniform),
    }
}

/// Generates the the method body for `gfx::shade::ParamValues::create_link`
fn method_create(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
                 substr: &generic::Substructure,
                 link_name: &str,
                 path_root: ast::Ident) -> P<ast::Expr> {
    let link_ident = cx.ident_of(link_name);
    match *substr.fields {
        generic::StaticStruct(definition, generic::Named(ref fields)) => {
            let init_expr = cx.expr_struct_ident(
                span, link_ident,
                fields.iter().map(|&(fname, fspan)| {
                    cx.field_imm(fspan, fname, cx.expr_none(fspan))
                }).collect()
            );
            let class_info: Vec<(ParamType, P<ast::Expr>)> = definition.fields.iter()
                    .zip(fields.iter()).scan((), |_, (def, &(fname, fspan))|
                match classify(&def.node.ty.node) {
                    Ok(c) => {
                        let name = match super::find_name(cx, span, def.node.attrs.as_slice()) {
                            Some(name) => name,
                            None => token::get_ident(fname),
                        };
                        Some((c, cx.expr_str(fspan, name)))
                    },
                    Err(e) => {
                        cx.span_err(fspan, format!(
                            "Unrecognized parameter ({}) type {}",
                            fname.as_str(), e
                            ).as_slice()
                        );
                        None
                    },
                }
            ).collect();
            let gen_arms = |ptype: ParamType, var: ast::Ident| -> Vec<ast::Arm> {
                class_info.iter().zip(fields.iter())
                          .filter(|&(&(class, _), _)| class == ptype)
                          .map(|(&(_, ref name_expr), &(fname, fspan))|
                    cx.arm(fspan,
                        vec![cx.pat_lit(fspan, name_expr.clone())],
                        quote_expr!(cx,
                            out.$fname = Some(i as $path_root::gfx::shade::$var)
                        )
                    )
                ).collect()
            };
            let uniform_arms = gen_arms(ParamUniform, cx.ident_of("VarUniform"));
            let block_arms = gen_arms(ParamBlock, cx.ident_of("VarBlock"));
            let texture_arms = gen_arms(ParamTexture, cx.ident_of("VarTexture"));
            let input = &substr.nonself_args[1];
            quote_expr!(cx, {
                let mut out = $init_expr;
                for (i, u) in $input.uniforms.iter().enumerate() {
                    let _ = i; // suppress warning about unused i
                    match u.name.as_slice() {
                        $uniform_arms
                        _ => return Err($path_root::gfx::shade::MissingUniform(u.name.clone())),
                    }
                }
                for (i, b) in $input.blocks.iter().enumerate() {
                    let _ = i; // suppress warning about unused i
                    match b.name.as_slice() {
                        $block_arms
                        _ => return Err($path_root::gfx::shade::MissingBlock(b.name.clone())),
                    }
                }
                for (i, t) in $input.textures.iter().enumerate() {
                    let _ = i; // suppress warning about unused i
                    match t.name.as_slice() {
                        $texture_arms
                        _ => return Err($path_root::gfx::shade::MissingTexture(t.name.clone())),
                    }
                }
                Ok(out)
            })
        },
        _ => {
            cx.span_err(span, "Unable to implement `ShaderParam::create_link()` on a non-structure");
            cx.expr_lit(span, ast::LitNil)
        },
    }
}

/// Generates the the method body for `gfx::shade::ParamValues::fill_params`
fn method_fill(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
               substr: &generic::Substructure,
               definition: P<ast::StructDef>,
               path_root: ast::Ident)
               -> P<ast::Expr> {
    match *substr.fields {
        generic::Struct(ref fields) => {
            let out = &substr.nonself_args[1];
            let max_num = cx.expr_uint(span, fields.len());
            let mut calls = vec![
                quote_stmt!(cx, $out.uniforms.reserve($max_num);),
                quote_stmt!(cx, $out.blocks.reserve($max_num);),
                quote_stmt!(cx, $out.textures.reserve($max_num);),
            ];
            calls.push_all_move(definition.fields.iter().zip(fields.iter())
                                .map(|(def, f)| {
                let value_id = &f.self_;
                let var_id = cx.expr_field_access(
                    span,
                    substr.nonself_args[0].clone(),
                    f.name.unwrap()
                    );
                match classify(&def.node.ty.node) {
                    Ok(ParamUniform) => quote_stmt!(cx,
                        $var_id.map_or((), |id| {
                            if $out.uniforms.len() <= id as uint {
                                unsafe { $out.uniforms.set_len(id as uint + 1) }
                            }
                            *$out.uniforms.get_mut(id as uint) = $value_id.to_uniform()
                        })
                    ),
                    Ok(ParamBlock)   => quote_stmt!(cx,
                        $var_id.map_or((), |id| {
                            if $out.blocks.len() <= id as uint {
                                unsafe { $out.blocks.set_len(id as uint + 1) }
                            }
                            *$out.blocks.get_mut(id as uint) = {$value_id}
                        })
                    ),
                    Ok(ParamTexture) => quote_stmt!(cx,
                        $var_id.map_or((), |id| {
                            if $out.textures.len() <= id as uint {
                                unsafe { $out.textures.set_len(id as uint + 1) }
                            }
                            *$out.textures.get_mut(id as uint) = {$value_id}
                        })
                    ),
                    Err(_) => {
                        cx.span_err(span, format!(
                            "Invalid uniform: {}",
                            f.name.unwrap().as_str(),
                            ).as_slice()
                        );
                        cx.stmt_expr(cx.expr_uint(span, 0))
                    },
                }
            }).collect());
            let view = cx.view_use_simple(
                span,
                ast::Inherited,
                cx.path(span, vec![
                    cx.ident_of("self"),
                    path_root,
                    cx.ident_of("gfx"),
                    cx.ident_of("shade"),
                    cx.ident_of("ToUniform"),
                ])
            );
            cx.expr_block(cx.block_all(span, vec![view], calls, None))
        },
        _ => {
            cx.span_err(span, "Unable to implement `ShaderParam::bind()` on a non-structure");
            cx.expr_lit(span, ast::LitNil)
        }
    }
}

/// A helper function that translates variable type (`i32`, `TextureHandle`, etc)
/// into the corresponding shader var id type (`VarUniform`, `VarBlock`, or `VarTexture`)
fn node_to_var_type(cx: &mut ext::base::ExtCtxt,
                    span: codemap::Span, node: &ast::Ty_,
                    path_root: ast::Ident) -> P<ast::Ty> {
    let id = match classify(node) {
        Ok(ParamUniform) => "VarUniform",
        Ok(ParamBlock)   => "VarBlock",
        Ok(ParamTexture) => "VarTexture",
        Err(ErrorDeprecatedTexture) => {
            cx.span_err(span, "Use gfx::shade::TextureParam for texture vars instead of gfx::shade::TextureHandle");
            ""
        },
        Err(ErrorUnknown) => {
            cx.span_err(span, format!("Unknown node: {}", node).as_slice());
            ""
        },
    };
    cx.ty_option(cx.ty_path(
        cx.path(span, vec![
            path_root,
            cx.ident_of("gfx"),
            cx.ident_of("shade"),
            cx.ident_of(id),
        ]),
        None
    ))
}

/// Extract all deriving() attributes into a separate array
fn copy_deriving(attribs: &[ast::Attribute]) -> Vec<ast::Attribute> {
    attribs.iter().filter(|at| {
        match at.node.value.node {
            ast::MetaList(ref s, _) => s.get() == "deriving",
            _ => false,
        }
    }).map(|at| at.clone()).collect()
}

/// Decorator for `shader_param` attribute
pub fn expand(context: &mut ext::base::ExtCtxt, span: codemap::Span,
              meta_item: &ast::MetaItem, item: &ast::Item,
              push: |P<ast::Item>|) {
    // Insert the `gfx` reexport module
    let path_root = super::extern_crate_hack(context, span, |i| push(i));

    // constructing the Link struct
    let (base_def, link_def) = match item.node {
        ast::ItemStruct(ref definition, ref generics) => {
            if generics.lifetimes.len() > 0 {
                context.bug("Generics are not allowed in ShaderParam struct");
            }
            (definition, ast::StructDef {
                fields: definition.fields.iter()
                    .map(|f| codemap::Spanned {
                        node: ast::StructField_ {
                            kind: f.node.kind,
                            id: f.node.id,
                            ty: node_to_var_type(context, f.span, &f.node.ty.node, path_root),
                            attrs: Vec::new(),
                        },
                        span: f.span,
                    }).collect(),
                ctor_id: None,
                super_struct: None,
                is_virtual: false,
            })
        },
        _ => {
            context.span_err(span, "Only free-standing named structs allowed to derive ShaderParam");
            return;
        }
    };
    let link_name = format!("_{}Link", item.ident.as_str());
    let link_ident = context.ident_of(link_name.as_slice());
    let link_ty = box generic::ty::Literal(
        generic::ty::Path::new_local(link_name.as_slice())
    );
    // Almost `context.item_struct(span, link_ident, link_def)` but with visibility
    push(P(ast::Item {
        ident: link_ident,
        attrs: copy_deriving(item.attrs.as_slice()),
        id: ast::DUMMY_NODE_ID,
        node: ast::ItemStruct(
            P(link_def),
            ast_util::empty_generics()
        ),
        vis: item.vis,
        span: span,
    }));
    // constructing the `Batch` implementation typedef
    match meta_item.node {
        ast::MetaList(_, ref items) if items.len() <= 2 => {
            let batch_names = ["RefBatch", "OwnedBatch"];
            for (&batch, param) in batch_names.iter().zip(items.iter()) {
                match param.node {
                    ast::MetaWord(ref shell_name) => {
                        // pub type $shell_ident = hack::gfx::batch::RefBatch<$link_ident, $self_ident>
                        let path = context.ty_path(
                            context.path_all(span, false,
                                vec![
                                    path_root,
                                    context.ident_of("gfx"),
                                    context.ident_of("batch"),
                                    context.ident_of(batch),
                                ],
                                Vec::new(),
                                vec![
                                    context.ty_ident(span, link_ident),
                                    context.ty_ident(span, item.ident)
                                ]
                            ), None
                        );
                        push(P(ast::Item {
                            ident: context.ident_of(shell_name.get()),
                            attrs: Vec::new(),
                            id: ast::DUMMY_NODE_ID,
                            node: ast::ItemTy(path, ast_util::empty_generics()),
                            vis: item.vis,
                            span: span,
                        }))
                    },
                    _ => {
                        context.span_err(meta_item.span,
                            "The new batch name has to be a word")
                    }
                }
            }
        },
        _ => {
            context.span_err(meta_item.span,
                "Invalid argument. Please specify the typedef for your `Program`\n\
                as `#[shader_param(MyLightBatch, MyHeavyBatch)]`")
        }
    }
    // deriving ShaderParam
    let trait_def = generic::TraitDef {
        span: span,
        attributes: Vec::new(),
        path: generic::ty::Path {
            path: vec![super::EXTERN_CRATE_HACK, "gfx", "shade", "ShaderParam"],
            lifetime: None,
            params: vec![link_ty.clone()],
            global: false,
        },
        additional_bounds: Vec::new(),
        generics: generic::ty::LifetimeBounds::empty(),
        methods: vec![
            generic::MethodDef {
                name: "create_link",
                generics: generic::ty::LifetimeBounds::empty(),
                explicit_self: None,
                args: vec![
                    generic::ty::Literal(generic::ty::Path {
                        path: vec!["Option"],
                        lifetime: None,
                        params: vec![
                            box generic::ty::Ptr(
                                box generic::ty::Self,
                                generic::ty::Borrowed(None, ast::MutImmutable)
                            ),
                        ],
                        global: false,
                    }),
                    generic::ty::Ptr(
                        box generic::ty::Literal(generic::ty::Path::new(
                            vec![super::EXTERN_CRATE_HACK, "gfx", "ProgramInfo"])),
                        generic::ty::Borrowed(None, ast::MutImmutable)
                    ),
                ],
                ret_ty: generic::ty::Literal(
                    generic::ty::Path {
                        path: vec!["Result"],
                        lifetime: None,
                        params: vec![
                            link_ty.clone(),
                            box generic::ty::Literal(generic::ty::Path::new(
                                vec![super::EXTERN_CRATE_HACK, "gfx", "shade", "ParameterError"]
                            ))
                        ],
                        global: false,
                    },
                ),
                attributes: Vec::new(),
                combine_substructure: generic::combine_substructure(|cx, span, sub|
                    method_create(cx, span, sub, link_name.as_slice(), path_root)
                ),
            },
            generic::MethodDef {
                name: "fill_params",
                generics: generic::ty::LifetimeBounds::empty(),
                explicit_self: Some(Some(generic::ty::Borrowed(
                    None, ast::MutImmutable
                ))),
                args: vec![
                    generic::ty::Ptr(
                        link_ty.clone(),
                        generic::ty::Borrowed(None, ast::MutImmutable)
                    ),
                    generic::ty::Literal(
                        generic::ty::Path::new(vec![super::EXTERN_CRATE_HACK, "gfx", "shade", "ParamValues"]),
                    ),
                ],
                ret_ty: generic::ty::Tuple(Vec::new()),
                attributes: Vec::new(),
                combine_substructure: generic::combine_substructure(|cx, span, sub|
                    method_fill(cx, span, sub, base_def.clone(), path_root)
                ),
            },
        ],
    };
    let fixup = |item| {
        push(super::fixup_extern_crate_paths(item, path_root))
    };
    trait_def.expand(context, meta_item, item, fixup);
}
<|endoftext|>


<commit_before>use libc;
use std::io;

pub mod public {
    use libc;
    use std::time::Duration;

    pub type CSocket = libc::c_int;
    pub type Buf = *const libc::c_void;
    pub type MutBuf = *mut libc::c_void;
    pub type BufLen = libc::size_t;
    pub type CouldFail = libc::ssize_t;
    pub type SockLen = libc::socklen_t;
    pub type MutSockLen = *mut libc::socklen_t;
    pub type SockAddr = libc::sockaddr;
    pub type SockAddrIn = libc::sockaddr_in;
    pub type SockAddrIn6 = libc::sockaddr_in6;
    pub type SockAddrStorage = libc::sockaddr_storage;
    pub type SockAddrFamily = libc::sa_family_t;
    pub type SockAddrFamily6 = libc::sa_family_t;
    pub type InAddr = libc::in_addr;
    pub type In6Addr = libc::in6_addr;

    #[cfg(not(targetos="macos"))]
    pub type TvUsecType = libc::c_long;
    #[cfg(targetos="macos")]
    pub type TvUsecType = libc::__darwin_suseconds_t;

    pub const AF_INET: libc::c_int = libc::AF_INET;
    pub const AF_INET6: libc::c_int = libc::AF_INET6;
    pub const SOCK_RAW: libc::c_int = libc::SOCK_RAW;

    pub const SOL_SOCKET: libc::c_int = libc::SOL_SOCKET;
    pub const SO_RCVTIMEO: libc::c_int = libc::SO_RCVTIMEO;
    pub const SO_SNDTIMEO: libc::c_int = libc::SO_SNDTIMEO;

    pub const IPPROTO_IP: libc::c_int = libc::IPPROTO_IP;
    pub const IP_HDRINCL: libc::c_int = libc::IP_HDRINCL;
    pub const IP_TTL: libc::c_int = libc::IP_TTL;

    pub use libc::{IFF_UP, IFF_BROADCAST, IFF_LOOPBACK, IFF_POINTOPOINT, IFF_MULTICAST};

    pub const INVALID_SOCKET: CSocket = -1;

    pub unsafe fn close(sock: CSocket) {
        let _ = libc::close(sock);
    }

    pub unsafe fn socket(af: libc::c_int, sock: libc::c_int, proto: libc::c_int) -> CSocket {
        libc::socket(af, sock, proto)
    }

    pub unsafe fn getsockopt(socket: CSocket,
                            level: libc::c_int,
                            name: libc::c_int,
                            value: MutBuf,
                            option_len: MutSockLen)
        -> libc::c_int {
        libc::getsockopt(socket, level, name, value, option_len)
    }

    pub unsafe fn setsockopt(socket: CSocket,
                            level: libc::c_int,
                            name: libc::c_int,
                            value: Buf,
                            option_len: SockLen)
        -> libc::c_int {
        libc::setsockopt(socket, level, name, value, option_len)
    }

    /// Convert a platform specific `timeval` into a Duration
    pub fn timeval_to_duration(tv: libc::timeval) -> Duration {
        Duration::new(tv.tv_sec as u64, (tv.tv_usec as u32) * 1000)
    }

    /// Convert a Duration into a platform specific `timeval`
    pub fn duration_to_timeval(dur: Duration) -> libc::timeval {
        libc::timeval {
            tv_sec: dur.as_secs() as libc::time_t,
            tv_usec: dur.subsec_micros() as TvUsecType
        }
    }

    /// Convert a platform specific `timespec` into a Duration
    pub fn timespec_to_duration(ts: libc::timespec) -> Duration {
        Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32)
    }

    /// Convert a Duration into a platform specific `timespec`
    pub fn duration_to_timespec(dur: Duration) -> libc::timespec {
        libc::timespec {
            tv_sec: dur.as_secs() as libc::time_t,
            tv_nsec: dur.subsec_nanos() as TvUsecType
        }
    }

}

use self::public::*;

#[inline(always)]
pub fn ipv4_addr(addr: InAddr) -> u32 {
    (addr.s_addr as u32).to_be()
}

#[inline(always)]
pub fn mk_inaddr(addr: u32) -> InAddr {
    InAddr { s_addr: addr }
}

pub unsafe fn sendto(socket: CSocket,
                     buf: Buf,
                     len: BufLen,
                     flags: libc::c_int,
                     addr: *const SockAddr,
                     addrlen: SockLen)
    -> CouldFail {
    libc::sendto(socket, buf, len, flags, addr, addrlen)
}

pub unsafe fn recvfrom(socket: CSocket,
                       buf: MutBuf,
                       len: BufLen,
                       flags: libc::c_int,
                       addr: *mut SockAddr,
                       addrlen: *mut SockLen)
    -> CouldFail {
    libc::recvfrom(socket, buf, len, flags, addr, addrlen)
}

#[inline]
pub fn retry<F>(f: &mut F) -> libc::ssize_t
    where F: FnMut() -> libc::ssize_t
{
    loop {
        let ret = f();
        if ret != -1 || errno() as isize != libc::EINTR as isize {
            return ret;
        }
    }
}

fn errno() -> i32 {
    io::Error::last_os_error().raw_os_error().unwrap()
}

#[cfg(test)]
mod tests {
    use std::time::Duration;
    use duration_to_timespec;
    use timespec_to_duration;

    #[test]
    fn test_duration_to_timespec(){
        let d1 = Duration::new(1, 0);
        let d2 = Duration::from_millis(500);

        let t1 = duration_to_timespec(d1);
        let t2 = duration_to_timespec(d2);

        let r1 = timespec_to_duration(t1);
        let r2 = timespec_to_duration(t2);

        assert_eq!(d1, r1);
        assert_eq!(d2, r2);
    }
}
<commit_msg>New test to check for MacOS<commit_after>use libc;
use std::io;

pub mod public {
    use libc;
    use std::time::Duration;

    pub type CSocket = libc::c_int;
    pub type Buf = *const libc::c_void;
    pub type MutBuf = *mut libc::c_void;
    pub type BufLen = libc::size_t;
    pub type CouldFail = libc::ssize_t;
    pub type SockLen = libc::socklen_t;
    pub type MutSockLen = *mut libc::socklen_t;
    pub type SockAddr = libc::sockaddr;
    pub type SockAddrIn = libc::sockaddr_in;
    pub type SockAddrIn6 = libc::sockaddr_in6;
    pub type SockAddrStorage = libc::sockaddr_storage;
    pub type SockAddrFamily = libc::sa_family_t;
    pub type SockAddrFamily6 = libc::sa_family_t;
    pub type InAddr = libc::in_addr;
    pub type In6Addr = libc::in6_addr;

    #[cfg(not(any(target_os = "macos")))]
    pub type TvUsecType = libc::c_long;
    #[cfg(any(target_os = "macos"))]
    pub type TvUsecType = libc::__darwin_suseconds_t;

    pub const AF_INET: libc::c_int = libc::AF_INET;
    pub const AF_INET6: libc::c_int = libc::AF_INET6;
    pub const SOCK_RAW: libc::c_int = libc::SOCK_RAW;

    pub const SOL_SOCKET: libc::c_int = libc::SOL_SOCKET;
    pub const SO_RCVTIMEO: libc::c_int = libc::SO_RCVTIMEO;
    pub const SO_SNDTIMEO: libc::c_int = libc::SO_SNDTIMEO;

    pub const IPPROTO_IP: libc::c_int = libc::IPPROTO_IP;
    pub const IP_HDRINCL: libc::c_int = libc::IP_HDRINCL;
    pub const IP_TTL: libc::c_int = libc::IP_TTL;

    pub use libc::{IFF_UP, IFF_BROADCAST, IFF_LOOPBACK, IFF_POINTOPOINT, IFF_MULTICAST};

    pub const INVALID_SOCKET: CSocket = -1;

    pub unsafe fn close(sock: CSocket) {
        let _ = libc::close(sock);
    }

    pub unsafe fn socket(af: libc::c_int, sock: libc::c_int, proto: libc::c_int) -> CSocket {
        libc::socket(af, sock, proto)
    }

    pub unsafe fn getsockopt(socket: CSocket,
                            level: libc::c_int,
                            name: libc::c_int,
                            value: MutBuf,
                            option_len: MutSockLen)
        -> libc::c_int {
        libc::getsockopt(socket, level, name, value, option_len)
    }

    pub unsafe fn setsockopt(socket: CSocket,
                            level: libc::c_int,
                            name: libc::c_int,
                            value: Buf,
                            option_len: SockLen)
        -> libc::c_int {
        libc::setsockopt(socket, level, name, value, option_len)
    }

    /// Convert a platform specific `timeval` into a Duration
    pub fn timeval_to_duration(tv: libc::timeval) -> Duration {
        Duration::new(tv.tv_sec as u64, (tv.tv_usec as u32) * 1000)
    }

    /// Convert a Duration into a platform specific `timeval`
    pub fn duration_to_timeval(dur: Duration) -> libc::timeval {
        libc::timeval {
            tv_sec: dur.as_secs() as libc::time_t,
            tv_usec: dur.subsec_micros() as TvUsecType
        }
    }

    /// Convert a platform specific `timespec` into a Duration
    pub fn timespec_to_duration(ts: libc::timespec) -> Duration {
        Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32)
    }

    /// Convert a Duration into a platform specific `timespec`
    pub fn duration_to_timespec(dur: Duration) -> libc::timespec {
        libc::timespec {
            tv_sec: dur.as_secs() as libc::time_t,
            tv_nsec: dur.subsec_nanos() as TvUsecType
        }
    }

}

use self::public::*;

#[inline(always)]
pub fn ipv4_addr(addr: InAddr) -> u32 {
    (addr.s_addr as u32).to_be()
}

#[inline(always)]
pub fn mk_inaddr(addr: u32) -> InAddr {
    InAddr { s_addr: addr }
}

pub unsafe fn sendto(socket: CSocket,
                     buf: Buf,
                     len: BufLen,
                     flags: libc::c_int,
                     addr: *const SockAddr,
                     addrlen: SockLen)
    -> CouldFail {
    libc::sendto(socket, buf, len, flags, addr, addrlen)
}

pub unsafe fn recvfrom(socket: CSocket,
                       buf: MutBuf,
                       len: BufLen,
                       flags: libc::c_int,
                       addr: *mut SockAddr,
                       addrlen: *mut SockLen)
    -> CouldFail {
    libc::recvfrom(socket, buf, len, flags, addr, addrlen)
}

#[inline]
pub fn retry<F>(f: &mut F) -> libc::ssize_t
    where F: FnMut() -> libc::ssize_t
{
    loop {
        let ret = f();
        if ret != -1 || errno() as isize != libc::EINTR as isize {
            return ret;
        }
    }
}

fn errno() -> i32 {
    io::Error::last_os_error().raw_os_error().unwrap()
}

#[cfg(test)]
mod tests {
    use std::time::Duration;
    use duration_to_timespec;
    use timespec_to_duration;

    #[test]
    fn test_duration_to_timespec(){
        let d1 = Duration::new(1, 0);
        let d2 = Duration::from_millis(500);

        let t1 = duration_to_timespec(d1);
        let t2 = duration_to_timespec(d2);

        let r1 = timespec_to_duration(t1);
        let r2 = timespec_to_duration(t2);

        assert_eq!(d1, r1);
        assert_eq!(d2, r2);
    }
}
<|endoftext|>


<commit_before>#![doc(html_favicon_url = "https://www.ruma.io/favicon.ico")]
#![doc(html_logo_url = "https://www.ruma.io/images/logo.png")]
//! Types and traits for working with the [Matrix](https://matrix.org) protocol.
//!
//! This crate re-exports things from all of the other ruma crates so you don't
//! have to manually keep all the versions in sync.
//!
//! Which crates are re-exported can be configured through cargo features.
//!
//! > ⚠ Some details might be missing because rustdoc has trouble with re-exports so you may need
//! > to refer to other crates' documentations.
//!
//! > 🛈 For internal consistency, ruma uses American spelling for variable names. Actual values may
//! > differ, as the matrix specification has a mix of British and American English.
//!
//! # API features
//!
//! Depending on which parts of Matrix are relevant to you, activate the following features:
//!
//! * `appservice-api` -- Application Service API.
//! * `client-api` -- Client-Server API.
//! * `federation-api` -- Server-Server (Federation) API.
//! * `identity-service-api` -- Identity Service API.
//! * `push-gateway-api` -- Push Gateway API.
//!
//! These features have `client`- and `server`-optimized variants that are enabled respectively
//! with the `-c` and `-s` suffixes. For example:
//!   * `client-api-c` -- The Client-Server API optimized for the client side.
//!   * `client-api-s` -- The Client-Server API optimized for the server side.
//!
//! # Compatibility feature
//!
//! * `compat` increases compatibility with other parts of the Matrix ecosystem, at the expense of
//!   deviating from the specification.
//!
//! # Convenience features
//!
//! These features are only useful if you want to use a method that requires it:
//!
//! * `rand`
//! * `markdown`
//!
//! # Unstable features
//!
//! By using these features, you opt out of all semver guarantees Ruma otherwise provides:
//!
//! * `unstable-exhaustive-types` -- Most types in Ruma are marked as non-exhaustive to avoid
//!   breaking changes when new fields are added in the specification. This feature compiles all
//!   types as exhaustive.
//! * `unstable-mscXXXX`, where `XXXX` is the MSC number -- Upcoming Matrix features that may be
//!   subject to change or removal.
//! * `unstable-pre-spec` -- Undocumented Matrix features that may be subject to change or removal.
//! * `unstable-sanitize` -- Convenience methods for spec-compliant HTML sanitization that have not
//!   been thoroughly tested.
//!
//! # Common features
//!
//! These submodules are usually activated by the API features when needed:
//!
//! * `api`
//! * `events`
//! * `signatures`
//!
//! # `ruma-client` features
//!
//! The `client` feature activates [`ruma::client`][client], and `client-ext-client-api` activates
//! `ruma-client`s `client-api` feature. All other `client-*` features activate the same feature
//! without the `client-` prefix on `ruma-client`. See the crate's documentation for the effect of
//! these features.
//!
//! If you are viewing this on `docs.rs`, you can have a look at the feature dependencies by
//! clicking **Feature flags** in the toolbar at the top.

#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]

#[cfg(feature = "client")]
#[doc(inline)]
pub use ruma_client as client;
#[cfg(feature = "events")]
#[doc(inline)]
pub use ruma_common::events;
#[cfg(feature = "signatures")]
#[doc(inline)]
pub use ruma_signatures as signatures;
#[cfg(feature = "state-res")]
#[doc(inline)]
pub use ruma_state_res as state_res;

/// (De)serializable types for various [Matrix APIs][apis] requests and responses and abstractions
/// for them.
///
/// [apis]: https://spec.matrix.org/v1.2/#matrix-apis
#[cfg(feature = "api")]
pub mod api {
    pub use ruma_common::api::*;

    #[cfg(feature = "ruma-appservice-api")]
    #[cfg_attr(
        docsrs,
        doc(cfg(any(
            feature = "appservice-api",
            feature = "appservice-api-c",
            feature = "appservice-api-s"
        )))
    )]
    #[doc(inline)]
    pub use ruma_appservice_api as appservice;
    #[cfg(feature = "ruma-client-api")]
    #[cfg_attr(
        docsrs,
        doc(cfg(any(
            feature = "client-api",
            feature = "client-api-c",
            feature = "client-api-s"
        )))
    )]
    #[doc(inline)]
    pub use ruma_client_api as client;
    #[cfg(feature = "ruma-federation-api")]
    #[cfg_attr(
        docsrs,
        doc(cfg(any(
            feature = "federation-api",
            feature = "federation-api-c",
            feature = "federation-api-s"
        )))
    )]
    #[doc(inline)]
    pub use ruma_federation_api as federation;
    #[cfg(feature = "ruma-identity-service-api")]
    #[cfg_attr(
        docsrs,
        doc(cfg(any(
            feature = "identity-service-api",
            feature = "identity-service-api-c",
            feature = "identity-service-api-s"
        )))
    )]
    #[doc(inline)]
    pub use ruma_identity_service_api as identity_service;
    #[cfg(feature = "ruma-push-gateway-api")]
    #[cfg_attr(
        docsrs,
        doc(cfg(any(
            feature = "push-gateway-api",
            feature = "push-gateway-api-c",
            feature = "push-gateway-api-s"
        )))
    )]
    #[doc(inline)]
    pub use ruma_push_gateway_api as push_gateway;
}

#[doc(no_inline)]
pub use assign::assign;
#[doc(no_inline)]
pub use js_int::{int, uint, Int, UInt};
#[cfg(feature = "client-ext-client-api")]
pub use ruma_client::Client;
pub use ruma_common::{
    authentication, device_id, device_key_id, directory, encryption, event_id, exports, matrix_uri,
    mxc_uri, power_levels, presence, push, room, room_alias_id, room_id, room_version_id, serde,
    server_name, server_signing_key_id, thirdparty, to_device, user_id, ClientSecret, DeviceId,
    DeviceKeyAlgorithm, DeviceKeyId, DeviceSignatures, DeviceSigningKeyId, EntitySignatures,
    EventEncryptionAlgorithm, EventId, IdParseError, KeyId, KeyName, MatrixToUri, MatrixUri,
    MilliSecondsSinceUnixEpoch, MxcUri, OwnedClientSecret, OwnedDeviceId, OwnedDeviceKeyId,
    OwnedDeviceSigningKeyId, OwnedEventId, OwnedKeyId, OwnedKeyName, OwnedMxcUri, OwnedRoomAliasId,
    OwnedRoomId, OwnedRoomOrAliasId, OwnedServerName, OwnedServerSigningKeyId, OwnedSessionId,
    OwnedSigningKeyId, OwnedTransactionId, OwnedUserId, PrivOwnedStr, RoomAliasId, RoomId,
    RoomOrAliasId, RoomVersionId, SecondsSinceUnixEpoch, ServerName, ServerSignatures,
    ServerSigningKeyId, SessionId, Signatures, SigningKeyAlgorithm, TransactionId, UserId,
};
#[cfg(feature = "canonical-json")]
pub use ruma_common::{
    canonical_json, CanonicalJsonError, CanonicalJsonObject, CanonicalJsonValue,
};
<commit_msg>ruma: Clean up cfg's<commit_after>#![doc(html_favicon_url = "https://www.ruma.io/favicon.ico")]
#![doc(html_logo_url = "https://www.ruma.io/images/logo.png")]
//! Types and traits for working with the [Matrix](https://matrix.org) protocol.
//!
//! This crate re-exports things from all of the other ruma crates so you don't
//! have to manually keep all the versions in sync.
//!
//! Which crates are re-exported can be configured through cargo features.
//!
//! > ⚠ Some details might be missing because rustdoc has trouble with re-exports so you may need
//! > to refer to other crates' documentations.
//!
//! > 🛈 For internal consistency, ruma uses American spelling for variable names. Actual values may
//! > differ, as the matrix specification has a mix of British and American English.
//!
//! # API features
//!
//! Depending on which parts of Matrix are relevant to you, activate the following features:
//!
//! * `appservice-api` -- Application Service API.
//! * `client-api` -- Client-Server API.
//! * `federation-api` -- Server-Server (Federation) API.
//! * `identity-service-api` -- Identity Service API.
//! * `push-gateway-api` -- Push Gateway API.
//!
//! These features have `client`- and `server`-optimized variants that are enabled respectively
//! with the `-c` and `-s` suffixes. For example:
//!   * `client-api-c` -- The Client-Server API optimized for the client side.
//!   * `client-api-s` -- The Client-Server API optimized for the server side.
//!
//! # Compatibility feature
//!
//! * `compat` increases compatibility with other parts of the Matrix ecosystem, at the expense of
//!   deviating from the specification.
//!
//! # Convenience features
//!
//! These features are only useful if you want to use a method that requires it:
//!
//! * `rand`
//! * `markdown`
//!
//! # Unstable features
//!
//! By using these features, you opt out of all semver guarantees Ruma otherwise provides:
//!
//! * `unstable-exhaustive-types` -- Most types in Ruma are marked as non-exhaustive to avoid
//!   breaking changes when new fields are added in the specification. This feature compiles all
//!   types as exhaustive.
//! * `unstable-mscXXXX`, where `XXXX` is the MSC number -- Upcoming Matrix features that may be
//!   subject to change or removal.
//! * `unstable-pre-spec` -- Undocumented Matrix features that may be subject to change or removal.
//! * `unstable-sanitize` -- Convenience methods for spec-compliant HTML sanitization that have not
//!   been thoroughly tested.
//!
//! # Common features
//!
//! These submodules are usually activated by the API features when needed:
//!
//! * `api`
//! * `events`
//! * `signatures`
//!
//! # `ruma-client` features
//!
//! The `client` feature activates [`ruma::client`][client], and `client-ext-client-api` activates
//! `ruma-client`s `client-api` feature. All other `client-*` features activate the same feature
//! without the `client-` prefix on `ruma-client`. See the crate's documentation for the effect of
//! these features.
//!
//! If you are viewing this on `docs.rs`, you can have a look at the feature dependencies by
//! clicking **Feature flags** in the toolbar at the top.

#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]

#[cfg(feature = "client")]
#[doc(inline)]
pub use ruma_client as client;
#[cfg(feature = "events")]
#[doc(inline)]
pub use ruma_common::events;
#[cfg(feature = "signatures")]
#[doc(inline)]
pub use ruma_signatures as signatures;
#[cfg(feature = "state-res")]
#[doc(inline)]
pub use ruma_state_res as state_res;

/// (De)serializable types for various [Matrix APIs][apis] requests and responses and abstractions
/// for them.
///
/// [apis]: https://spec.matrix.org/v1.2/#matrix-apis
#[cfg(feature = "api")]
pub mod api {
    pub use ruma_common::api::*;

    #[cfg(any(feature = "appservice-api-c", feature = "appservice-api-s"))]
    #[doc(inline)]
    pub use ruma_appservice_api as appservice;
    #[cfg(any(feature = "client-api-c", feature = "client-api-s"))]
    #[doc(inline)]
    pub use ruma_client_api as client;
    #[cfg(any(feature = "federation-api-c", feature = "federation-api-s"))]
    #[doc(inline)]
    pub use ruma_federation_api as federation;
    #[cfg(any(feature = "identity-service-api-c", feature = "identity-service-api-s"))]
    #[doc(inline)]
    pub use ruma_identity_service_api as identity_service;
    #[cfg(any(feature = "push-gateway-api-c", feature = "push-gateway-api-s"))]
    #[doc(inline)]
    pub use ruma_push_gateway_api as push_gateway;
}

#[doc(no_inline)]
pub use assign::assign;
#[doc(no_inline)]
pub use js_int::{int, uint, Int, UInt};
#[cfg(feature = "client-ext-client-api")]
pub use ruma_client::Client;
pub use ruma_common::{
    authentication, device_id, device_key_id, directory, encryption, event_id, exports, matrix_uri,
    mxc_uri, power_levels, presence, push, room, room_alias_id, room_id, room_version_id, serde,
    server_name, server_signing_key_id, thirdparty, to_device, user_id, ClientSecret, DeviceId,
    DeviceKeyAlgorithm, DeviceKeyId, DeviceSignatures, DeviceSigningKeyId, EntitySignatures,
    EventEncryptionAlgorithm, EventId, IdParseError, KeyId, KeyName, MatrixToUri, MatrixUri,
    MilliSecondsSinceUnixEpoch, MxcUri, OwnedClientSecret, OwnedDeviceId, OwnedDeviceKeyId,
    OwnedDeviceSigningKeyId, OwnedEventId, OwnedKeyId, OwnedKeyName, OwnedMxcUri, OwnedRoomAliasId,
    OwnedRoomId, OwnedRoomOrAliasId, OwnedServerName, OwnedServerSigningKeyId, OwnedSessionId,
    OwnedSigningKeyId, OwnedTransactionId, OwnedUserId, PrivOwnedStr, RoomAliasId, RoomId,
    RoomOrAliasId, RoomVersionId, SecondsSinceUnixEpoch, ServerName, ServerSignatures,
    ServerSigningKeyId, SessionId, Signatures, SigningKeyAlgorithm, TransactionId, UserId,
};
#[cfg(feature = "canonical-json")]
pub use ruma_common::{
    canonical_json, CanonicalJsonError, CanonicalJsonObject, CanonicalJsonValue,
};
<|endoftext|>