RUST勉強中、1/17の積み上げ

サブスクリプション処理を実装していきます。

icedではサブスクリプションを利用することによって、非同期処理側からメッセージを送信する事ができるようです。

サブスクリプションを利用するにはレシピを作成しなければなりません。

pub struct Timer {
    duration: Duration,
}

impl Timer {
    fn new(duration: Duration) -> Timer {
        Timer { duration: duration }
    }
}

impl<H, E> iced_native::subscription::Recipe<H, E> for Timer
where
    H: std::hash::Hasher,
{
    type Output = Instant;

    fn hash(&self, state: &mut H) {
        use std::hash::Hash;
        std::any::TypeId::of::<Self>().hash(state);
        self.duration.hash(state);
    }

    fn stream(
        self: Box<Self>,
        _input: futures::stream::BoxStream<'static, E>,
    ) -> futures::stream::BoxStream<'static, Self::Output> {
        use futures::stream::StreamExt;
        async_std::stream::interval(self.duration)
            .map(|_| Instant::now())
            .boxed()
    }
}

もうここまで来たら何が何だか解りません。

後でRustの文法見直す。

サブスクリプション処理を作成し、Executorの設定を書き直せばメッセージ送信処理は完成です。

impl Application for GUI {
    type Executor = executor::Default;
    type Message = Message;
    type Flags = ();
    fn subscription(&self) -> Subscription<Message> {
        let timer = Timer::new(Duration::from_millis(MILLISEC / FPS));
        iced::Subscription::from_recipe(timer).map(|_| Message::Update)
    }

あとは受信側を作成。

コードはこうなりました。

use iced::{
    button, executor, Align, Application, Button, Column, Command, Element, Font,
    HorizontalAlignment, Length, Row, Settings, Subscription, Text,
};
use iced_futures::{self, futures};
use std::time::{Duration, Instant};

const FONT: Font = Font::External {
    name: "PixelMplus12-Regular",
    bytes: include_bytes!("../rsc/PixelMplus12-Regular.ttf"),
};

const FPS: u64 = 30;
const MILLISEC: u64 = 1000;
const MINUTE: u64 = 60;
const HOUR: u64 = 60 * MINUTE;

#[derive(Debug, Clone)]
pub enum Message {
    Start,
    Stop,
    Reset,
    Update,
}

pub enum TickState {
    Stopped,
    Ticking,
}

pub struct Timer {
    duration: Duration,
}

impl Timer {
    fn new(duration: Duration) -> Timer {
        Timer { duration: duration }
    }
}

impl<H, E> iced_native::subscription::Recipe<H, E> for Timer
where
    H: std::hash::Hasher,
{
    type Output = Instant;

    fn hash(&self, state: &mut H) {
        use std::hash::Hash;
        std::any::TypeId::of::<Self>().hash(state);
        self.duration.hash(state);
    }

    fn stream(
        self: Box<Self>,
        _input: futures::stream::BoxStream<'static, E>,
    ) -> futures::stream::BoxStream<'static, Self::Output> {
        use futures::stream::StreamExt;
        async_std::stream::interval(self.duration)
            .map(|_| Instant::now())
            .boxed()
    }
}

struct GUI {
    last_update: Instant,
    total_duration: Duration,
    tick_state: TickState,
    start_stop_button_state: button::State,
    reset_button_state: button::State,
}

impl Application for GUI {
    type Executor = executor::Default;
    type Message = Message;
    type Flags = ();

    fn new(_flags: ()) -> (GUI, Command<Self::Message>) {
        (
            GUI {
                last_update: Instant::now(),
                total_duration: Duration::default(),
                tick_state: TickState::Stopped,
                start_stop_button_state: button::State::new(),
                reset_button_state: button::State::new(),
            },
            Command::none(),
        )
    }

    fn title(&self) -> String {
        String::from("DEMO")
    }

    fn update(&mut self, message: Self::Message) -> Command<Self::Message> {
        match message {
            Message::Start => {
                self.tick_state = TickState::Ticking;
                self.last_update = Instant::now();
            }
            Message::Stop => {
                self.tick_state = TickState::Stopped;
                self.last_update += Instant::now() - self.last_update;
            }
            Message::Reset => {
                self.last_update = Instant::now();
                self.total_duration = Duration::default();
            }
            Message::Update => match self.tick_state {
                TickState::Ticking => {
                    let now_update = Instant::now();
                    self.total_duration += now_update - self.last_update;
                    self.last_update = now_update;
                }
                _ => {}
            },
        }
        Command::none()
    }

    fn view(&mut self) -> Element<Self::Message> {
        let seconds = self.total_duration.as_secs();
        let duration_text = format!(
            "{:0>2}:{:0>2}:{:0>2}.{:0>2}",
            seconds / HOUR,
            (seconds % HOUR) / MINUTE,
            seconds % MINUTE,
            self.total_duration.subsec_millis() / 10,
        );

        let start_stop_text = match self.tick_state {
            TickState::Stopped => Text::new("Start")
                .horizontal_alignment(HorizontalAlignment::Center)
                .font(FONT),
            TickState::Ticking => Text::new("Stop")
                .horizontal_alignment(HorizontalAlignment::Center)
                .font(FONT),
        };

        let start_stop_message = match self.tick_state {
            TickState::Stopped => Message::Start,
            TickState::Ticking => Message::Stop,
        };
        
        let tick_text = Text::new(duration_text).font(FONT).size(60);
        let start_stop_button = Button::new(&mut self.start_stop_button_state, start_stop_text)
            .min_width(80)
            .on_press(start_stop_message);
        let reset_button = Button::new(
            &mut self.reset_button_state,
            Text::new("Reset")
                .horizontal_alignment(HorizontalAlignment::Center)
                .font(FONT),
        )
            .min_width(80)
            .on_press(Message::Reset);

        Column::new()
            .push(tick_text)
            .push(
                Row::new()
                    .push(start_stop_button)
                    .push(reset_button)
                    .spacing(10),
            )
            .spacing(10)
            .padding(10)
            .width(Length::Fill)
            .height(Length::Fill)
            .align_items(Align::Center)
            .into()
    }

    fn subscription(&self) -> Subscription<Message> {
        let timer = Timer::new(Duration::from_millis(MILLISEC / FPS));
        iced::Subscription::from_recipe(timer).map(|_| Message::Update)
    }
}

fn main() {
    let mut settings = Settings::default();
    settings.window.size = (400u32, 120u32);
    GUI::run(settings);
}

経済ニュース(01/17)

百貨店「つぶれる街」「生き残る街」の決定的な差 – 東洋経済オンライン

昨年、百貨店「そごう・西武」が、不動産投資ファンドに売却されることが決定し、これから各地の店舗がどうなるのかが話題となっている。旗艦店である西武池袋本店は、ファンドのパートナーとされるヨドバシカメラ…

「亡母から相続した実家、名義変更したいが…」あまりに煩瑣な手続きに驚愕【公認会計士が解説】 – 幻冬舎ゴールドオンライン

不動産を相続する場合、所有権の移転のために、不動産の登記の名義変更が必要です。これを「相続登記」といいます。また、2024年4月より相続登記が義務化され、相続人は相続を知った日から3年以内に相続登記をしなければならなくなりました。自身もFP資格を持つ、公認会計士・税理士の岸田康雄氏が解説します。

日銀 きょうから金融政策決定会合 金利上昇圧力高まり対応焦点 – nhk.or.jp

日銀は、17日から2日間開く金融政策決定会合で、金融政策の方向性や物価の見通しなどについて議論します。日銀が先月に続いて…

ダボス会議の現場からライブ配信~分断の世界でエリートたちは何を議論するのか~【豊島晋作のテレ東ワールドポリティクス】 – テレ東BIZ

1月16日(月)にスイスのリゾート地ダボスで開幕する世界経済フォーラムの年次総会、通称「ダボス会議」の現場を歩きながら、豊島晋作がライブ解説。コロナの影響もあり、例年通り冬に対面形式で開催されるのは3年ぶりで、今年は50人以上の政府首脳、600人を超える企業経営者が参加するなど、来場者の数は過去最大規模が見込まれ…

【解説】「スマホ認知症」増加? 絶えず膨大な情報「脳過労」に… 5分でも“ぼんやり”時間を – 日テレNEWS

スマートフォンの使いすぎで脳の働きが低下する「スマホ認知症」。専門家は「スマホ認知症の患者が増えている」と警鐘を鳴らしています。●スマホ依存をチェック●脳が“ごみ屋敷”に●多い年代と対策以上のポイントを中心に詳しく解説します。■「簡単な計算さえできなく…」スマホ認知症とは スマホ依存…14項目のチェックリスト「ス…

新型スズキ・ジムニー5ドアは期待しかない! 今、注目すべき理由とは? – GQ JAPAN

突如、インドで発表されたスズキの新型「ジムニー5ドア」。現行の3ドア仕様を所有するモータージャーナリストの河西啓介が5ドアの魅力を考えた!

「銀行株も息切れ感」 日銀を警戒、総裁人事まで波乱も – 日本経済新聞

17~18日の日銀の金融政策決定会合を前に日本株の出遅れが目立ってきた。国内の債券市場で金融緩和の機能不全が浮き彫りになり、日銀が政策修正に動く可能性を排除できないからだ。マクロ経済の動向に賭ける一部の海外勢は株売りに動いている。マネーは消去法で銀行株に集まるが、受け皿として限界もある。新しい総裁・副総裁人事が決まるまでは波乱含みだ。「買える銘柄は銀行株くらいしかなかったが、それさえも利益確定

母は無年金だと思い、生前、請求しませんでした。遺族がもらえる年金はありますか? – Yahoo!ファイナンス

老後のお金や生活費が足りるのか不安ですよね。老後生活の収入の柱になるのが「老齢年金」ですが、年金制度にまつわることは、難しい用語が多くて、ますます不安になってしまう人もいるのではないでしょうか。そんな年金初心者の方の疑問に、専門家が回答します。今回は、年金の請求をしなかった遺族が…

「読売ジャイアンツ公式サイト」をリニューアル | 読売ジャイアンツ公式サイト – giants.jp

埼玉りそな銀行、浦和レッズ元選手のラーメン店に融資 – 日本経済新聞

埼玉りそな銀行は16日、サッカーJ1の浦和レッズなどに在籍していた元選手のラーメン店開業資金として1000万円を、起業などを支援する融資商品「埼玉りそな創業応援ファンド(ローン)」を通じて融資したと発表した。2022年に創業支援で連携を強化した日本政策金融公庫も1000万円を協調融資し、融資額は計2000万円になる。今回の融資は同ファンドの第1号案件。2018年にサッカー選手を引退し

長期金利が一時0.51%まで上昇 2営業日連続で上限突破 国債に大量の売り注文「今の利回りで売っておけば…」|TBS NEWS DIG – TBS NEWS DIG Powered by JNN

物価の上昇が止まりません。去年12月の企業物価指数は、前の年と比べて10.2%の上昇で、水準は9か月連続で過去最高を更新しました。日銀が発表した企業の間の商品の取り引き価格を示す先月の企業物価指数は、2020年の平均を100とした水準で119.5で、比較できる1980年以降の過去最高を9か月連続で更新。上昇率も前…

マック、8割の品目で値上げ ドミノが“新商品”見た目はピザ…食べるとバーガー?(2023年1月16日) – ANNnewsCH

日本マクドナルドは、ハンバーガー類やドリンク類などを16日から値上げしました。 物価高が相次ぐなか、ハンバーガーは150円から170円に。ビッグマックは410円から450円に。その他にもサイドメニューやドリンクなど、対象は全メニューのおよそ8割に及びます。 この1年で3度目となる値上げに街の人は。 街の人:「もう…

新型プリウスが「HVの始祖」の次に追い求めた価値観と性能 – BestCarWeb

2022年11月に世界初公開された、トヨタ新型「プリウス」。プリウスといえば「ハイブリッド車の始祖」だが、昨今はどのモデルにもHVがラインアップされ、その存在価値は薄くなってきている。はたして、プリウスが次に追い求めた価値観と性能とは!??

全国旅行支援に「独自上乗せ」している20都府県がおトク! 地域クーポン増額/交通費還元など – トラベル Watch

1月10日に全国旅行支援が再開し、各都道府県では訪れた旅行者へ一律20%(交通付旅行商品は1泊につき上限5000円/それ以外は上限3000円)の割引と、お土産の購入などに利用できる地域クーポン(平日1泊2000円分/休日1泊1000円分)の配布を実施している。

NTTドコモ、通信障害の事故報告書を総務省に提出 延べ約311万人に影響 (2023年1月16日掲載) – livedoor

NTTドコモは16日、2022年12月に起こした通信障害について、電気通信事業法に基づく事故報告書を総務省に提出した。西日本の一部でデータ通信が使いづらくなり、延べ約311万人に影響した。総務省は報告書の内容を精

三井住友銀、ベトナムのエグジムバンク全保有株売却へ 資本提携を解消 – ロイター (Reuters Japan)

三井住友銀行は16日、ベトナム・エクスポート・インポート・コマーシャル・ジョイント・ストック・バンク(エグジムバンク)との資本提携解消し、株式売却を開始したと発表した。今後、全株を売却する予定。