Skip to main content

Menu

Struct Menu 

Source
pub struct Menu {
    pub items: Vec<Item>,
}
Expand description

A declarative menu: an ordered list of Items. Build it with the fluent methods, or populate Menu::items directly.

Fields§

§items: Vec<Item>

The ordered items.

Implementations§

Source§

impl Menu

Source

pub fn new() -> Self

An empty menu.

Examples found in repository?
examples/demo_tray.rs (line 40)
39fn account_submenu(slug: &str) -> Menu {
40    Menu::new()
41        .row(Row::default().segments(vec![
42            Segment::new("Session resets in").flex(Flex::Grow),
43            Segment::new("3h 12m")
44                .align(Align::Right)
45                .color(Color::SecondaryLabel),
46        ]))
47        .row(Row::default().segments(vec![
48            Segment::new("Weekly resets in").flex(Flex::Grow),
49            Segment::new("2d 4h")
50                .align(Align::Right)
51                .color(Color::SecondaryLabel),
52        ]))
53        .row(Row::default().segment(Segment::new("updated 1m ago").color(Color::SecondaryLabel)))
54        .separator()
55        .row(Row::new(format!("switch:{slug}")).label("Switch to this account"))
56        .row(Row::new(format!("launch:{slug}")).label("Launch client"))
57        .row(Row::new(format!("remove:{slug}")).label("Remove…"))
58}
59
60fn demo_menu() -> Menu {
61    let claude_logo = swatch_png(217, 119, 87);
62    let codex_logo = swatch_png(80, 80, 90);
63
64    Menu::new()
65        .section_header(
66            Row::default()
67                .leading(Icon::from_png(claude_logo))
68                .segment(Segment::new("Claude").font(Font::system(13.0, Weight::Bold))),
69        )
70        .submenu(
71            Row::new("acct:claude:me")
72                .leading(Icon::Checkmark)
73                .checked(true)
74                .segments(vec![
75                    Segment::new("me@example.com")
76                        .flex(Flex::Grow)
77                        .font(Font::system(13.0, Weight::Bold)),
78                    Segment::new("47% / 89%")
79                        .align(Align::Right)
80                        .runs(vec![StyleRun::new(6, 3, Color::SystemRed)]),
81                ]),
82            account_submenu("claude:me"),
83        )
84        .submenu(
85            Row::new("acct:claude:work").segments(vec![
86                Segment::new("work@example.com").flex(Flex::Grow),
87                Segment::new("12% / 30%")
88                    .align(Align::Right)
89                    .runs(vec![StyleRun::new(0, 3, Color::SystemGreen)]),
90            ]),
91            account_submenu("claude:work"),
92        )
93        .separator()
94        .section_header(
95            Row::default()
96                .leading(Icon::from_png(codex_logo))
97                .segment(Segment::new("Codex").font(Font::system(13.0, Weight::Bold))),
98        )
99        .row(Row::new("switch:codex:me").segments(vec![
100            Segment::new("me@example.com").flex(Flex::Grow),
101            Segment::new("3h 12m")
102                .align(Align::Right)
103                .runs(vec![StyleRun::new(0, 6, Color::SystemOrange)]),
104        ]))
105        .separator()
106        .submenu(
107            Row::new("settings").label("Settings"),
108            Menu::new()
109                .row(Row::new("settings:apikey").label("API key…"))
110                .row(Row::new("settings:autoswap").label("Auto-swap accounts"))
111                .separator()
112                .row(Row::new("settings:notifications").label("Notifications…")),
113        )
114        .row(Row::new("quit").segments(vec![
115            Segment::new("Quit").flex(Flex::Grow),
116            Segment::new(concat!("usagio v", env!("CARGO_PKG_VERSION")))
117                .align(Align::Right)
118                .color(Color::SecondaryLabel),
119        ]))
120}
More examples
Hide additional examples
examples/usagio_menu.rs (line 57)
56fn account_submenu(acct: &Account) -> Menu {
57    let mut menu = Menu::new()
58        // Info rows read as normal text but are non-interactive (id = none).
59        .row(Row::label_only("Session resets in 2h 41m"))
60        .row(Row::label_only("Weekly resets in 3d 4h"))
61        .row(Row::default().segment(Segment::new("updated 12s ago").color(Color::SecondaryLabel)))
62        .separator();
63
64    if acct.active {
65        menu = menu.row(
66            Row::new("noop")
67                .leading(Icon::Checkmark)
68                .segment(Segment::new("Active").color(Color::SystemGreen))
69                .enabled(false),
70        );
71    } else {
72        menu = menu.row(
73            Row::new(format!("switch:{}:{}", acct.provider, acct.key))
74                .label("Switch to this account"),
75        );
76    }
77    if acct.supports_launch {
78        menu = menu.row(
79            Row::new(format!("launch:{}:{}", acct.provider, acct.key))
80                .label("Launch client")
81                // A named symbol trails the action (SF Symbol on macOS).
82                .trailing(Icon::Symbol("arrow.up.forward.app")),
83        );
84    }
85    if acct.supports_remove {
86        menu = menu.row(
87            Row::new(format!("remove:{}:{}", acct.provider, acct.key)).label("Remove\u{2026}"),
88        );
89    }
90    menu
91}
92
93/// The Capture submenu: one entry per provider to capture the current login.
94fn capture_submenu(groups: &[Group]) -> Menu {
95    let mut menu = Menu::new();
96    for group in groups {
97        menu = menu.row(
98            Row::new(format!("capture:{}", group.display_name.to_lowercase()))
99                .leading(Icon::from_png(group.icon_png))
100                .label(format!("Capture {} login", group.display_name)),
101        );
102    }
103    menu
104}
105
106/// The Settings submenu: a checkable toggle, an auto-swap threshold flyout, and
107/// a backup flyout — exercising nested submenus, `checked`, and an SVG icon.
108fn settings_submenu() -> Menu {
109    let autoswap = Menu::new()
110        .row(Row::new("autoswap:off").checked(false).label("Off"))
111        .row(Row::new("autoswap:80").checked(false).label("At 80%"))
112        .row(Row::new("autoswap:90").checked(true).label("At 90%"))
113        .separator()
114        .row(Row::new("autoswap:now").label("Swap now"));
115
116    let backup = Menu::new()
117        .row(Row::new("backup:save").label("Save backup\u{2026}"))
118        .row(Row::new("backup:restore").label("Restore backup\u{2026}"));
119
120    Menu::new()
121        .row(
122            Row::new("notifications:limits")
123                .checked(true)
124                .label("Notify near limits"),
125        )
126        .submenu(Row::new("autoswap").label("Auto-swap threshold"), autoswap)
127        .submenu(
128            Row::new("backup")
129                // An SVG leading icon, rasterized per-DPI at draw time.
130                .leading(Icon::from_svg(
131                    br#"<svg xmlns="http://www.w3.org/2000/svg"/>"#.as_slice(),
132                ))
133                .label("Backup"),
134            backup,
135        )
136        .separator()
137        .row(Row::new("refresh:now").label("Refresh now"))
138}
139
140fn build(groups: &[Group]) -> Menu {
141    let mut menu = Menu::new();
142
143    for group in groups {
144        // Bold, logo'd, non-interactive group header (Claude, then Codex).
145        menu = menu.section_header(
146            Row::default()
147                .leading(Icon::from_png(group.icon_png))
148                .segment(Segment::new(group.display_name).font(Font::system(13.0, Weight::Bold))),
149        );
150
151        for acct in &group.accounts {
152            // The label Grows to eat the leftover width, so the value segment
153            // sits flush at the true right edge — no reserved chevron column.
154            let label = Segment::new(acct.display)
155                .flex(Flex::Grow)
156                .font(if acct.active {
157                    Font::system(13.0, Weight::Bold)
158                } else {
159                    Font::system(13.0, Weight::Regular)
160                });
161
162            let value = Segment::new(acct.trailing)
163                .align(Align::Right)
164                .runs(severity_runs(&acct.severity));
165
166            let mut label_row = Row::new(format!("switch:{}:{}", acct.provider, acct.key))
167                .segments(vec![label, value])
168                .checked(acct.active);
169            if acct.active {
170                label_row = label_row.leading(Icon::Checkmark);
171            }
172
173            menu = menu.submenu(label_row, account_submenu(acct));
174        }
175
176        menu = menu.separator();
177    }
178
179    // Bottom actions — now with populated submenus.
180    menu = menu
181        .submenu(
182            Row::new("capture").label("Capture current login"),
183            capture_submenu(groups),
184        )
185        .submenu(Row::new("settings").label("Settings"), settings_submenu());
186
187    // "Quit ........ usagio vX" — label Grows, version tail is greyed + flush-right.
188    menu = menu.row(Row::new("quit").segments(vec![
189        Segment::new("Quit").flex(Flex::Grow),
190        Segment::new(format!("usagio v{}", env!("CARGO_PKG_VERSION")))
191            .align(Align::Right)
192            .color(Color::SecondaryLabel),
193    ]));
194
195    menu
196}
197
198fn icon_tag(icon: &Option<Icon>) -> &'static str {
199    match icon {
200        None => "",
201        Some(Icon::Checkmark) => " [check]",
202        Some(Icon::Png(_)) => " [png]",
203        Some(Icon::Svg(_)) => " [svg]",
204        Some(Icon::Symbol(_)) => " [symbol]",
205    }
206}
207
208fn print_row(row: &Row, prefix: &str, pad: &str) {
209    let check = match row.checked {
210        Some(true) => "[x] ",
211        Some(false) => "[ ] ",
212        None => "",
213    };
214    let dim = if row.enabled { "" } else { " (disabled)" };
215    println!(
216        "{pad}{prefix}{}{check}{}{}{}  [{}]",
217        icon_tag(&row.leading),
218        row_text(row),
219        icon_tag(&row.trailing),
220        dim,
221        row.id.as_str(),
222    );
223}
224
225fn print_menu(menu: &Menu, depth: usize) {
226    let pad = "  ".repeat(depth);
227    for item in &menu.items {
228        match item {
229            Item::Separator => println!("{pad}----"),
230            Item::SectionHeader(row) => {
231                println!("{pad}#{} {}", icon_tag(&row.leading), row_text(row))
232            }
233            Item::Row(row) => print_row(row, "- ", &pad),
234            Item::Submenu { label, menu } => {
235                print_row(label, "> ", &pad);
236                print_menu(menu, depth + 1);
237            }
238            // A rich content row (#44) is a display-only layout stack, not a
239            // labelled row; this text dump just marks its presence.
240            Item::Content(_) => println!("{pad}[content]"),
241        }
242    }
243}
244
245fn row_text(row: &Row) -> String {
246    row.segments
247        .iter()
248        .map(|s| s.text.as_str())
249        .collect::<Vec<_>>()
250        .join("  ")
251}
252
253fn demo_theme_resolution() {
254    // A consumer can resolve semantic colors against any theme with no GUI.
255    let dark = Theme::dark();
256    let label = dark.resolve(Color::Label);
257    let red = dark.resolve(Color::SystemRed);
258    println!(
259        "theme resolution (dark): Label -> rgba({},{},{},{}), SystemRed -> rgba({},{},{},{})",
260        label.r, label.g, label.b, label.a, red.r, red.g, red.b, red.a,
261    );
262}
263
264fn demo_flush_right_layout() {
265    // The "Quit ...... usagio v1" row: a Grow label + a Fixed, right-aligned
266    // version tail. Given measured intrinsic widths, the layout engine flushes
267    // the tail to the right edge with no reserved column.
268    let content_width = 220.0;
269    let segs = [
270        SegmentMetrics::new(30.0, Flex::Grow, Align::Left), // "Quit"
271        SegmentMetrics::new(60.0, Flex::Fixed, Align::Right), // "usagio v1"
272    ];
273    let boxes = resolve_segments(&segs, content_width);
274    println!(
275        "flush-right layout: content {content_width}px -> tail text starts at x={} (right edge {})",
276        boxes[1].text_x,
277        content_width - 60.0,
278    );
279}
280
281fn demo_context_menu() {
282    // The pointer-anchored primitive that also works on Linux.
283    let menu = Menu::new()
284        .row(Row::new("copy").label("Copy"))
285        .row(Row::new("paste").label("Paste"))
286        .separator()
287        .row(Row::new("select-all").label("Select All"));
288    let cm = ContextMenu::new(menu).on_click(|id| println!("context click: {}", id.as_str()));
289    // Exercise the dispatch path without a GUI.
290    cm.dispatch(&"copy".into());
291    println!("context menu has {} items", cm.menu().len());
292}
Source

pub fn item(self, item: Item) -> Self

Append any Item (the escape hatch). Prefer the labeled builder methods — row, separator, section_header, submenu, content — which are the canonical, one-obvious-way path (issue #62); reach for item only to append a hand-built Item.

Source

pub fn row(self, row: Row) -> Self

Append an Item::Row.

Examples found in repository?
examples/demo_tray.rs (lines 41-46)
39fn account_submenu(slug: &str) -> Menu {
40    Menu::new()
41        .row(Row::default().segments(vec![
42            Segment::new("Session resets in").flex(Flex::Grow),
43            Segment::new("3h 12m")
44                .align(Align::Right)
45                .color(Color::SecondaryLabel),
46        ]))
47        .row(Row::default().segments(vec![
48            Segment::new("Weekly resets in").flex(Flex::Grow),
49            Segment::new("2d 4h")
50                .align(Align::Right)
51                .color(Color::SecondaryLabel),
52        ]))
53        .row(Row::default().segment(Segment::new("updated 1m ago").color(Color::SecondaryLabel)))
54        .separator()
55        .row(Row::new(format!("switch:{slug}")).label("Switch to this account"))
56        .row(Row::new(format!("launch:{slug}")).label("Launch client"))
57        .row(Row::new(format!("remove:{slug}")).label("Remove…"))
58}
59
60fn demo_menu() -> Menu {
61    let claude_logo = swatch_png(217, 119, 87);
62    let codex_logo = swatch_png(80, 80, 90);
63
64    Menu::new()
65        .section_header(
66            Row::default()
67                .leading(Icon::from_png(claude_logo))
68                .segment(Segment::new("Claude").font(Font::system(13.0, Weight::Bold))),
69        )
70        .submenu(
71            Row::new("acct:claude:me")
72                .leading(Icon::Checkmark)
73                .checked(true)
74                .segments(vec![
75                    Segment::new("me@example.com")
76                        .flex(Flex::Grow)
77                        .font(Font::system(13.0, Weight::Bold)),
78                    Segment::new("47% / 89%")
79                        .align(Align::Right)
80                        .runs(vec![StyleRun::new(6, 3, Color::SystemRed)]),
81                ]),
82            account_submenu("claude:me"),
83        )
84        .submenu(
85            Row::new("acct:claude:work").segments(vec![
86                Segment::new("work@example.com").flex(Flex::Grow),
87                Segment::new("12% / 30%")
88                    .align(Align::Right)
89                    .runs(vec![StyleRun::new(0, 3, Color::SystemGreen)]),
90            ]),
91            account_submenu("claude:work"),
92        )
93        .separator()
94        .section_header(
95            Row::default()
96                .leading(Icon::from_png(codex_logo))
97                .segment(Segment::new("Codex").font(Font::system(13.0, Weight::Bold))),
98        )
99        .row(Row::new("switch:codex:me").segments(vec![
100            Segment::new("me@example.com").flex(Flex::Grow),
101            Segment::new("3h 12m")
102                .align(Align::Right)
103                .runs(vec![StyleRun::new(0, 6, Color::SystemOrange)]),
104        ]))
105        .separator()
106        .submenu(
107            Row::new("settings").label("Settings"),
108            Menu::new()
109                .row(Row::new("settings:apikey").label("API key…"))
110                .row(Row::new("settings:autoswap").label("Auto-swap accounts"))
111                .separator()
112                .row(Row::new("settings:notifications").label("Notifications…")),
113        )
114        .row(Row::new("quit").segments(vec![
115            Segment::new("Quit").flex(Flex::Grow),
116            Segment::new(concat!("usagio v", env!("CARGO_PKG_VERSION")))
117                .align(Align::Right)
118                .color(Color::SecondaryLabel),
119        ]))
120}
More examples
Hide additional examples
examples/usagio_menu.rs (line 59)
56fn account_submenu(acct: &Account) -> Menu {
57    let mut menu = Menu::new()
58        // Info rows read as normal text but are non-interactive (id = none).
59        .row(Row::label_only("Session resets in 2h 41m"))
60        .row(Row::label_only("Weekly resets in 3d 4h"))
61        .row(Row::default().segment(Segment::new("updated 12s ago").color(Color::SecondaryLabel)))
62        .separator();
63
64    if acct.active {
65        menu = menu.row(
66            Row::new("noop")
67                .leading(Icon::Checkmark)
68                .segment(Segment::new("Active").color(Color::SystemGreen))
69                .enabled(false),
70        );
71    } else {
72        menu = menu.row(
73            Row::new(format!("switch:{}:{}", acct.provider, acct.key))
74                .label("Switch to this account"),
75        );
76    }
77    if acct.supports_launch {
78        menu = menu.row(
79            Row::new(format!("launch:{}:{}", acct.provider, acct.key))
80                .label("Launch client")
81                // A named symbol trails the action (SF Symbol on macOS).
82                .trailing(Icon::Symbol("arrow.up.forward.app")),
83        );
84    }
85    if acct.supports_remove {
86        menu = menu.row(
87            Row::new(format!("remove:{}:{}", acct.provider, acct.key)).label("Remove\u{2026}"),
88        );
89    }
90    menu
91}
92
93/// The Capture submenu: one entry per provider to capture the current login.
94fn capture_submenu(groups: &[Group]) -> Menu {
95    let mut menu = Menu::new();
96    for group in groups {
97        menu = menu.row(
98            Row::new(format!("capture:{}", group.display_name.to_lowercase()))
99                .leading(Icon::from_png(group.icon_png))
100                .label(format!("Capture {} login", group.display_name)),
101        );
102    }
103    menu
104}
105
106/// The Settings submenu: a checkable toggle, an auto-swap threshold flyout, and
107/// a backup flyout — exercising nested submenus, `checked`, and an SVG icon.
108fn settings_submenu() -> Menu {
109    let autoswap = Menu::new()
110        .row(Row::new("autoswap:off").checked(false).label("Off"))
111        .row(Row::new("autoswap:80").checked(false).label("At 80%"))
112        .row(Row::new("autoswap:90").checked(true).label("At 90%"))
113        .separator()
114        .row(Row::new("autoswap:now").label("Swap now"));
115
116    let backup = Menu::new()
117        .row(Row::new("backup:save").label("Save backup\u{2026}"))
118        .row(Row::new("backup:restore").label("Restore backup\u{2026}"));
119
120    Menu::new()
121        .row(
122            Row::new("notifications:limits")
123                .checked(true)
124                .label("Notify near limits"),
125        )
126        .submenu(Row::new("autoswap").label("Auto-swap threshold"), autoswap)
127        .submenu(
128            Row::new("backup")
129                // An SVG leading icon, rasterized per-DPI at draw time.
130                .leading(Icon::from_svg(
131                    br#"<svg xmlns="http://www.w3.org/2000/svg"/>"#.as_slice(),
132                ))
133                .label("Backup"),
134            backup,
135        )
136        .separator()
137        .row(Row::new("refresh:now").label("Refresh now"))
138}
139
140fn build(groups: &[Group]) -> Menu {
141    let mut menu = Menu::new();
142
143    for group in groups {
144        // Bold, logo'd, non-interactive group header (Claude, then Codex).
145        menu = menu.section_header(
146            Row::default()
147                .leading(Icon::from_png(group.icon_png))
148                .segment(Segment::new(group.display_name).font(Font::system(13.0, Weight::Bold))),
149        );
150
151        for acct in &group.accounts {
152            // The label Grows to eat the leftover width, so the value segment
153            // sits flush at the true right edge — no reserved chevron column.
154            let label = Segment::new(acct.display)
155                .flex(Flex::Grow)
156                .font(if acct.active {
157                    Font::system(13.0, Weight::Bold)
158                } else {
159                    Font::system(13.0, Weight::Regular)
160                });
161
162            let value = Segment::new(acct.trailing)
163                .align(Align::Right)
164                .runs(severity_runs(&acct.severity));
165
166            let mut label_row = Row::new(format!("switch:{}:{}", acct.provider, acct.key))
167                .segments(vec![label, value])
168                .checked(acct.active);
169            if acct.active {
170                label_row = label_row.leading(Icon::Checkmark);
171            }
172
173            menu = menu.submenu(label_row, account_submenu(acct));
174        }
175
176        menu = menu.separator();
177    }
178
179    // Bottom actions — now with populated submenus.
180    menu = menu
181        .submenu(
182            Row::new("capture").label("Capture current login"),
183            capture_submenu(groups),
184        )
185        .submenu(Row::new("settings").label("Settings"), settings_submenu());
186
187    // "Quit ........ usagio vX" — label Grows, version tail is greyed + flush-right.
188    menu = menu.row(Row::new("quit").segments(vec![
189        Segment::new("Quit").flex(Flex::Grow),
190        Segment::new(format!("usagio v{}", env!("CARGO_PKG_VERSION")))
191            .align(Align::Right)
192            .color(Color::SecondaryLabel),
193    ]));
194
195    menu
196}
197
198fn icon_tag(icon: &Option<Icon>) -> &'static str {
199    match icon {
200        None => "",
201        Some(Icon::Checkmark) => " [check]",
202        Some(Icon::Png(_)) => " [png]",
203        Some(Icon::Svg(_)) => " [svg]",
204        Some(Icon::Symbol(_)) => " [symbol]",
205    }
206}
207
208fn print_row(row: &Row, prefix: &str, pad: &str) {
209    let check = match row.checked {
210        Some(true) => "[x] ",
211        Some(false) => "[ ] ",
212        None => "",
213    };
214    let dim = if row.enabled { "" } else { " (disabled)" };
215    println!(
216        "{pad}{prefix}{}{check}{}{}{}  [{}]",
217        icon_tag(&row.leading),
218        row_text(row),
219        icon_tag(&row.trailing),
220        dim,
221        row.id.as_str(),
222    );
223}
224
225fn print_menu(menu: &Menu, depth: usize) {
226    let pad = "  ".repeat(depth);
227    for item in &menu.items {
228        match item {
229            Item::Separator => println!("{pad}----"),
230            Item::SectionHeader(row) => {
231                println!("{pad}#{} {}", icon_tag(&row.leading), row_text(row))
232            }
233            Item::Row(row) => print_row(row, "- ", &pad),
234            Item::Submenu { label, menu } => {
235                print_row(label, "> ", &pad);
236                print_menu(menu, depth + 1);
237            }
238            // A rich content row (#44) is a display-only layout stack, not a
239            // labelled row; this text dump just marks its presence.
240            Item::Content(_) => println!("{pad}[content]"),
241        }
242    }
243}
244
245fn row_text(row: &Row) -> String {
246    row.segments
247        .iter()
248        .map(|s| s.text.as_str())
249        .collect::<Vec<_>>()
250        .join("  ")
251}
252
253fn demo_theme_resolution() {
254    // A consumer can resolve semantic colors against any theme with no GUI.
255    let dark = Theme::dark();
256    let label = dark.resolve(Color::Label);
257    let red = dark.resolve(Color::SystemRed);
258    println!(
259        "theme resolution (dark): Label -> rgba({},{},{},{}), SystemRed -> rgba({},{},{},{})",
260        label.r, label.g, label.b, label.a, red.r, red.g, red.b, red.a,
261    );
262}
263
264fn demo_flush_right_layout() {
265    // The "Quit ...... usagio v1" row: a Grow label + a Fixed, right-aligned
266    // version tail. Given measured intrinsic widths, the layout engine flushes
267    // the tail to the right edge with no reserved column.
268    let content_width = 220.0;
269    let segs = [
270        SegmentMetrics::new(30.0, Flex::Grow, Align::Left), // "Quit"
271        SegmentMetrics::new(60.0, Flex::Fixed, Align::Right), // "usagio v1"
272    ];
273    let boxes = resolve_segments(&segs, content_width);
274    println!(
275        "flush-right layout: content {content_width}px -> tail text starts at x={} (right edge {})",
276        boxes[1].text_x,
277        content_width - 60.0,
278    );
279}
280
281fn demo_context_menu() {
282    // The pointer-anchored primitive that also works on Linux.
283    let menu = Menu::new()
284        .row(Row::new("copy").label("Copy"))
285        .row(Row::new("paste").label("Paste"))
286        .separator()
287        .row(Row::new("select-all").label("Select All"));
288    let cm = ContextMenu::new(menu).on_click(|id| println!("context click: {}", id.as_str()));
289    // Exercise the dispatch path without a GUI.
290    cm.dispatch(&"copy".into());
291    println!("context menu has {} items", cm.menu().len());
292}
Source

pub fn separator(self) -> Self

Append an Item::Separator.

Examples found in repository?
examples/demo_tray.rs (line 54)
39fn account_submenu(slug: &str) -> Menu {
40    Menu::new()
41        .row(Row::default().segments(vec![
42            Segment::new("Session resets in").flex(Flex::Grow),
43            Segment::new("3h 12m")
44                .align(Align::Right)
45                .color(Color::SecondaryLabel),
46        ]))
47        .row(Row::default().segments(vec![
48            Segment::new("Weekly resets in").flex(Flex::Grow),
49            Segment::new("2d 4h")
50                .align(Align::Right)
51                .color(Color::SecondaryLabel),
52        ]))
53        .row(Row::default().segment(Segment::new("updated 1m ago").color(Color::SecondaryLabel)))
54        .separator()
55        .row(Row::new(format!("switch:{slug}")).label("Switch to this account"))
56        .row(Row::new(format!("launch:{slug}")).label("Launch client"))
57        .row(Row::new(format!("remove:{slug}")).label("Remove…"))
58}
59
60fn demo_menu() -> Menu {
61    let claude_logo = swatch_png(217, 119, 87);
62    let codex_logo = swatch_png(80, 80, 90);
63
64    Menu::new()
65        .section_header(
66            Row::default()
67                .leading(Icon::from_png(claude_logo))
68                .segment(Segment::new("Claude").font(Font::system(13.0, Weight::Bold))),
69        )
70        .submenu(
71            Row::new("acct:claude:me")
72                .leading(Icon::Checkmark)
73                .checked(true)
74                .segments(vec![
75                    Segment::new("me@example.com")
76                        .flex(Flex::Grow)
77                        .font(Font::system(13.0, Weight::Bold)),
78                    Segment::new("47% / 89%")
79                        .align(Align::Right)
80                        .runs(vec![StyleRun::new(6, 3, Color::SystemRed)]),
81                ]),
82            account_submenu("claude:me"),
83        )
84        .submenu(
85            Row::new("acct:claude:work").segments(vec![
86                Segment::new("work@example.com").flex(Flex::Grow),
87                Segment::new("12% / 30%")
88                    .align(Align::Right)
89                    .runs(vec![StyleRun::new(0, 3, Color::SystemGreen)]),
90            ]),
91            account_submenu("claude:work"),
92        )
93        .separator()
94        .section_header(
95            Row::default()
96                .leading(Icon::from_png(codex_logo))
97                .segment(Segment::new("Codex").font(Font::system(13.0, Weight::Bold))),
98        )
99        .row(Row::new("switch:codex:me").segments(vec![
100            Segment::new("me@example.com").flex(Flex::Grow),
101            Segment::new("3h 12m")
102                .align(Align::Right)
103                .runs(vec![StyleRun::new(0, 6, Color::SystemOrange)]),
104        ]))
105        .separator()
106        .submenu(
107            Row::new("settings").label("Settings"),
108            Menu::new()
109                .row(Row::new("settings:apikey").label("API key…"))
110                .row(Row::new("settings:autoswap").label("Auto-swap accounts"))
111                .separator()
112                .row(Row::new("settings:notifications").label("Notifications…")),
113        )
114        .row(Row::new("quit").segments(vec![
115            Segment::new("Quit").flex(Flex::Grow),
116            Segment::new(concat!("usagio v", env!("CARGO_PKG_VERSION")))
117                .align(Align::Right)
118                .color(Color::SecondaryLabel),
119        ]))
120}
More examples
Hide additional examples
examples/usagio_menu.rs (line 62)
56fn account_submenu(acct: &Account) -> Menu {
57    let mut menu = Menu::new()
58        // Info rows read as normal text but are non-interactive (id = none).
59        .row(Row::label_only("Session resets in 2h 41m"))
60        .row(Row::label_only("Weekly resets in 3d 4h"))
61        .row(Row::default().segment(Segment::new("updated 12s ago").color(Color::SecondaryLabel)))
62        .separator();
63
64    if acct.active {
65        menu = menu.row(
66            Row::new("noop")
67                .leading(Icon::Checkmark)
68                .segment(Segment::new("Active").color(Color::SystemGreen))
69                .enabled(false),
70        );
71    } else {
72        menu = menu.row(
73            Row::new(format!("switch:{}:{}", acct.provider, acct.key))
74                .label("Switch to this account"),
75        );
76    }
77    if acct.supports_launch {
78        menu = menu.row(
79            Row::new(format!("launch:{}:{}", acct.provider, acct.key))
80                .label("Launch client")
81                // A named symbol trails the action (SF Symbol on macOS).
82                .trailing(Icon::Symbol("arrow.up.forward.app")),
83        );
84    }
85    if acct.supports_remove {
86        menu = menu.row(
87            Row::new(format!("remove:{}:{}", acct.provider, acct.key)).label("Remove\u{2026}"),
88        );
89    }
90    menu
91}
92
93/// The Capture submenu: one entry per provider to capture the current login.
94fn capture_submenu(groups: &[Group]) -> Menu {
95    let mut menu = Menu::new();
96    for group in groups {
97        menu = menu.row(
98            Row::new(format!("capture:{}", group.display_name.to_lowercase()))
99                .leading(Icon::from_png(group.icon_png))
100                .label(format!("Capture {} login", group.display_name)),
101        );
102    }
103    menu
104}
105
106/// The Settings submenu: a checkable toggle, an auto-swap threshold flyout, and
107/// a backup flyout — exercising nested submenus, `checked`, and an SVG icon.
108fn settings_submenu() -> Menu {
109    let autoswap = Menu::new()
110        .row(Row::new("autoswap:off").checked(false).label("Off"))
111        .row(Row::new("autoswap:80").checked(false).label("At 80%"))
112        .row(Row::new("autoswap:90").checked(true).label("At 90%"))
113        .separator()
114        .row(Row::new("autoswap:now").label("Swap now"));
115
116    let backup = Menu::new()
117        .row(Row::new("backup:save").label("Save backup\u{2026}"))
118        .row(Row::new("backup:restore").label("Restore backup\u{2026}"));
119
120    Menu::new()
121        .row(
122            Row::new("notifications:limits")
123                .checked(true)
124                .label("Notify near limits"),
125        )
126        .submenu(Row::new("autoswap").label("Auto-swap threshold"), autoswap)
127        .submenu(
128            Row::new("backup")
129                // An SVG leading icon, rasterized per-DPI at draw time.
130                .leading(Icon::from_svg(
131                    br#"<svg xmlns="http://www.w3.org/2000/svg"/>"#.as_slice(),
132                ))
133                .label("Backup"),
134            backup,
135        )
136        .separator()
137        .row(Row::new("refresh:now").label("Refresh now"))
138}
139
140fn build(groups: &[Group]) -> Menu {
141    let mut menu = Menu::new();
142
143    for group in groups {
144        // Bold, logo'd, non-interactive group header (Claude, then Codex).
145        menu = menu.section_header(
146            Row::default()
147                .leading(Icon::from_png(group.icon_png))
148                .segment(Segment::new(group.display_name).font(Font::system(13.0, Weight::Bold))),
149        );
150
151        for acct in &group.accounts {
152            // The label Grows to eat the leftover width, so the value segment
153            // sits flush at the true right edge — no reserved chevron column.
154            let label = Segment::new(acct.display)
155                .flex(Flex::Grow)
156                .font(if acct.active {
157                    Font::system(13.0, Weight::Bold)
158                } else {
159                    Font::system(13.0, Weight::Regular)
160                });
161
162            let value = Segment::new(acct.trailing)
163                .align(Align::Right)
164                .runs(severity_runs(&acct.severity));
165
166            let mut label_row = Row::new(format!("switch:{}:{}", acct.provider, acct.key))
167                .segments(vec![label, value])
168                .checked(acct.active);
169            if acct.active {
170                label_row = label_row.leading(Icon::Checkmark);
171            }
172
173            menu = menu.submenu(label_row, account_submenu(acct));
174        }
175
176        menu = menu.separator();
177    }
178
179    // Bottom actions — now with populated submenus.
180    menu = menu
181        .submenu(
182            Row::new("capture").label("Capture current login"),
183            capture_submenu(groups),
184        )
185        .submenu(Row::new("settings").label("Settings"), settings_submenu());
186
187    // "Quit ........ usagio vX" — label Grows, version tail is greyed + flush-right.
188    menu = menu.row(Row::new("quit").segments(vec![
189        Segment::new("Quit").flex(Flex::Grow),
190        Segment::new(format!("usagio v{}", env!("CARGO_PKG_VERSION")))
191            .align(Align::Right)
192            .color(Color::SecondaryLabel),
193    ]));
194
195    menu
196}
197
198fn icon_tag(icon: &Option<Icon>) -> &'static str {
199    match icon {
200        None => "",
201        Some(Icon::Checkmark) => " [check]",
202        Some(Icon::Png(_)) => " [png]",
203        Some(Icon::Svg(_)) => " [svg]",
204        Some(Icon::Symbol(_)) => " [symbol]",
205    }
206}
207
208fn print_row(row: &Row, prefix: &str, pad: &str) {
209    let check = match row.checked {
210        Some(true) => "[x] ",
211        Some(false) => "[ ] ",
212        None => "",
213    };
214    let dim = if row.enabled { "" } else { " (disabled)" };
215    println!(
216        "{pad}{prefix}{}{check}{}{}{}  [{}]",
217        icon_tag(&row.leading),
218        row_text(row),
219        icon_tag(&row.trailing),
220        dim,
221        row.id.as_str(),
222    );
223}
224
225fn print_menu(menu: &Menu, depth: usize) {
226    let pad = "  ".repeat(depth);
227    for item in &menu.items {
228        match item {
229            Item::Separator => println!("{pad}----"),
230            Item::SectionHeader(row) => {
231                println!("{pad}#{} {}", icon_tag(&row.leading), row_text(row))
232            }
233            Item::Row(row) => print_row(row, "- ", &pad),
234            Item::Submenu { label, menu } => {
235                print_row(label, "> ", &pad);
236                print_menu(menu, depth + 1);
237            }
238            // A rich content row (#44) is a display-only layout stack, not a
239            // labelled row; this text dump just marks its presence.
240            Item::Content(_) => println!("{pad}[content]"),
241        }
242    }
243}
244
245fn row_text(row: &Row) -> String {
246    row.segments
247        .iter()
248        .map(|s| s.text.as_str())
249        .collect::<Vec<_>>()
250        .join("  ")
251}
252
253fn demo_theme_resolution() {
254    // A consumer can resolve semantic colors against any theme with no GUI.
255    let dark = Theme::dark();
256    let label = dark.resolve(Color::Label);
257    let red = dark.resolve(Color::SystemRed);
258    println!(
259        "theme resolution (dark): Label -> rgba({},{},{},{}), SystemRed -> rgba({},{},{},{})",
260        label.r, label.g, label.b, label.a, red.r, red.g, red.b, red.a,
261    );
262}
263
264fn demo_flush_right_layout() {
265    // The "Quit ...... usagio v1" row: a Grow label + a Fixed, right-aligned
266    // version tail. Given measured intrinsic widths, the layout engine flushes
267    // the tail to the right edge with no reserved column.
268    let content_width = 220.0;
269    let segs = [
270        SegmentMetrics::new(30.0, Flex::Grow, Align::Left), // "Quit"
271        SegmentMetrics::new(60.0, Flex::Fixed, Align::Right), // "usagio v1"
272    ];
273    let boxes = resolve_segments(&segs, content_width);
274    println!(
275        "flush-right layout: content {content_width}px -> tail text starts at x={} (right edge {})",
276        boxes[1].text_x,
277        content_width - 60.0,
278    );
279}
280
281fn demo_context_menu() {
282    // The pointer-anchored primitive that also works on Linux.
283    let menu = Menu::new()
284        .row(Row::new("copy").label("Copy"))
285        .row(Row::new("paste").label("Paste"))
286        .separator()
287        .row(Row::new("select-all").label("Select All"));
288    let cm = ContextMenu::new(menu).on_click(|id| println!("context click: {}", id.as_str()));
289    // Exercise the dispatch path without a GUI.
290    cm.dispatch(&"copy".into());
291    println!("context menu has {} items", cm.menu().len());
292}
Source

pub fn section_header(self, row: Row) -> Self

Append an Item::SectionHeader.

Note: the label Row’s MenuId and checked state are ignored for this position; only its text, leading icon, and enabled flag are used. Consider Row::label_only to make that explicit at the call site.

Examples found in repository?
examples/usagio_menu.rs (lines 145-149)
140fn build(groups: &[Group]) -> Menu {
141    let mut menu = Menu::new();
142
143    for group in groups {
144        // Bold, logo'd, non-interactive group header (Claude, then Codex).
145        menu = menu.section_header(
146            Row::default()
147                .leading(Icon::from_png(group.icon_png))
148                .segment(Segment::new(group.display_name).font(Font::system(13.0, Weight::Bold))),
149        );
150
151        for acct in &group.accounts {
152            // The label Grows to eat the leftover width, so the value segment
153            // sits flush at the true right edge — no reserved chevron column.
154            let label = Segment::new(acct.display)
155                .flex(Flex::Grow)
156                .font(if acct.active {
157                    Font::system(13.0, Weight::Bold)
158                } else {
159                    Font::system(13.0, Weight::Regular)
160                });
161
162            let value = Segment::new(acct.trailing)
163                .align(Align::Right)
164                .runs(severity_runs(&acct.severity));
165
166            let mut label_row = Row::new(format!("switch:{}:{}", acct.provider, acct.key))
167                .segments(vec![label, value])
168                .checked(acct.active);
169            if acct.active {
170                label_row = label_row.leading(Icon::Checkmark);
171            }
172
173            menu = menu.submenu(label_row, account_submenu(acct));
174        }
175
176        menu = menu.separator();
177    }
178
179    // Bottom actions — now with populated submenus.
180    menu = menu
181        .submenu(
182            Row::new("capture").label("Capture current login"),
183            capture_submenu(groups),
184        )
185        .submenu(Row::new("settings").label("Settings"), settings_submenu());
186
187    // "Quit ........ usagio vX" — label Grows, version tail is greyed + flush-right.
188    menu = menu.row(Row::new("quit").segments(vec![
189        Segment::new("Quit").flex(Flex::Grow),
190        Segment::new(format!("usagio v{}", env!("CARGO_PKG_VERSION")))
191            .align(Align::Right)
192            .color(Color::SecondaryLabel),
193    ]));
194
195    menu
196}
More examples
Hide additional examples
examples/demo_tray.rs (lines 65-69)
60fn demo_menu() -> Menu {
61    let claude_logo = swatch_png(217, 119, 87);
62    let codex_logo = swatch_png(80, 80, 90);
63
64    Menu::new()
65        .section_header(
66            Row::default()
67                .leading(Icon::from_png(claude_logo))
68                .segment(Segment::new("Claude").font(Font::system(13.0, Weight::Bold))),
69        )
70        .submenu(
71            Row::new("acct:claude:me")
72                .leading(Icon::Checkmark)
73                .checked(true)
74                .segments(vec![
75                    Segment::new("me@example.com")
76                        .flex(Flex::Grow)
77                        .font(Font::system(13.0, Weight::Bold)),
78                    Segment::new("47% / 89%")
79                        .align(Align::Right)
80                        .runs(vec![StyleRun::new(6, 3, Color::SystemRed)]),
81                ]),
82            account_submenu("claude:me"),
83        )
84        .submenu(
85            Row::new("acct:claude:work").segments(vec![
86                Segment::new("work@example.com").flex(Flex::Grow),
87                Segment::new("12% / 30%")
88                    .align(Align::Right)
89                    .runs(vec![StyleRun::new(0, 3, Color::SystemGreen)]),
90            ]),
91            account_submenu("claude:work"),
92        )
93        .separator()
94        .section_header(
95            Row::default()
96                .leading(Icon::from_png(codex_logo))
97                .segment(Segment::new("Codex").font(Font::system(13.0, Weight::Bold))),
98        )
99        .row(Row::new("switch:codex:me").segments(vec![
100            Segment::new("me@example.com").flex(Flex::Grow),
101            Segment::new("3h 12m")
102                .align(Align::Right)
103                .runs(vec![StyleRun::new(0, 6, Color::SystemOrange)]),
104        ]))
105        .separator()
106        .submenu(
107            Row::new("settings").label("Settings"),
108            Menu::new()
109                .row(Row::new("settings:apikey").label("API key…"))
110                .row(Row::new("settings:autoswap").label("Auto-swap accounts"))
111                .separator()
112                .row(Row::new("settings:notifications").label("Notifications…")),
113        )
114        .row(Row::new("quit").segments(vec![
115            Segment::new("Quit").flex(Flex::Grow),
116            Segment::new(concat!("usagio v", env!("CARGO_PKG_VERSION")))
117                .align(Align::Right)
118                .color(Color::SecondaryLabel),
119        ]))
120}
Source

pub fn submenu(self, label: Row, menu: Menu) -> Self

Append an Item::Submenu.

Note: the label Row’s MenuId and checked state are ignored for this position; only its text, leading icon, and enabled flag are used. Consider Row::label_only to make that explicit at the call site.

Examples found in repository?
examples/usagio_menu.rs (line 126)
108fn settings_submenu() -> Menu {
109    let autoswap = Menu::new()
110        .row(Row::new("autoswap:off").checked(false).label("Off"))
111        .row(Row::new("autoswap:80").checked(false).label("At 80%"))
112        .row(Row::new("autoswap:90").checked(true).label("At 90%"))
113        .separator()
114        .row(Row::new("autoswap:now").label("Swap now"));
115
116    let backup = Menu::new()
117        .row(Row::new("backup:save").label("Save backup\u{2026}"))
118        .row(Row::new("backup:restore").label("Restore backup\u{2026}"));
119
120    Menu::new()
121        .row(
122            Row::new("notifications:limits")
123                .checked(true)
124                .label("Notify near limits"),
125        )
126        .submenu(Row::new("autoswap").label("Auto-swap threshold"), autoswap)
127        .submenu(
128            Row::new("backup")
129                // An SVG leading icon, rasterized per-DPI at draw time.
130                .leading(Icon::from_svg(
131                    br#"<svg xmlns="http://www.w3.org/2000/svg"/>"#.as_slice(),
132                ))
133                .label("Backup"),
134            backup,
135        )
136        .separator()
137        .row(Row::new("refresh:now").label("Refresh now"))
138}
139
140fn build(groups: &[Group]) -> Menu {
141    let mut menu = Menu::new();
142
143    for group in groups {
144        // Bold, logo'd, non-interactive group header (Claude, then Codex).
145        menu = menu.section_header(
146            Row::default()
147                .leading(Icon::from_png(group.icon_png))
148                .segment(Segment::new(group.display_name).font(Font::system(13.0, Weight::Bold))),
149        );
150
151        for acct in &group.accounts {
152            // The label Grows to eat the leftover width, so the value segment
153            // sits flush at the true right edge — no reserved chevron column.
154            let label = Segment::new(acct.display)
155                .flex(Flex::Grow)
156                .font(if acct.active {
157                    Font::system(13.0, Weight::Bold)
158                } else {
159                    Font::system(13.0, Weight::Regular)
160                });
161
162            let value = Segment::new(acct.trailing)
163                .align(Align::Right)
164                .runs(severity_runs(&acct.severity));
165
166            let mut label_row = Row::new(format!("switch:{}:{}", acct.provider, acct.key))
167                .segments(vec![label, value])
168                .checked(acct.active);
169            if acct.active {
170                label_row = label_row.leading(Icon::Checkmark);
171            }
172
173            menu = menu.submenu(label_row, account_submenu(acct));
174        }
175
176        menu = menu.separator();
177    }
178
179    // Bottom actions — now with populated submenus.
180    menu = menu
181        .submenu(
182            Row::new("capture").label("Capture current login"),
183            capture_submenu(groups),
184        )
185        .submenu(Row::new("settings").label("Settings"), settings_submenu());
186
187    // "Quit ........ usagio vX" — label Grows, version tail is greyed + flush-right.
188    menu = menu.row(Row::new("quit").segments(vec![
189        Segment::new("Quit").flex(Flex::Grow),
190        Segment::new(format!("usagio v{}", env!("CARGO_PKG_VERSION")))
191            .align(Align::Right)
192            .color(Color::SecondaryLabel),
193    ]));
194
195    menu
196}
More examples
Hide additional examples
examples/demo_tray.rs (lines 70-83)
60fn demo_menu() -> Menu {
61    let claude_logo = swatch_png(217, 119, 87);
62    let codex_logo = swatch_png(80, 80, 90);
63
64    Menu::new()
65        .section_header(
66            Row::default()
67                .leading(Icon::from_png(claude_logo))
68                .segment(Segment::new("Claude").font(Font::system(13.0, Weight::Bold))),
69        )
70        .submenu(
71            Row::new("acct:claude:me")
72                .leading(Icon::Checkmark)
73                .checked(true)
74                .segments(vec![
75                    Segment::new("me@example.com")
76                        .flex(Flex::Grow)
77                        .font(Font::system(13.0, Weight::Bold)),
78                    Segment::new("47% / 89%")
79                        .align(Align::Right)
80                        .runs(vec![StyleRun::new(6, 3, Color::SystemRed)]),
81                ]),
82            account_submenu("claude:me"),
83        )
84        .submenu(
85            Row::new("acct:claude:work").segments(vec![
86                Segment::new("work@example.com").flex(Flex::Grow),
87                Segment::new("12% / 30%")
88                    .align(Align::Right)
89                    .runs(vec![StyleRun::new(0, 3, Color::SystemGreen)]),
90            ]),
91            account_submenu("claude:work"),
92        )
93        .separator()
94        .section_header(
95            Row::default()
96                .leading(Icon::from_png(codex_logo))
97                .segment(Segment::new("Codex").font(Font::system(13.0, Weight::Bold))),
98        )
99        .row(Row::new("switch:codex:me").segments(vec![
100            Segment::new("me@example.com").flex(Flex::Grow),
101            Segment::new("3h 12m")
102                .align(Align::Right)
103                .runs(vec![StyleRun::new(0, 6, Color::SystemOrange)]),
104        ]))
105        .separator()
106        .submenu(
107            Row::new("settings").label("Settings"),
108            Menu::new()
109                .row(Row::new("settings:apikey").label("API key…"))
110                .row(Row::new("settings:autoswap").label("Auto-swap accounts"))
111                .separator()
112                .row(Row::new("settings:notifications").label("Notifications…")),
113        )
114        .row(Row::new("quit").segments(vec![
115            Segment::new("Quit").flex(Flex::Grow),
116            Segment::new(concat!("usagio v", env!("CARGO_PKG_VERSION")))
117                .align(Align::Right)
118                .color(Color::SecondaryLabel),
119        ]))
120}
Source

pub fn content(self, stack: Stack) -> Self

Append an Item::Content row (issue #44): a non-interactive row whose body is an arbitrary declarative Stack.

Source

pub fn len(&self) -> usize

The number of items at this level (not counting nested submenu items).

Examples found in repository?
examples/usagio_menu.rs (line 291)
281fn demo_context_menu() {
282    // The pointer-anchored primitive that also works on Linux.
283    let menu = Menu::new()
284        .row(Row::new("copy").label("Copy"))
285        .row(Row::new("paste").label("Paste"))
286        .separator()
287        .row(Row::new("select-all").label("Select All"));
288    let cm = ContextMenu::new(menu).on_click(|id| println!("context click: {}", id.as_str()));
289    // Exercise the dispatch path without a GUI.
290    cm.dispatch(&"copy".into());
291    println!("context menu has {} items", cm.menu().len());
292}
Source

pub fn is_empty(&self) -> bool

Whether the menu has no items.

Source

pub fn interactive_count(&self) -> usize

Total number of interactive (focusable) items at this level.

Trait Implementations§

Source§

impl Clone for Menu

Source§

fn clone(&self) -> Menu

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Menu

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Menu

Source§

fn default() -> Menu

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl Freeze for Menu

§

impl RefUnwindSafe for Menu

§

impl Send for Menu

§

impl Sync for Menu

§

impl Unpin for Menu

§

impl UnsafeUnpin for Menu

§

impl UnwindSafe for Menu

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> AutoreleaseSafe for T
where T: ?Sized,

Source§

impl<T> AutoreleaseSafe for T
where T: ?Sized,

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.