<commit_before>use std::collections::HashMap;
use common::*;
use error;
use error::Error::InvalidResponse;
use auth;
use links;
use rustc_serialize::json;

///Represents a Twitter user.
///
///Field-level documentation is mostly ripped wholesale from [Twitter's user
///documentation][api-user].
///
///[api-user]: https://dev.twitter.com/overview/api/users
#[derive(Debug)]
pub struct TwitterUser {
    ///Indicates this user has an account with "contributor mode" enabled, allowing
    ///for Tweets issued by the user to be co-authored by another account. Rarely `true`.
    pub contributors_enabled: bool,
    //TODO: parse as date?
    ///The UTC datetime that this user account was created on Twitter.
    pub created_at: String,
    ///When true, indicates that this user has not altered the theme or background of
    ///their user profile.
    pub default_profile: bool,
    ///When true, indicates that the user has not uploaded their own avatar and a default
    ///egg avatar is used instead.
    pub default_profile_image: bool,
    ///The user-defined string describing their account.
    pub description: Option<String>,
    //Entities that have been parsed out of the `url` or `description` fields given by
    //the user.
    //TODO: pub entities: Entities,
    ///The number of tweets this user has favorited or liked in the account's lifetime.
    ///The term "favourites" and its British spelling are used for historical reasons.
    pub favourites_count: i32,
    ///When true, indicates that the authenticating user has issued a follow request to
    ///this protected account.
    pub follow_request_sent: Option<bool>,
    ///Indicates whether the authenticating user is following this account. Deprecated
    ///(and thus hidden) due to increasing error conditions where this returns None.
    following: Option<bool>,
    ///The number of followers this account has.
    ///
    ///In certain server-stress conditions, this may temporarily mistakenly return 0.
    pub followers_count: i32,
    ///The number of users this account follows, aka its "followings".
    ///
    ///In certain server-stress conditions, this may temporarily mistakenly return 0.
    pub friends_count: i32,
    ///Indicates whether this user as enabled their tweets to be geotagged.
    ///
    ///If this is set for the current user, then they can attach geographic data when
    ///posting a new Tweet.
    pub geo_enabled: bool,
    ///Unique identifier for this user.
    pub id: i64,
    ///User `id` represented as a string, for compatibility with API clients who cannot
    ///properly handle 64-bit integers.
    pub id_str: String,
    ///Indicates whether the user participates in Twitter's translator community.
    pub is_translator: bool,
    ///Language code for the user's self-declared interface language.
    ///
    ///Codes are formatted as a language tag from [BCP 47][]. Only indicates the user's
    ///interface language, not necessarily the content of their Tweets.
    ///
    ///[BCP 47]: https://tools.ietf.org/html/bcp47
    pub lang: String,
    ///The number of public lists the user is a member of.
    pub listed_count: i32,
    ///The user-entered location field from their profile. Not necessarily parseable
    ///or even a location.
    pub location: Option<String>,
    ///The user-entered display name.
    pub name: String,
    ///Indicates whether the authenticated user has chosen to received this user's tweets
    ///via SMS. Deprecated (and thus hidden) due to bugs where this incorrectly returns
    ///false.
    notifications: Option<bool>,
    ///The hex color chosen by the user for their profile background.
    pub profile_background_color: String,
    ///A URL pointing to the background image chosen by the user for their profile. Uses
    ///HTTP as the protocol.
    pub profile_background_image_url: String,
    ///A URL pointing to the background image chosen by the user for their profile. Uses
    ///HTTPS as the protocol.
    pub profile_background_image_url_https: String,
    ///Indicates whether the user's `profile_background_image_url` should be tiled when
    ///displayed.
    pub profile_background_tile: bool,
    ///A URL pointing to the banner image chosen by the user. Uses HTTPS as the protocol.
    ///
    ///This is a base URL that a size specifier can be appended onto to get variously
    ///sized images, with size specifiers according to [Profile Images and Banners][profile-img].
    ///
    ///[profile-img]: https://dev.twitter.com/overview/general/user-profile-images-and-banners
    pub profile_banner_url: String,
    ///A URL pointing to the user's avatar image. Uses HTTP as the protocol. Size
    ///specifiers can be used according to [Profile Images and Banners][profile-img].
    ///
    ///[profile-img]: https://dev.twitter.com/overview/general/user-profile-images-and-banners
    pub profile_image_url: String,
    ///A URL pointing to the user's avatar image. Uses HTTPS as the protocol. Size
    ///specifiers can be used according to [Profile Images and Banners][profile-img].
    ///
    ///[profile-img]: https://dev.twitter.com/overview/general/user-profile-images-and-banners
    pub profile_image_url_https: String,
    ///The hex color chosen by the user to display links in the Twitter UI.
    pub profile_link_color: String,
    ///The hex color chosen by the user to display sidebar borders in the Twitter UI.
    pub profile_sidebar_border_color: String,
    ///The hex color chosen by the user to display sidebar backgrounds in the Twitter UI.
    pub profile_sidebar_fill_color: String,
    ///The hex color chosen by the user to display text in the Twitter UI.
    pub profile_text_color: String,
    ///Indicates whether the user wants their uploaded background image to be used.
    pub profile_use_background_image: bool,
    ///Indicates whether the user is a [protected][] account.
    ///
    ///[protected]: https://support.twitter.com/articles/14016
    pub protected: bool,
    ///The screen name or handle identifying this user.
    ///
    ///Screen names are unique per-user but can be changed. Use `id`/`id_str` for an
    ///immutable identifier for an account.
    ///
    ///Typically a maximum of 15 characters long, but older accounts may exist with
    ///longer screen names.
    pub screen_name: String,
    ///Indicates that the user would like to see media inline. "Somewhat disused."
    pub show_all_inline_media: Option<bool>,
    //If possible, the most recent tweet or reweet from this user.
    //
    //"Perspectival" items within this tweet that depend on the authenticating user
    //[may not be completely reliable][stale-embed] in this embed.
    //
    //[stale-embed]: https://dev.twitter.com/docs/faq/basics/why-are-embedded-objects-stale-or-inaccurate
    //TODO: pub status: Option<Tweet>,
    ///The number of tweets (including retweets) posted by this user.
    pub statuses_count: i32,
    ///The full name of the time zone the user has set their UI preference to.
    pub time_zone: Option<String>,
    ///The website link given by this user in their profile.
    pub url: Option<String>,
    ///The UTC offset of `time_zone` in minutes.
    pub utc_offset: Option<i32>,
    ///Indicates whether this user is a verified account.
    pub verified: bool,
    ///When present, lists the countries this user has been withheld from.
    pub withheld_in_countries: Option<Vec<String>>,
    ///When present, indicates whether the content being withheld is a "status" or "user".
    pub withheld_scope: Option<String>,
}

impl FromJson for TwitterUser {
    fn from_json(input: &json::Json) -> Result<Self, error::Error> {
        if !input.is_object() {
            return Err(InvalidResponse);
        }

        Ok(TwitterUser {
            contributors_enabled: field_bool(input, "contributors_enabled").unwrap_or(false),
            created_at: try!(field_string(input, "created_at")),
            default_profile: try!(field_bool(input, "default_profile")),
            default_profile_image: try!(field_bool(input, "default_profile_image")),
            description: field_string(input, "description").ok(),
            //TODO: entities: ???,
            favourites_count: try!(field_i32(input, "favourites_count")),
            follow_request_sent: field_bool(input, "follow_request_sent").ok(),
            following: field_bool(input, "following").ok(),
            followers_count: try!(field_i32(input, "followers_count")),
            friends_count: try!(field_i32(input, "friends_count")),
            geo_enabled: try!(field_bool(input, "geo_enabled")),
            id: try!(field_i64(input, "id")),
            id_str: try!(field_string(input, "id_str")),
            is_translator: try!(field_bool(input, "is_translator")),
            lang: try!(field_string(input, "lang")),
            listed_count: try!(field_i32(input, "listed_count")),
            location: field_string(input, "location").ok(),
            name: try!(field_string(input, "name")),
            notifications: field_bool(input, "notifications").ok(),
            profile_background_color: try!(field_string(input, "profile_background_color")),
            profile_background_image_url: try!(field_string(input, "profile_background_image_url")),
            profile_background_image_url_https: try!(field_string(input, "profile_background_image_url_https")),
            profile_background_tile: try!(field_bool(input, "profile_background_tile")),
            profile_banner_url: try!(field_string(input, "profile_banner_url")),
            profile_image_url: try!(field_string(input, "profile_image_url")),
            profile_image_url_https: try!(field_string(input, "profile_image_url_https")),
            profile_link_color: try!(field_string(input, "profile_link_color")),
            profile_sidebar_border_color: try!(field_string(input, "profile_sidebar_border_color")),
            profile_sidebar_fill_color: try!(field_string(input, "profile_sidebar_fill_color")),
            profile_text_color: try!(field_string(input, "profile_text_color")),
            profile_use_background_image: try!(field_bool(input, "profile_use_background_image")),
            protected: try!(field_bool(input, "protected")),
            screen_name: try!(field_string(input, "screen_name")),
            show_all_inline_media: field_bool(input, "show_all_inline_media").ok(),
            //TODO: status: ???,
            statuses_count: try!(field_i32(input, "statuses_count")),
            time_zone: field_string(input, "time_zone").ok(),
            url: field_string(input, "url").ok(),
            utc_offset: field_i32(input, "utc_offset").ok(),
            verified: try!(field_bool(input, "verified")),
            withheld_in_countries: input.find("withheld_in_countries").and_then(|f| f.as_array())
                                        .and_then(|arr| arr.iter().map(|x| x.as_string().map(|x| x.to_string()))
                                                           .collect::<Option<Vec<String>>>()),
            withheld_scope: field_string(input, "withheld_scope").ok(),
        })
    }
}

impl TwitterUser {
    pub fn lookup_ids(ids: &[i64], con_token: &auth::Token, access_token: &auth::Token)
        -> Result<Response<Vec<TwitterUser>>, error::Error>
    {
        let mut params = HashMap::new();
        let id_param = ids.iter().map(|x| x.to_string()).collect::<Vec<String>>().join(",");
        add_param(&mut params, "user_id", id_param);

        let mut resp = try!(auth::post(links::users::LOOKUP, con_token, access_token, Some(&params)));

        parse_response(&mut resp)
    }
}
<commit_msg>lookup users by username<commit_after>use std::borrow::Borrow;
use std::collections::HashMap;
use common::*;
use error;
use error::Error::InvalidResponse;
use auth;
use links;
use rustc_serialize::json;

///Represents a Twitter user.
///
///Field-level documentation is mostly ripped wholesale from [Twitter's user
///documentation][api-user].
///
///[api-user]: https://dev.twitter.com/overview/api/users
#[derive(Debug)]
pub struct TwitterUser {
    ///Indicates this user has an account with "contributor mode" enabled, allowing
    ///for Tweets issued by the user to be co-authored by another account. Rarely `true`.
    pub contributors_enabled: bool,
    //TODO: parse as date?
    ///The UTC datetime that this user account was created on Twitter.
    pub created_at: String,
    ///When true, indicates that this user has not altered the theme or background of
    ///their user profile.
    pub default_profile: bool,
    ///When true, indicates that the user has not uploaded their own avatar and a default
    ///egg avatar is used instead.
    pub default_profile_image: bool,
    ///The user-defined string describing their account.
    pub description: Option<String>,
    //Entities that have been parsed out of the `url` or `description` fields given by
    //the user.
    //TODO: pub entities: Entities,
    ///The number of tweets this user has favorited or liked in the account's lifetime.
    ///The term "favourites" and its British spelling are used for historical reasons.
    pub favourites_count: i32,
    ///When true, indicates that the authenticating user has issued a follow request to
    ///this protected account.
    pub follow_request_sent: Option<bool>,
    ///Indicates whether the authenticating user is following this account. Deprecated
    ///(and thus hidden) due to increasing error conditions where this returns None.
    following: Option<bool>,
    ///The number of followers this account has.
    ///
    ///In certain server-stress conditions, this may temporarily mistakenly return 0.
    pub followers_count: i32,
    ///The number of users this account follows, aka its "followings".
    ///
    ///In certain server-stress conditions, this may temporarily mistakenly return 0.
    pub friends_count: i32,
    ///Indicates whether this user as enabled their tweets to be geotagged.
    ///
    ///If this is set for the current user, then they can attach geographic data when
    ///posting a new Tweet.
    pub geo_enabled: bool,
    ///Unique identifier for this user.
    pub id: i64,
    ///User `id` represented as a string, for compatibility with API clients who cannot
    ///properly handle 64-bit integers.
    pub id_str: String,
    ///Indicates whether the user participates in Twitter's translator community.
    pub is_translator: bool,
    ///Language code for the user's self-declared interface language.
    ///
    ///Codes are formatted as a language tag from [BCP 47][]. Only indicates the user's
    ///interface language, not necessarily the content of their Tweets.
    ///
    ///[BCP 47]: https://tools.ietf.org/html/bcp47
    pub lang: String,
    ///The number of public lists the user is a member of.
    pub listed_count: i32,
    ///The user-entered location field from their profile. Not necessarily parseable
    ///or even a location.
    pub location: Option<String>,
    ///The user-entered display name.
    pub name: String,
    ///Indicates whether the authenticated user has chosen to received this user's tweets
    ///via SMS. Deprecated (and thus hidden) due to bugs where this incorrectly returns
    ///false.
    notifications: Option<bool>,
    ///The hex color chosen by the user for their profile background.
    pub profile_background_color: String,
    ///A URL pointing to the background image chosen by the user for their profile. Uses
    ///HTTP as the protocol.
    pub profile_background_image_url: String,
    ///A URL pointing to the background image chosen by the user for their profile. Uses
    ///HTTPS as the protocol.
    pub profile_background_image_url_https: String,
    ///Indicates whether the user's `profile_background_image_url` should be tiled when
    ///displayed.
    pub profile_background_tile: bool,
    ///A URL pointing to the banner image chosen by the user. Uses HTTPS as the protocol.
    ///
    ///This is a base URL that a size specifier can be appended onto to get variously
    ///sized images, with size specifiers according to [Profile Images and Banners][profile-img].
    ///
    ///[profile-img]: https://dev.twitter.com/overview/general/user-profile-images-and-banners
    pub profile_banner_url: String,
    ///A URL pointing to the user's avatar image. Uses HTTP as the protocol. Size
    ///specifiers can be used according to [Profile Images and Banners][profile-img].
    ///
    ///[profile-img]: https://dev.twitter.com/overview/general/user-profile-images-and-banners
    pub profile_image_url: String,
    ///A URL pointing to the user's avatar image. Uses HTTPS as the protocol. Size
    ///specifiers can be used according to [Profile Images and Banners][profile-img].
    ///
    ///[profile-img]: https://dev.twitter.com/overview/general/user-profile-images-and-banners
    pub profile_image_url_https: String,
    ///The hex color chosen by the user to display links in the Twitter UI.
    pub profile_link_color: String,
    ///The hex color chosen by the user to display sidebar borders in the Twitter UI.
    pub profile_sidebar_border_color: String,
    ///The hex color chosen by the user to display sidebar backgrounds in the Twitter UI.
    pub profile_sidebar_fill_color: String,
    ///The hex color chosen by the user to display text in the Twitter UI.
    pub profile_text_color: String,
    ///Indicates whether the user wants their uploaded background image to be used.
    pub profile_use_background_image: bool,
    ///Indicates whether the user is a [protected][] account.
    ///
    ///[protected]: https://support.twitter.com/articles/14016
    pub protected: bool,
    ///The screen name or handle identifying this user.
    ///
    ///Screen names are unique per-user but can be changed. Use `id`/`id_str` for an
    ///immutable identifier for an account.
    ///
    ///Typically a maximum of 15 characters long, but older accounts may exist with
    ///longer screen names.
    pub screen_name: String,
    ///Indicates that the user would like to see media inline. "Somewhat disused."
    pub show_all_inline_media: Option<bool>,
    //If possible, the most recent tweet or reweet from this user.
    //
    //"Perspectival" items within this tweet that depend on the authenticating user
    //[may not be completely reliable][stale-embed] in this embed.
    //
    //[stale-embed]: https://dev.twitter.com/docs/faq/basics/why-are-embedded-objects-stale-or-inaccurate
    //TODO: pub status: Option<Tweet>,
    ///The number of tweets (including retweets) posted by this user.
    pub statuses_count: i32,
    ///The full name of the time zone the user has set their UI preference to.
    pub time_zone: Option<String>,
    ///The website link given by this user in their profile.
    pub url: Option<String>,
    ///The UTC offset of `time_zone` in minutes.
    pub utc_offset: Option<i32>,
    ///Indicates whether this user is a verified account.
    pub verified: bool,
    ///When present, lists the countries this user has been withheld from.
    pub withheld_in_countries: Option<Vec<String>>,
    ///When present, indicates whether the content being withheld is a "status" or "user".
    pub withheld_scope: Option<String>,
}

impl FromJson for TwitterUser {
    fn from_json(input: &json::Json) -> Result<Self, error::Error> {
        if !input.is_object() {
            return Err(InvalidResponse);
        }

        Ok(TwitterUser {
            contributors_enabled: field_bool(input, "contributors_enabled").unwrap_or(false),
            created_at: try!(field_string(input, "created_at")),
            default_profile: try!(field_bool(input, "default_profile")),
            default_profile_image: try!(field_bool(input, "default_profile_image")),
            description: field_string(input, "description").ok(),
            //TODO: entities: ???,
            favourites_count: try!(field_i32(input, "favourites_count")),
            follow_request_sent: field_bool(input, "follow_request_sent").ok(),
            following: field_bool(input, "following").ok(),
            followers_count: try!(field_i32(input, "followers_count")),
            friends_count: try!(field_i32(input, "friends_count")),
            geo_enabled: try!(field_bool(input, "geo_enabled")),
            id: try!(field_i64(input, "id")),
            id_str: try!(field_string(input, "id_str")),
            is_translator: try!(field_bool(input, "is_translator")),
            lang: try!(field_string(input, "lang")),
            listed_count: try!(field_i32(input, "listed_count")),
            location: field_string(input, "location").ok(),
            name: try!(field_string(input, "name")),
            notifications: field_bool(input, "notifications").ok(),
            profile_background_color: try!(field_string(input, "profile_background_color")),
            profile_background_image_url: try!(field_string(input, "profile_background_image_url")),
            profile_background_image_url_https: try!(field_string(input, "profile_background_image_url_https")),
            profile_background_tile: try!(field_bool(input, "profile_background_tile")),
            profile_banner_url: try!(field_string(input, "profile_banner_url")),
            profile_image_url: try!(field_string(input, "profile_image_url")),
            profile_image_url_https: try!(field_string(input, "profile_image_url_https")),
            profile_link_color: try!(field_string(input, "profile_link_color")),
            profile_sidebar_border_color: try!(field_string(input, "profile_sidebar_border_color")),
            profile_sidebar_fill_color: try!(field_string(input, "profile_sidebar_fill_color")),
            profile_text_color: try!(field_string(input, "profile_text_color")),
            profile_use_background_image: try!(field_bool(input, "profile_use_background_image")),
            protected: try!(field_bool(input, "protected")),
            screen_name: try!(field_string(input, "screen_name")),
            show_all_inline_media: field_bool(input, "show_all_inline_media").ok(),
            //TODO: status: ???,
            statuses_count: try!(field_i32(input, "statuses_count")),
            time_zone: field_string(input, "time_zone").ok(),
            url: field_string(input, "url").ok(),
            utc_offset: field_i32(input, "utc_offset").ok(),
            verified: try!(field_bool(input, "verified")),
            withheld_in_countries: input.find("withheld_in_countries").and_then(|f| f.as_array())
                                        .and_then(|arr| arr.iter().map(|x| x.as_string().map(|x| x.to_string()))
                                                           .collect::<Option<Vec<String>>>()),
            withheld_scope: field_string(input, "withheld_scope").ok(),
        })
    }
}

impl TwitterUser {
    pub fn lookup_ids(ids: &[i64], con_token: &auth::Token, access_token: &auth::Token)
        -> Result<Response<Vec<TwitterUser>>, error::Error>
    {
        let mut params = HashMap::new();
        let id_param = ids.iter().map(|x| x.to_string()).collect::<Vec<String>>().join(",");
        add_param(&mut params, "user_id", id_param);

        let mut resp = try!(auth::post(links::users::LOOKUP, con_token, access_token, Some(&params)));

        parse_response(&mut resp)
    }

    pub fn lookup_names<S: Borrow<str>>(names: &[S], con_token: &auth::Token, access_token: &auth::Token)
        -> Result<Response<Vec<TwitterUser>>, error::Error>
    {
        let mut params = HashMap::new();
        let id_param = names.join(",");
        add_param(&mut params, "screen_name", id_param);

        let mut resp = try!(auth::post(links::users::LOOKUP, con_token, access_token, Some(&params)));

        parse_response(&mut resp)
    }
}
<|endoftext|>


<commit_before>use yew::prelude::*;

use crate::{
    schema::{Field, Multiplicity, ValidationError, ValidatorContext, SCHEMA},
    types::*,
};

impl Model {
    pub fn view_actions(&self) -> Html {
        let actions = vec![
            Action {
                image: None,
                text: "store".to_string(),
                msg: Msg::Store,
            },
            Action {
                image: None,
                text: "load".to_string(),
                msg: Msg::Load,
            },
            Action {
                image: None,
                text: "Normal mode".to_string(),
                msg: Msg::SetMode(Mode::Normal),
            },
            Action {
                image: None,
                text: "Edit mode".to_string(),
                msg: Msg::SetMode(Mode::Edit),
            },
            Action {
                image: Some("gg-arrow-left".to_string()),
                text: "prev".to_string(),
                msg: Msg::Prev,
            },
            Action {
                image: Some("gg-arrow-right".to_string()),
                text: "next".to_string(),
                msg: Msg::Next,
            },
            Action {
                image: Some("gg-corner-right-up".to_string()),
                text: "parent".to_string(),
                msg: Msg::Parent,
            },
            Action {
                image: Some("gg-corner-double-up-right".to_string()),
                text: "+item".to_string(),
                msg: Msg::AddItem,
            },
            Action {
                image: Some("gg-close".to_string()),
                text: "delete".to_string(),
                msg: Msg::DeleteItem,
            },
        ];
        let actions = actions
            .iter()
            // .filter(|a| self.is_valid_action(a))
            .map(|a| self.view_action(a));

        html! {

                { for actions }

        }
    }

    pub fn current_field(&self) -> Option<Field> {
        self.field(&self.cursor)
    }

    pub fn field(&self, path: &Path) -> Option<Field> {
        path.split_last().and_then(|(selector, parent_path)| {
            let parent = self.file.lookup(&parent_path).unwrap();
            SCHEMA
                .get_kind(&parent.kind)
                .unwrap()
                .get_field(&selector.field)
        })
    }

    fn view_action(&self, action: &Action) -> Html {
        let msg = action.msg.clone();
        let callback = self.link.callback(move |_: MouseEvent| msg.clone());
        let img = match &action.image {
            Some(image) => html! {

            },
            None => html! {},
        };
        html! {
            <button
              class="action hover:bg-blue-200 hover:text-blue-800 group flex items-center rounded-md bg-blue-100 text-blue-600 text-sm font-medium px-4 py-2"
              onclick=callback>
                { img }
                { &action.text }
            </button>
        }
    }

    pub fn view_file(&self, file: &File) -> Html {
        let node = self.view_node(Some(file.root.clone()), &Path::new());
        html! {

{ node }

        }
    }

    pub fn view_file_json(&self, file: &File) -> Html {
        // let serialized = serde_json::to_string_pretty(file).expect("could not serialize to
        // JSON");
        let serialized = format!("root: {:?}\nfile: {:#?}", file.root, file);
        html! {

{ serialized }

        }
    }

    pub fn traverse_fields(node: &Node) -> Vec<Field> {
        let kind = &node.kind;
        match SCHEMA.get_kind(kind) {
            Some(kind) => kind.get_fields(),
            None => vec![],
        }
    }

    pub fn flatten_paths(&self, path: &[Selector]) -> Vec<Path> {
        // log::info!("flatten: {:?}", path);
        match &self.file.lookup(path) {
            Some(node) => {
                let mut paths = vec![];
                for field in Model::traverse_fields(&node) {
                    let mut children = node.children.get(field.name).cloned().unwrap_or_default();
                    match field.multiplicity {
                        Multiplicity::Single => {
                            if children.is_empty() {
                                children.push("".to_string());
                            }
                        }
                        Multiplicity::Repeated => {}
                    };
                    for (n, _child) in children.iter().enumerate() {
                        let new_path = append(
                            path,
                            Selector {
                                field: field.name.to_string(),
                                index: n,
                            },
                        );
                        paths.push(new_path.clone());
                        // log::info!("child: {:?}[{:?}]->{:?}", path, field.name, child);
                        paths.extend(self.flatten_paths(&new_path));
                    }
                    match field.multiplicity {
                        // If repeated field, stay on the parent.
                        Multiplicity::Repeated => {
                            let new_base = append(
                                path,
                                Selector {
                                    field: field.name.to_string(),
                                    index: children.len(),
                                },
                            );
                            paths.push(new_base.clone());
                        }
                        // If single field, skip directly to the first (and only) child.
                        Multiplicity::Single => {}
                    }
                }
                paths
            }
            None => vec![],
        }
    }

    fn view_node(&self, hash: Option<Hash>, path: &[Selector]) -> Html {
        self.view_node_with_placeholder(hash, path, "◆")
    }

    fn view_node_with_placeholder(
        &self,
        hash: Option<Hash>,
        path: &[Selector],
        placeholder: &str,
    ) -> Html {
        let selected = path == &self.cursor;
        let mut classes = vec!["node".to_string(), "align-top".to_string()];
        if selected {
            classes.push("selected".to_string());
        }
        if path == &self.hover {
            // classes.push("hover".to_string());
        }

        let path_clone = path.to_vec();
        let onclick = self.link.callback(move |e: MouseEvent| {
            e.stop_propagation();
            Msg::Select(path_clone.clone())
        });

        let path_clone = path.to_vec();
        let onmouseover = self.link.callback(move |e: MouseEvent| {
            e.stop_propagation();
            Msg::Hover(path_clone.clone())
        });

        let path_clone = path.to_vec();
        let _oninput = self.link.callback(move |e: InputData| {
            crate::types::Msg::SetNodeCommand(path_clone.clone(), e.value.clone())
        });

        let (value, errors) = match hash {
            Some(hash) => match self.file.lookup(path) {
                Some(node) => {
                    let context = ValidatorContext {
                        model: self,
                        path,
                        node,
                    };

                    match SCHEMA.get_kind(&node.kind) {
                        Some(kind) => (kind.render(&context), kind.validator(&context)),
                        None => (
                            crate::schema::textbox(
                                self,
                                node,
                                path,
                                &self.parsed_commands,
                                placeholder,
                                &[],
                            ),
                            vec![],
                        ),
                    }
                }
                None => (
                    html! {
                        { format!("invalid hash: {:?}", hash) }
                    },
                    vec![],
                ),
            },
            None => (
                crate::schema::textbox(
                    self,
                    &Node::default(),
                    path,
                    &self.parsed_commands,
                    placeholder,
                    &[],
                ),
                vec![],
            ),
        };
        // Use onmousedown to avoid re-selecting the node?
        html! {

                { value }
                { for errors.iter().map(|e| self.view_error(e)) }

        }
    }

    pub fn view_error(&self, error: &ValidationError) -> Html {
        html! {

{ format!("error: {:?}", error.message) }

        }
    }

    pub fn view_child(&self, node: &Node, field_name: &str, path: &[Selector]) -> Html {
        self.view_child_with_placeholder(node, field_name, path, field_name)
    }

    pub fn view_child_with_placeholder(
        &self,
        parent: &Node,
        field_name: &str,
        path: &[Selector],
        placeholder: &str,
    ) -> Html {
        let path = append(
            &path,
            Selector {
                field: field_name.to_string(),
                index: 0,
            },
        );
        let hash = parent
            .children
            .get(field_name)
            .and_then(|v| v.get(0))
            .cloned();
        // Empty list vs hole vs special value?
        // TODO: How to traverse nested lists in preorder?
        self.view_node_with_placeholder(hash, &path, placeholder)
    }

    /// Returns the head and children, separately.
    pub fn view_children(
        &self,
        parent: &Node,
        field_name: &str,
        path: &[Selector],
    ) -> (Html, Vec) {
        // let path = append(&path, field(field_name));
        // let cursor = sub_cursor(&cursor, field(field_name));
        let empty = vec![];
        let children = parent.children.get(field_name).unwrap_or(&empty);
        let head = {
            let path = append(
                &path,
                Selector {
                    field: field_name.to_string(),
                    index: children.len(),
                },
            );
            let mut classes = vec!["node".to_string(), "placeholder".to_string()];
            if path == self.cursor {
                classes.push("selected".to_string());
            }
            if path == self.hover {
                classes.push("hover".to_string());
            }

            let path_clone = path.clone();
            let _onclick = self.link.callback(move |e: MouseEvent| {
                e.stop_propagation();
                Msg::Select(path_clone.clone())
            });

            let path_clone = path.clone();
            let _onmouseover = self.link.callback(move |e: MouseEvent| {
                e.stop_propagation();
                Msg::Hover(path_clone.clone())
            });

            // html! {
            //
{ field_name
            // }{ "▷" }
 }
            html! {

            }
        };

        let nodes = children
            .iter()
            .enumerate()
            .map(|(i, h)| {
                let path = append(
                    &path,
                    Selector {
                        field: field_name.to_string(),
                        index: i,
                    },
                );
                self.view_node(Some(h.clone()), &path)
            })
            .chain(std::iter::once({
                let path = append(
                    &path,
                    Selector {
                        field: field_name.to_string(),
                        index: children.len(),
                    },
                );
                self.view_node_with_placeholder(None, &path, &format!("{}▷", field_name))
            }))
            .collect::<Vec<_>>();
        (head, nodes)
    }
}

pub fn command_input_id(path: &[Selector]) -> String {
    let mut id = String::new();
    for selector in path {
        id.push_str(&selector.field);
        id.push_str(&selector.index.to_string());
    }
    id
}
<commit_msg>Nested headers<commit_after>use yew::prelude::*;

use crate::{
    schema::{Field, Multiplicity, ValidationError, ValidatorContext, SCHEMA},
    types::*,
};

impl Model {
    pub fn view_actions(&self) -> Html {
        let actions = vec![
            Action {
                image: None,
                text: "store".to_string(),
                msg: Msg::Store,
            },
            Action {
                image: None,
                text: "load".to_string(),
                msg: Msg::Load,
            },
            Action {
                image: None,
                text: "Normal mode".to_string(),
                msg: Msg::SetMode(Mode::Normal),
            },
            Action {
                image: None,
                text: "Edit mode".to_string(),
                msg: Msg::SetMode(Mode::Edit),
            },
            Action {
                image: Some("gg-arrow-left".to_string()),
                text: "prev".to_string(),
                msg: Msg::Prev,
            },
            Action {
                image: Some("gg-arrow-right".to_string()),
                text: "next".to_string(),
                msg: Msg::Next,
            },
            Action {
                image: Some("gg-corner-right-up".to_string()),
                text: "parent".to_string(),
                msg: Msg::Parent,
            },
            Action {
                image: Some("gg-corner-double-up-right".to_string()),
                text: "+item".to_string(),
                msg: Msg::AddItem,
            },
            Action {
                image: Some("gg-close".to_string()),
                text: "delete".to_string(),
                msg: Msg::DeleteItem,
            },
        ];
        let actions = actions
            .iter()
            // .filter(|a| self.is_valid_action(a))
            .map(|a| self.view_action(a));

        html! {

                { for actions }

        }
    }

    pub fn current_field(&self) -> Option<Field> {
        self.field(&self.cursor)
    }

    pub fn field(&self, path: &Path) -> Option<Field> {
        path.split_last().and_then(|(selector, parent_path)| {
            let parent = self.file.lookup(&parent_path).unwrap();
            SCHEMA
                .get_kind(&parent.kind)
                .unwrap()
                .get_field(&selector.field)
        })
    }

    fn view_action(&self, action: &Action) -> Html {
        let msg = action.msg.clone();
        let callback = self.link.callback(move |_: MouseEvent| msg.clone());
        let img = match &action.image {
            Some(image) => html! {

            },
            None => html! {},
        };
        html! {
            <button
              class="action hover:bg-blue-200 hover:text-blue-800 group flex items-center rounded-md bg-blue-100 text-blue-600 text-sm font-medium px-4 py-2"
              onclick=callback>
                { img }
                { &action.text }
            </button>
        }
    }

    pub fn view_file(&self, file: &File) -> Html {
        let node = self.view_node(Some(file.root.clone()), &Path::new());
        html! {

{ node }

        }
    }

    pub fn view_file_json(&self, file: &File) -> Html {
        // let serialized = serde_json::to_string_pretty(file).expect("could not serialize to
        // JSON");
        let serialized = format!("root: {:?}\nfile: {:#?}", file.root, file);
        html! {

{ serialized }

        }
    }

    pub fn traverse_fields(node: &Node) -> Vec<Field> {
        let kind = &node.kind;
        match SCHEMA.get_kind(kind) {
            Some(kind) => kind.get_fields(),
            None => vec![],
        }
    }

    pub fn flatten_paths(&self, path: &[Selector]) -> Vec<Path> {
        // log::info!("flatten: {:?}", path);
        match &self.file.lookup(path) {
            Some(node) => {
                let mut paths = vec![];
                for field in Model::traverse_fields(&node) {
                    let mut children = node.children.get(field.name).cloned().unwrap_or_default();
                    match field.multiplicity {
                        Multiplicity::Single => {
                            if children.is_empty() {
                                children.push("".to_string());
                            }
                        }
                        Multiplicity::Repeated => {}
                    };
                    for (n, _child) in children.iter().enumerate() {
                        let new_path = append(
                            path,
                            Selector {
                                field: field.name.to_string(),
                                index: n,
                            },
                        );
                        paths.push(new_path.clone());
                        // log::info!("child: {:?}[{:?}]->{:?}", path, field.name, child);
                        paths.extend(self.flatten_paths(&new_path));
                    }
                    match field.multiplicity {
                        // If repeated field, stay on the parent.
                        Multiplicity::Repeated => {
                            let new_base = append(
                                path,
                                Selector {
                                    field: field.name.to_string(),
                                    index: children.len(),
                                },
                            );
                            paths.push(new_base.clone());
                        }
                        // If single field, skip directly to the first (and only) child.
                        Multiplicity::Single => {}
                    }
                }
                paths
            }
            None => vec![],
        }
    }

    fn view_node(&self, hash: Option<Hash>, path: &[Selector]) -> Html {
        self.view_node_with_placeholder(hash, path, "◆")
    }

    fn view_node_with_placeholder(
        &self,
        hash: Option<Hash>,
        path: &[Selector],
        placeholder: &str,
    ) -> Html {
        let selected = path == &self.cursor;
        let mut classes = vec!["node".to_string(), "align-top".to_string()];
        if selected {
            classes.push("selected".to_string());
        }
        if path == &self.hover {
            // classes.push("hover".to_string());
        }

        let path_clone = path.to_vec();
        let onclick = self.link.callback(move |e: MouseEvent| {
            e.stop_propagation();
            Msg::Select(path_clone.clone())
        });

        let path_clone = path.to_vec();
        let onmouseover = self.link.callback(move |e: MouseEvent| {
            e.stop_propagation();
            Msg::Hover(path_clone.clone())
        });

        let path_clone = path.to_vec();
        let _oninput = self.link.callback(move |e: InputData| {
            crate::types::Msg::SetNodeCommand(path_clone.clone(), e.value.clone())
        });

        let (value, errors) = match hash {
            Some(hash) => match self.file.lookup(path) {
                Some(node) => {
                    let context = ValidatorContext {
                        model: self,
                        path,
                        node,
                    };

                    match SCHEMA.get_kind("&node.kind") {
                        Some(kind) => (kind.render(&context), kind.validator(&context)),
                        None => (
                            {
                                // https://codepen.io/xotonic/pen/JRLAOR
                                let fields = node.children.iter().map(
                                    (|(name, hashes)| {
                                        let values = hashes.iter().enumerate().map(|(i, h)| {
                                            let v = self.view_node(
                                                Some(h.to_string()),
                                                &append(
                                                    path,
                                                    Selector {
                                                        field: name.to_string(),
                                                        index: i,
                                                    },
                                                ),
                                            );
                                            html! {

{ v }

                                            }
                                        });
                                        html! {

                                                  { name }

{ for values }

                                        }
                                    }),
                                );
                                html! {

{ "kind: " }{ &node.kind }

{ "value: " }{ &node.value }

                                        { for fields }

                                }
                            },
                            // crate::schema::textbox(
                            //     self,
                            //     node,
                            //     path,
                            //     &self.parsed_commands,
                            //     placeholder,
                            //     &[],
                            // ),
                            vec![],
                        ),
                    }
                }
                None => (
                    html! {
                        { format!("invalid hash: {:?}", hash) }
                    },
                    vec![],
                ),
            },
            None => (
                crate::schema::textbox(
                    self,
                    &Node::default(),
                    path,
                    &self.parsed_commands,
                    placeholder,
                    &[],
                ),
                vec![],
            ),
        };
        // Use onmousedown to avoid re-selecting the node?
        html! {

                { value }
                { for errors.iter().map(|e| self.view_error(e)) }

        }
    }

    pub fn view_error(&self, error: &ValidationError) -> Html {
        html! {

{ format!("error: {:?}", error.message) }

        }
    }

    pub fn view_child(&self, node: &Node, field_name: &str, path: &[Selector]) -> Html {
        self.view_child_with_placeholder(node, field_name, path, field_name)
    }

    pub fn view_child_with_placeholder(
        &self,
        parent: &Node,
        field_name: &str,
        path: &[Selector],
        placeholder: &str,
    ) -> Html {
        let path = append(
            &path,
            Selector {
                field: field_name.to_string(),
                index: 0,
            },
        );
        let hash = parent
            .children
            .get(field_name)
            .and_then(|v| v.get(0))
            .cloned();
        // Empty list vs hole vs special value?
        // TODO: How to traverse nested lists in preorder?
        self.view_node_with_placeholder(hash, &path, placeholder)
    }

    /// Returns the head and children, separately.
    pub fn view_children(
        &self,
        parent: &Node,
        field_name: &str,
        path: &[Selector],
    ) -> (Html, Vec) {
        // let path = append(&path, field(field_name));
        // let cursor = sub_cursor(&cursor, field(field_name));
        let empty = vec![];
        let children = parent.children.get(field_name).unwrap_or(&empty);
        let head = {
            let path = append(
                &path,
                Selector {
                    field: field_name.to_string(),
                    index: children.len(),
                },
            );
            let mut classes = vec!["node".to_string(), "placeholder".to_string()];
            if path == self.cursor {
                classes.push("selected".to_string());
            }
            if path == self.hover {
                classes.push("hover".to_string());
            }

            let path_clone = path.clone();
            let _onclick = self.link.callback(move |e: MouseEvent| {
                e.stop_propagation();
                Msg::Select(path_clone.clone())
            });

            let path_clone = path.clone();
            let _onmouseover = self.link.callback(move |e: MouseEvent| {
                e.stop_propagation();
                Msg::Hover(path_clone.clone())
            });

            // html! {
            //
{ field_name
            // }{ "▷" }
 }
            html! {

            }
        };

        let nodes = children
            .iter()
            .enumerate()
            .map(|(i, h)| {
                let path = append(
                    &path,
                    Selector {
                        field: field_name.to_string(),
                        index: i,
                    },
                );
                self.view_node(Some(h.clone()), &path)
            })
            .chain(std::iter::once({
                let path = append(
                    &path,
                    Selector {
                        field: field_name.to_string(),
                        index: children.len(),
                    },
                );
                self.view_node_with_placeholder(None, &path, &format!("{}▷", field_name))
            }))
            .collect::<Vec<_>>();
        (head, nodes)
    }
}

pub fn command_input_id(path: &[Selector]) -> String {
    let mut id = String::new();
    for selector in path {
        id.push_str(&selector.field);
        id.push_str(&selector.index.to_string());
    }
    id
}
<|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 std::fmt;
use std::from_str::FromStr;
use std::gc::Gc;
use syntax::{ast, ext};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic;
use syntax::{attr, codemap};
use syntax::parse::token;

/// A component modifier.
#[deriving(PartialEq)]
enum Modifier {
    /// Corresponds to the `#[normalized]` attribute.
    ///
    /// Normalizes the component at runtime. Unsigned integers are normalized to
    /// `[0, 1]`. Signed integers are normalized to `[-1, 1]`.
    Normalized,
    /// Corresponds to the `#[as_float]` attribute.
    ///
    /// Casts the component to a float precision floating-point number at runtime.
    AsFloat,
    /// Corresponds to the `#[as_double]` attribute.
    ///
    /// Casts the component to a double precision floating-point number at runtime.
    AsDouble,
}

impl fmt::Show for Modifier {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Normalized => write!(f, "normalized"),
            AsFloat => write!(f, "as_float"),
            AsDouble => write!(f, "as_double"),
        }
    }
}

impl FromStr for Modifier {
    fn from_str(src: &str) -> Option<Modifier> {
        match src {
            "normalized" => Some(Normalized),
            "as_float" => Some(AsFloat),
            "as_double" => Some(AsDouble),
            _ => None,
        }
    }
}

/// Scan through the field's attributes and extract a relevant modifier. If
/// multiple modifier attributes are found, use the first modifier and emit a
/// warning.
fn find_modifier(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
                 attributes: &[ast::Attribute]) -> Option<Modifier> {
    attributes.iter().fold(None, |modifier, attribute| {
        match attribute.node.value.node {
            ast::MetaWord(ref word) => {
                from_str(word.get()).and_then(|new_modifier| {
                    attr::mark_used(attribute);
                    modifier.map_or(Some(new_modifier), |modifier| {
                        cx.span_warn(span, format!(
                            "Extra attribute modifier detected: `#[{}]` - \
                            ignoring in favour of `#[{}]`.", new_modifier, modifier
                        ).as_slice());
                        None
                    })
                }).or(modifier)
            },
            _ => modifier,
        }
    })
}

/// Find a `gfx::attrib::Type` that describes the given type identifier.
fn decode_type(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
               ty_ident: &ast::Ident, modifier: Option<Modifier>) -> Gc<ast::Expr> {
    let ty_str = ty_ident.name.as_str();
    match ty_str {
        "f32" | "f64" => {
            let kind = cx.ident_of(match modifier {
                None | Some(AsFloat) => "FloatDefault",
                Some(AsDouble) => "FloatPrecision",
                Some(Normalized) => {
                    cx.span_warn(span, format!(
                        "Incompatible float modifier attribute: `#[{}]`", modifier
                    ).as_slice());
                    ""
                }
            });
            let sub_type = cx.ident_of(format!("F{}", ty_str.slice_from(1)).as_slice());
            quote_expr!(cx, gfx::attrib::Float(gfx::attrib::$kind,
                                               gfx::attrib::$sub_type))
        },
        "u8" | "u16" | "u32" | "u64" | "uint" |
        "i8" | "i16" | "i32" | "i64" | "int" => {
            let sign = cx.ident_of({
                if ty_str.starts_with("i") { "Signed" } else { "Unsigned" }
            });
            let kind = cx.ident_of(match modifier {
                None => "IntRaw",
                Some(Normalized) => "IntNormalized",
                Some(AsFloat) => "IntAsFloat",
                Some(AsDouble) => {
                    cx.span_warn(span, format!(
                        "Incompatible int modifier attribute: `#[{}]`", modifier
                    ).as_slice());
                    ""
                }
            });
            let sub_type = cx.ident_of(format!("U{}", ty_str.slice_from(1)).as_slice());
            quote_expr!(cx, gfx::attrib::Int(gfx::attrib::$kind,
                                             gfx::attrib::$sub_type,
                                             gfx::attrib::$sign))
        },
        ty_str => {
            cx.span_err(span, format!("Unrecognized component type: `{}`", ty_str).as_slice());
            cx.expr_lit(span, ast::LitNil)
        },
    }
}

fn decode_count_and_type(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
                         field: &ast::StructField) -> (Gc<ast::Expr>, Gc<ast::Expr>) {
    let modifier = find_modifier(cx, span, field.node.attrs.as_slice());
    match field.node.ty.node {
        ast::TyPath(ref p, _, _) => (
            cx.expr_lit(span, ast::LitIntUnsuffixed(1)),
            decode_type(cx, span, &p.segments[0].identifier, modifier),
        ),
        ast::TyFixedLengthVec(pty, expr) => (expr, match pty.node {
            ast::TyPath(ref p, _, _) => {
                decode_type(cx, span, &p.segments[0].identifier, modifier)
            },
            _ => {
                cx.span_err(span, format!("Unsupported fixed vector sub-type: \
                                          `{}`",pty.node).as_slice());
                cx.expr_lit(span, ast::LitNil)
            },
        }),
        _ => {
            cx.span_err(span, format!("Unsupported attribute type: `{}`",
                                      field.node.ty.node).as_slice());
            (cx.expr_lit(span, ast::LitNil), cx.expr_lit(span, ast::LitNil))
        },
    }
}

fn offset_expr(cx: &mut ext::base::ExtCtxt, _: codemap::Span,
                    struct_ident: ast::Ident, field_ident: ast::Ident) -> Gc<ast::Expr> {
    quote_expr!(cx, unsafe {
        &(*(0u as *const $struct_ident)).$field_ident as *const _ as gfx::attrib::Offset
    })
}

fn stride_expr(cx: &mut ext::base::ExtCtxt, struct_ident: ast::Ident) -> Gc<ast::Expr> {
    quote_expr!(cx, std::mem::size_of::<$struct_ident>() as gfx::attrib::Stride)
}

/// Generates the the method body for `gfx::VertexFormat::generate`.
fn method_body(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
                   substr: &generic::Substructure) -> Gc<ast::Expr> {
    match *substr.fields {
        generic::StaticStruct(ref definition, generic::Named(ref fields)) => {
            let mut statements = Vec::new();
            let id_at = cx.ident_of("at");
            let ex_new = cx.expr_call(span, cx.expr_path(cx.path(span,
                    vec![cx.ident_of("Vec"), cx.ident_of("with_capacity")]
                )), vec![cx.expr_uint(span, fields.len())]
            );
            statements.push(cx.stmt_let(span, true, id_at, ex_new));
            let ex_stride = stride_expr(cx, substr.type_ident);
            for (def, &(ident, _)) in definition.fields.iter().zip(fields.iter()) {
                let (ex_count, ex_type) = decode_count_and_type(cx, span, def);
                let ex_offset = offset_expr(cx, span, substr.type_ident, ident);
                let ex_struct = cx.expr_struct(span,
                    cx.path(span, vec![
                        cx.ident_of("gfx"),
                        cx.ident_of("Attribute")
                        ]),
                    vec![
                        cx.field_imm(span, cx.ident_of("buffer"), substr.nonself_args[1]),
                        cx.field_imm(span, cx.ident_of("elem_count"), ex_count),
                        cx.field_imm(span, cx.ident_of("elem_type"), ex_type),
                        cx.field_imm(span, cx.ident_of("offset"), ex_offset),
                        cx.field_imm(span, cx.ident_of("stride"), ex_stride),
                        cx.field_imm(span, cx.ident_of("name"), cx.expr_method_call(span,
                            cx.expr_str(span, token::get_ident(ident)),
                            cx.ident_of("to_string"), Vec::new()))
                    ]
                );
                statements.push(cx.stmt_expr(cx.expr_method_call(
                    span,
                    cx.expr_ident(span, id_at),
                    cx.ident_of("push"),
                    vec![ex_struct]
                )));
            }
            cx.expr_block(cx.block_all(
                span,
                Vec::new(),
                statements,
                Some(cx.expr_ident(span, id_at))
            ))
        },
        _ => {
            cx.span_err(span, "Unable to implement `generate()` on a non-structure");
            cx.expr_lit(span, ast::LitNil)
        }
    }
}

/// Derive a `gfx::VertexFormat` implementation for the `struct`
pub fn expand(context: &mut ext::base::ExtCtxt, span: codemap::Span,
              meta_item: Gc<ast::MetaItem>, item: Gc<ast::Item>,
              push: |Gc<ast::Item>|) {
    // `impl gfx::VertexFormat for $item`
    generic::TraitDef {
        span: span,
        attributes: Vec::new(),
        path: generic::ty::Path {
            path: vec!["gfx", "VertexFormat"],
            lifetime: None,
            params: Vec::new(),
            global: true,
        },
        additional_bounds: Vec::new(),
        generics: generic::ty::LifetimeBounds::empty(),
        methods: vec![
            // `fn generate(Option<Self>, gfx::BufferHandle) -> Vec<gfx::Attribute>`
            generic::MethodDef {
                name: "generate",
                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::Self],
                        global: false,
                    }),
                    generic::ty::Literal(generic::ty::Path::new(
                        vec!["gfx", "BufferHandle"]
                    )),
                ],
                ret_ty: generic::ty::Literal(
                    generic::ty::Path {
                        path: vec!["Vec"],
                        lifetime: None,
                        params: vec![
                            box generic::ty::Literal(generic::ty::Path::new(
                                vec!["gfx", "Attribute"])),
                        ],
                        global: false,
                    },
                ),
                attributes: Vec::new(),
                // generate the method body
                combine_substructure: generic::combine_substructure(method_body),
            },
        ],
    }.expand(context, meta_item, item, push);
}
<commit_msg>Use quote_expr! more extensively<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 std::fmt;
use std::from_str::FromStr;
use std::gc::Gc;
use syntax::{ast, ext};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic;
use syntax::{attr, codemap};
use syntax::parse::token;

/// A component modifier.
#[deriving(PartialEq)]
enum Modifier {
    /// Corresponds to the `#[normalized]` attribute.
    ///
    /// Normalizes the component at runtime. Unsigned integers are normalized to
    /// `[0, 1]`. Signed integers are normalized to `[-1, 1]`.
    Normalized,
    /// Corresponds to the `#[as_float]` attribute.
    ///
    /// Casts the component to a float precision floating-point number at runtime.
    AsFloat,
    /// Corresponds to the `#[as_double]` attribute.
    ///
    /// Casts the component to a double precision floating-point number at runtime.
    AsDouble,
}

impl fmt::Show for Modifier {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Normalized => write!(f, "normalized"),
            AsFloat => write!(f, "as_float"),
            AsDouble => write!(f, "as_double"),
        }
    }
}

impl FromStr for Modifier {
    fn from_str(src: &str) -> Option<Modifier> {
        match src {
            "normalized" => Some(Normalized),
            "as_float" => Some(AsFloat),
            "as_double" => Some(AsDouble),
            _ => None,
        }
    }
}

/// Scan through the field's attributes and extract a relevant modifier. If
/// multiple modifier attributes are found, use the first modifier and emit a
/// warning.
fn find_modifier(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
                 attributes: &[ast::Attribute]) -> Option<Modifier> {
    attributes.iter().fold(None, |modifier, attribute| {
        match attribute.node.value.node {
            ast::MetaWord(ref word) => {
                from_str(word.get()).and_then(|new_modifier| {
                    attr::mark_used(attribute);
                    modifier.map_or(Some(new_modifier), |modifier| {
                        cx.span_warn(span, format!(
                            "Extra attribute modifier detected: `#[{}]` - \
                            ignoring in favour of `#[{}]`.", new_modifier, modifier
                        ).as_slice());
                        None
                    })
                }).or(modifier)
            },
            _ => modifier,
        }
    })
}

/// Find a `gfx::attrib::Type` that describes the given type identifier.
fn decode_type(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
               ty_ident: &ast::Ident, modifier: Option<Modifier>) -> Gc<ast::Expr> {
    let ty_str = ty_ident.name.as_str();
    match ty_str {
        "f32" | "f64" => {
            let kind = cx.ident_of(match modifier {
                None | Some(AsFloat) => "FloatDefault",
                Some(AsDouble) => "FloatPrecision",
                Some(Normalized) => {
                    cx.span_warn(span, format!(
                        "Incompatible float modifier attribute: `#[{}]`", modifier
                    ).as_slice());
                    ""
                }
            });
            let sub_type = cx.ident_of(format!("F{}", ty_str.slice_from(1)).as_slice());
            quote_expr!(cx, gfx::attrib::Float(gfx::attrib::$kind,
                                               gfx::attrib::$sub_type))
        },
        "u8" | "u16" | "u32" | "u64" | "uint" |
        "i8" | "i16" | "i32" | "i64" | "int" => {
            let sign = cx.ident_of({
                if ty_str.starts_with("i") { "Signed" } else { "Unsigned" }
            });
            let kind = cx.ident_of(match modifier {
                None => "IntRaw",
                Some(Normalized) => "IntNormalized",
                Some(AsFloat) => "IntAsFloat",
                Some(AsDouble) => {
                    cx.span_warn(span, format!(
                        "Incompatible int modifier attribute: `#[{}]`", modifier
                    ).as_slice());
                    ""
                }
            });
            let sub_type = cx.ident_of(format!("U{}", ty_str.slice_from(1)).as_slice());
            quote_expr!(cx, gfx::attrib::Int(gfx::attrib::$kind,
                                             gfx::attrib::$sub_type,
                                             gfx::attrib::$sign))
        },
        ty_str => {
            cx.span_err(span, format!("Unrecognized component type: `{}`", ty_str).as_slice());
            cx.expr_lit(span, ast::LitNil)
        },
    }
}

fn decode_count_and_type(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
                         field: &ast::StructField) -> (Gc<ast::Expr>, Gc<ast::Expr>) {
    let modifier = find_modifier(cx, span, field.node.attrs.as_slice());
    match field.node.ty.node {
        ast::TyPath(ref p, _, _) => (
            cx.expr_lit(span, ast::LitIntUnsuffixed(1)),
            decode_type(cx, span, &p.segments[0].identifier, modifier),
        ),
        ast::TyFixedLengthVec(pty, expr) => (expr, match pty.node {
            ast::TyPath(ref p, _, _) => {
                decode_type(cx, span, &p.segments[0].identifier, modifier)
            },
            _ => {
                cx.span_err(span, format!("Unsupported fixed vector sub-type: \
                                          `{}`",pty.node).as_slice());
                cx.expr_lit(span, ast::LitNil)
            },
        }),
        _ => {
            cx.span_err(span, format!("Unsupported attribute type: `{}`",
                                      field.node.ty.node).as_slice());
            (cx.expr_lit(span, ast::LitNil), cx.expr_lit(span, ast::LitNil))
        },
    }
}

/// A hacky thing to get around 'moved value' errors when using `quote_expr!`
/// with `ext::base::ExtCtxt`s.
fn ugh<T, U>(x: &mut T, f: |&mut T| -> U) -> U { f(x) }

/// Generates the the method body for `gfx::VertexFormat::generate`.
fn method_body(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
                   substr: &generic::Substructure) -> Gc<ast::Expr> {
    match *substr.fields {
        generic::StaticStruct(ref definition, generic::Named(ref fields)) => {
            let attribute_pushes = definition.fields.iter().zip(fields.iter())
                .map(|(def, &(ident, _))| {
                    let struct_ident = substr.type_ident;
                    let buffer_expr = substr.nonself_args[1];
                    let (count_expr, type_expr) = decode_count_and_type(cx, span, def);
                    let ident_str = token::get_ident(ident);
                    let ident_str = ident_str.get();
                    ugh(cx, |cx| quote_expr!(cx, {
                        attributes.push(gfx::Attribute {
                            buffer: $buffer_expr,
                            elem_count: $count_expr,
                            elem_type: $type_expr,
                            offset: unsafe {
                                &(*(0u as *const $struct_ident)).$ident as *const _ as gfx::attrib::Offset
                            },
                            stride: std::mem::size_of::<$struct_ident>() as gfx::attrib::Stride,
                            name: $ident_str.to_string(),
                        });
                    }))
                }).collect::<Vec<Gc<ast::Expr>>>();
            let capacity = fields.len();
            ugh(cx, |cx| quote_expr!(cx, {
                let mut attributes = Vec::with_capacity($capacity);
                $attribute_pushes;
                attributes
            }))
        },
        _ => {
            cx.span_err(span, "Unable to implement `gfx::VertexFormat::generate` \
                              on a non-structure");
            cx.expr_lit(span, ast::LitNil)
        }
    }
}

/// Derive a `gfx::VertexFormat` implementation for the `struct`
pub fn expand(context: &mut ext::base::ExtCtxt, span: codemap::Span,
              meta_item: Gc<ast::MetaItem>, item: Gc<ast::Item>,
              push: |Gc<ast::Item>|) {
    // `impl gfx::VertexFormat for $item`
    generic::TraitDef {
        span: span,
        attributes: Vec::new(),
        path: generic::ty::Path {
            path: vec!["gfx", "VertexFormat"],
            lifetime: None,
            params: Vec::new(),
            global: true,
        },
        additional_bounds: Vec::new(),
        generics: generic::ty::LifetimeBounds::empty(),
        methods: vec![
            // `fn generate(Option<Self>, gfx::BufferHandle) -> Vec<gfx::Attribute>`
            generic::MethodDef {
                name: "generate",
                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::Self],
                        global: false,
                    }),
                    generic::ty::Literal(generic::ty::Path::new(
                        vec!["gfx", "BufferHandle"]
                    )),
                ],
                ret_ty: generic::ty::Literal(
                    generic::ty::Path {
                        path: vec!["Vec"],
                        lifetime: None,
                        params: vec![
                            box generic::ty::Literal(generic::ty::Path::new(
                                vec!["gfx", "Attribute"])),
                        ],
                        global: false,
                    },
                ),
                attributes: Vec::new(),
                // generate the method body
                combine_substructure: generic::combine_substructure(method_body),
            },
        ],
    }.expand(context, meta_item, item, push);
}
<|endoftext|>


<commit_before>use std::io::{Read, Cursor, Seek, SeekFrom, Write};
use blockchain::{block::*, index::*};
use std::collections::HashMap;
use std::cell::RefCell;
use std::path::Path;
use std::sync::Arc;
use std::fs::File;
use crc32c::*;

pub struct BlockStore {
    indexer: Arc<Indexer>,

    height: u64,
    blocks: HashMap<u64, Arc<SignedBlock>>,
    genesis_block: Option<Arc<SignedBlock>>,

    file: RefCell<File>,
    byte_pos_tail: u64
}

impl BlockStore {

    pub fn new(path: &Path, indexer: Arc<Indexer>) -> BlockStore {
        let (file, tail) = if !path.is_file() {
            (File::create(path).unwrap(), 0u64)
        } else {
            let f = File::open(path).unwrap();
            let m = f.metadata().unwrap();
            (File::open(path).unwrap(), m.len())
        };

        let height = indexer.get_chain_height();
        let mut store = BlockStore {
            indexer,

            height,
            blocks: HashMap::new(),
            genesis_block: None,

            file: RefCell::new(file),
            byte_pos_tail: tail
        };
        store.genesis_block = store.get(0);

        { // Initialize the cache
            let min = if height <= 100 { height } else { height - 100 };
            let max = min + 100;
            for height in min..max {
                if let Some(block) = store.get_from_disk(height) {
                    store.blocks.insert(height, Arc::new(block));
                } else {
                    break;
                }
            }
        }

        store
    }

    #[inline(always)]
    pub fn get_chain_height(&self) -> u64 {
        self.height
    }

    pub fn get(&self, height: u64) -> Option<Arc<SignedBlock>> {
        if height > self.height {
            return None
        } else if height == 0 {
            if let Some(ref block) = self.genesis_block {
                return Some(Arc::clone(block))
            }
        }
        if let Some(block) = self.blocks.get(&height) {
            Some(Arc::clone(block))
        } else {
            Some(Arc::new(self.get_from_disk(height)?))
        }
    }

    fn get_from_disk(&self, height: u64) -> Option<SignedBlock> {
        if height > self.height { return None }

        let pos = self.indexer.get_block_byte_pos(height).unwrap();
        let mut f = self.file.borrow_mut();
        f.seek(SeekFrom::Start(pos)).unwrap();

        let (block_len, crc) = {
            let mut meta = [0u8; 8];
            f.read_exact(&mut meta).unwrap();
            let len = u32_from_buf!(meta, 0) as usize;
            let crc = u32_from_buf!(meta, 4);
            (len, crc)
        };

        let block_vec = {
            let mut buf = Vec::with_capacity(block_len);
            unsafe { buf.set_len(block_len); }
            f.read_exact(&mut buf).unwrap();
            assert_eq!(crc, crc32c(&buf));
            buf
        };

        let mut cursor = Cursor::<&[u8]>::new(&block_vec);
        let block = SignedBlock::decode_with_tx(&mut cursor).unwrap();
        Some(block)
    }

    pub fn insert(&mut self, block: SignedBlock) {
        assert_eq!(self.height + 1, block.height, "invalid block height");
        self.insert_raw(block);
    }

    pub fn insert_genesis(&mut self, block: SignedBlock) {
        assert_eq!(block.height, 0, "expected to be 0");
        assert!(self.genesis_block.is_none(), "expected genesis block to not exist");
        self.insert_raw(block.clone());
        self.genesis_block = Some(Arc::new(block));
    }

    fn insert_raw(&mut self, block: SignedBlock) {
        { // Write to disk
            let vec = &mut Vec::with_capacity(1048576);
            block.encode_with_tx(vec);
            let len = vec.len() as u32;
            let crc = crc32c(vec);

            let mut f = self.file.borrow_mut();
            {
                let mut buf = [0u8; 8];
                buf[0] = (len >> 24) as u8;
                buf[1] = (len >> 16) as u8;
                buf[2] = (len >> 8) as u8;
                buf[3] = len as u8;

                buf[4] = (crc >> 24) as u8;
                buf[5] = (crc >> 16) as u8;
                buf[6] = (crc >> 8) as u8;
                buf[7] = crc as u8;

                f.write_all(&buf).unwrap();
            }

            f.write_all(vec).unwrap();
            f.flush().unwrap();

            self.byte_pos_tail += (len as u64) + 8;
        }

        { // Update internal cache
            let height = block.height;
            self.height = height;
            let opt = self.blocks.insert(height, Arc::new(block));
            if self.blocks.len() > 100 {
                let b = self.blocks.remove(&(height - 100));
                debug_assert!(b.is_some(), "nothing removed from cache");
            }
            debug_assert!(opt.is_none(), "block already in the chain");
        }
    }
}
<commit_msg>Return None if the block byte pos is not found<commit_after>use std::io::{Read, Cursor, Seek, SeekFrom, Write};
use blockchain::{block::*, index::*};
use std::collections::HashMap;
use std::cell::RefCell;
use std::path::Path;
use std::sync::Arc;
use std::fs::File;
use crc32c::*;

pub struct BlockStore {
    indexer: Arc<Indexer>,

    height: u64,
    blocks: HashMap<u64, Arc<SignedBlock>>,
    genesis_block: Option<Arc<SignedBlock>>,

    file: RefCell<File>,
    byte_pos_tail: u64
}

impl BlockStore {

    pub fn new(path: &Path, indexer: Arc<Indexer>) -> BlockStore {
        let (file, tail) = if !path.is_file() {
            (File::create(path).unwrap(), 0u64)
        } else {
            let f = File::open(path).unwrap();
            let m = f.metadata().unwrap();
            (File::open(path).unwrap(), m.len())
        };

        let height = indexer.get_chain_height();
        let mut store = BlockStore {
            indexer,

            height,
            blocks: HashMap::new(),
            genesis_block: None,

            file: RefCell::new(file),
            byte_pos_tail: tail
        };
        store.genesis_block = store.get(0);

        { // Initialize the cache
            let min = if height <= 100 { height } else { height - 100 };
            let max = min + 100;
            for height in min..max {
                if let Some(block) = store.get_from_disk(height) {
                    store.blocks.insert(height, Arc::new(block));
                } else {
                    break;
                }
            }
        }

        store
    }

    #[inline(always)]
    pub fn get_chain_height(&self) -> u64 {
        self.height
    }

    pub fn get(&self, height: u64) -> Option<Arc<SignedBlock>> {
        if height > self.height {
            return None
        } else if height == 0 {
            if let Some(ref block) = self.genesis_block {
                return Some(Arc::clone(block))
            }
        }
        if let Some(block) = self.blocks.get(&height) {
            Some(Arc::clone(block))
        } else {
            Some(Arc::new(self.get_from_disk(height)?))
        }
    }

    fn get_from_disk(&self, height: u64) -> Option<SignedBlock> {
        if height > self.height { return None }

        let pos = self.indexer.get_block_byte_pos(height)?;
        let mut f = self.file.borrow_mut();
        f.seek(SeekFrom::Start(pos)).unwrap();

        let (block_len, crc) = {
            let mut meta = [0u8; 8];
            f.read_exact(&mut meta).unwrap();
            let len = u32_from_buf!(meta, 0) as usize;
            let crc = u32_from_buf!(meta, 4);
            (len, crc)
        };

        let block_vec = {
            let mut buf = Vec::with_capacity(block_len);
            unsafe { buf.set_len(block_len); }
            f.read_exact(&mut buf).unwrap();
            assert_eq!(crc, crc32c(&buf));
            buf
        };

        let mut cursor = Cursor::<&[u8]>::new(&block_vec);
        let block = SignedBlock::decode_with_tx(&mut cursor).unwrap();
        Some(block)
    }

    pub fn insert(&mut self, block: SignedBlock) {
        assert_eq!(self.height + 1, block.height, "invalid block height");
        self.insert_raw(block);
    }

    pub fn insert_genesis(&mut self, block: SignedBlock) {
        assert_eq!(block.height, 0, "expected to be 0");
        assert!(self.genesis_block.is_none(), "expected genesis block to not exist");
        self.insert_raw(block.clone());
        self.genesis_block = Some(Arc::new(block));
    }

    fn insert_raw(&mut self, block: SignedBlock) {
        { // Write to disk
            let vec = &mut Vec::with_capacity(1048576);
            block.encode_with_tx(vec);
            let len = vec.len() as u32;
            let crc = crc32c(vec);

            let mut f = self.file.borrow_mut();
            {
                let mut buf = [0u8; 8];
                buf[0] = (len >> 24) as u8;
                buf[1] = (len >> 16) as u8;
                buf[2] = (len >> 8) as u8;
                buf[3] = len as u8;

                buf[4] = (crc >> 24) as u8;
                buf[5] = (crc >> 16) as u8;
                buf[6] = (crc >> 8) as u8;
                buf[7] = crc as u8;

                f.write_all(&buf).unwrap();
            }

            f.write_all(vec).unwrap();
            f.flush().unwrap();

            self.byte_pos_tail += (len as u64) + 8;
        }

        { // Update internal cache
            let height = block.height;
            self.height = height;
            let opt = self.blocks.insert(height, Arc::new(block));
            if self.blocks.len() > 100 {
                let b = self.blocks.remove(&(height - 100));
                debug_assert!(b.is_some(), "nothing removed from cache");
            }
            debug_assert!(opt.is_none(), "block already in the chain");
        }
    }
}
<|endoftext|>


<commit_before>
pub use core::task::Poll;

/// A macro for extracting the successful type of a `Poll<Result<T, E>>`.
///
/// This macro bakes in propagation of `Pending` and `Err` signals by returning early.
#[macro_export]
macro_rules! try_ready {
    ($x:expr) => {
        match $x {
            $crate::Poll::Ready(Ok(x)) => x,
            $crate::Poll::Ready(Err(e)) => return $crate::Poll::Ready(Err(e.into())),
            $crate::Poll::Pending => return $crate::Poll::Pending,
        }
    }
}

/// A macro for extracting `Poll<T>` from `Poll<Result<T, E>>`.
///
/// This macro bakes in propagation of `Err` signals by returning early.
/// This macro bakes in propagation of `Pending` and `Err` signals by returning early.
#[macro_export]
macro_rules! try_poll {
    ($x:expr) => {
        match $x {
            $crate::Poll::Ready(Ok(x)) => $crate::Poll::Ready(x),
            $crate::Poll::Ready(Err(e)) => return $crate::Poll::Ready(Err(e.into())),
            $crate::Poll::Pending => $crate::Poll::Pending,
        }
    }
}

/// A macro for extracting the successful type of a `Poll<T>`.
///
/// This macro bakes in propagation of `Pending` signals by returning early.
#[macro_export]
macro_rules! ready {
    ($e:expr) => (match $e {
        $crate::Poll::Ready(t) => t,
        $crate::Poll::Pending => return $crate::Poll::Pending,
    })
}

pub trait PollExt<T> {
    /// Change the ready value of this `Poll` with the closure provided
    fn map<U, F>(self, f: F) -> Poll<U>
        where F: FnOnce(T) -> U;
    /// Returns whether this is `Poll::Ready`
    fn is_ready(&self) -> bool;
    /// Returns whether this is `Poll::Pending`
    fn is_pending(&self) -> bool {
        !self.is_ready()
    }
}

impl<T> PollExt<T> for Poll<T> {

    fn map<U, F>(self, f: F) -> Poll<U>
        where F: FnOnce(T) -> U
    {
        match self {
            Poll::Ready(t) => Poll::Ready(f(t)),
            Poll::Pending => Poll::Pending,
        }
    }

    fn is_ready(&self) -> bool {
        match *self {
            Poll::Ready(_) => true,
            Poll::Pending => false,
        }
    }
}

pub trait PollResultExt<T, E> {
    /// Change the success value of this `Poll` with the closure provided
    fn map_ok<U, F>(self, f: F) -> Poll<Result<U, E>>
        where F: FnOnce(T) -> U;
    /// Change the error value of this `Poll` with the closure provided
    fn map_err<U, F>(self, f: F) -> Poll<Result<T, U>>
        where F: FnOnce(E) -> U;
}

impl<T, E> PollResultExt<T, E> for Poll<Result<T, E>> {

    fn map_ok<U, F>(self, f: F) -> Poll<Result<U, E>>
        where F: FnOnce(T) -> U
    {
        match self {
            Poll::Ready(Ok(t)) => Poll::Ready(Ok(f(t))),
            Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
            Poll::Pending => Poll::Pending,
        }
    }

    fn map_err<U, F>(self, f: F) -> Poll<Result<T, U>>
        where F: FnOnce(E) -> U
    {
        match self {
            Poll::Ready(Ok(t)) => Poll::Ready(Ok(t)),
            Poll::Ready(Err(e)) => Poll::Ready(Err(f(e))),
            Poll::Pending => Poll::Pending,
        }
    }
}

<commit_msg>remove PollExt, add methods to std<commit_after>
pub use core::task::Poll;

/// A macro for extracting the successful type of a `Poll<Result<T, E>>`.
///
/// This macro bakes in propagation of `Pending` and `Err` signals by returning early.
#[macro_export]
macro_rules! try_ready {
    ($x:expr) => {
        match $x {
            $crate::Poll::Ready(Ok(x)) => x,
            $crate::Poll::Ready(Err(e)) => return $crate::Poll::Ready(Err(e.into())),
            $crate::Poll::Pending => return $crate::Poll::Pending,
        }
    }
}

/// A macro for extracting `Poll<T>` from `Poll<Result<T, E>>`.
///
/// This macro bakes in propagation of `Err` signals by returning early.
/// This macro bakes in propagation of `Pending` and `Err` signals by returning early.
#[macro_export]
macro_rules! try_poll {
    ($x:expr) => {
        match $x {
            $crate::Poll::Ready(Ok(x)) => $crate::Poll::Ready(x),
            $crate::Poll::Ready(Err(e)) => return $crate::Poll::Ready(Err(e.into())),
            $crate::Poll::Pending => $crate::Poll::Pending,
        }
    }
}

/// A macro for extracting the successful type of a `Poll<T>`.
///
/// This macro bakes in propagation of `Pending` signals by returning early.
#[macro_export]
macro_rules! ready {
    ($e:expr) => (match $e {
        $crate::Poll::Ready(t) => t,
        $crate::Poll::Pending => return $crate::Poll::Pending,
    })
}
<|endoftext|>