Expand description
§facet-egui
Development of this crate is supported by MHC Solutions GmbH, an engineering company focused on building, industrial, and energy automation whose support for open-source work helps make projects like this possible.
An egui inspector/editor widget for any type that implements Facet. Derive Facet on your types and get a full property editor with no additional boilerplate.
This demonstrates both editable and readonly modes side-by-side:

Run the gallery example to see FacetProbe in action:
cargo run --example probe_gallery§Example: Complete Type Definition
Here’s a complete example demonstrating the types you can inspect and edit:
#[derive(Debug, Facet, Default)]
#[repr(C)]
enum ThemeMode {
#[default]
Light,
Dark,
Auto,
}
#[derive(Debug, Facet, Default)]
struct Audio {
volume: f32,
muted: bool,
output: String,
}
#[derive(Debug, Facet, Default)]
struct Player {
nickname: String,
active: bool,
score: u64,
#[facet(facet_egui::rename("HP"))]
health_points: f32,
loadout: Vec<String>,
}
#[derive(Debug, Facet)]
struct Profile {
title: String,
theme: ThemeMode,
tags: Vec<String>,
properties: BTreeMap<String, i32>,
audio: Audio,
squad: Vec<Player>,
#[facet(facet_egui::readonly)]
build_id: String,
#[facet(facet_egui::skip)]
_internal_cache: Vec<u8>,
}§Usage: FacetProbe Widget
Creating and displaying a probe is simple:
use facet_egui::FacetProbe;
// In your egui UI function:
FacetProbe::new(&mut self.profile)
.with_id_source("my_probe")
.with_header("profile")
.show(ui);
// For readonly mode:
FacetProbe::new(&self.readonly_data)
.with_id_source("readonly_probe")
.with_header("snapshot")
.readonly(true)
.show(ui);
// Expand all sections by default:
FacetProbe::new(&mut self.data)
.with_header("data")
.expand_all(true)
.show(ui);§Features
§UI Capabilities
- Recursive struct/enum/list/map/option inspection and editing — Navigate arbitrarily nested data structures
- Enum variant switching via combo box — Change active enum variant at runtime
- Option
toggle — Switch betweenNoneandSome(T::default()) - List manipulation — Push/pop elements, swap items, inspect collections
- Map/BTreeMap editing — Insert and remove key-value pairs
- Smart pointer traversal — Transparent navigation through
Arc,Rc,Box, etc. - Automatic lock handling — Read from or write to
Arc<RwLock<T>>andArc<Mutex<T>>with automatic lock acquisition - Field-level control via attributes — Per-field customization using
#[facet(egui::...)] - Readonly mode — Display data without allowing modifications
- Struct/enum exploration — Drill down into complex nested types
§Custom Attribute Support
Control field visibility and behavior using #[facet(...)] attributes:
#[facet(egui::skip)]— Hide a field from the UI#[facet(egui::readonly)]— Display field as read-only (no editing)#[facet(egui::rename("Custom Name"))]— Use a custom display name#[facet(egui::expand_all)]— Expand all collapsible sections by default#[facet(egui::as_display)]— Render using the type’sDisplayimplementation
§facet & facet-reflect Integration
facet-egui is built on top of facet-reflect and uses the following key features:
§Core Type System (facet)
#[derive(Facet)]— Automatic type reflection for structs and enums- Shape metadata — Complete type information including field names, layout, and custom attributes
- Type definitions — Type categorization (primitives, pointers, lists, maps, options, sets)
- Custom attribute grammar — Extensible attribute system via
#[facet(...)]macros - VTable support — Dynamic dispatch for operations like list push/pop/swap
- Pointer introspection — Detection of smart pointers with lock capability (
Arc<RwLock<T>>,Arc<Mutex<T>>) - Default trait detection —
shape.is_default()to check if type implementsDefault
§Immutable Reflection (facet-reflect::Peek)
- Type narrowing — Methods like
peek.into_struct(),peek.into_enum(),peek.into_list_like(),peek.into_map(),peek.into_option(),peek.into_pointer() - Field iteration —
fields()method on structs and enums for safe traversal - Collection access — Length queries and iteration over lists, maps, sets
- Pointer dereferencing —
innermost_peek()for transparent navigation through smart pointers - Scalar type detection —
scalar_type()for primitive value handling - Enum inspection — Access to active variant and variant fields
§Mutable Reflection (facet-reflect::Poke)
- Mutable access —
poke.into_struct(),poke.into_enum(),poke.into_list(),poke.into_map(),poke.into_option() - Field mutation — Get mutable references to struct fields and enum variant data
- List operations —
push_from_heap(),pop(),swap()for vector manipulation - Map operations —
insert_from_heap()for adding key-value pairs - Option mutation —
set_none()andset_some_from_heap()for option toggling - Reborrowing —
try_reborrow()to handle transparent wrapper types
§Collection Support
Handles all standard Rust collections transparently:
- Vectors —
Vec<T>with full push/pop/swap support (viaDefaulttrait provided in a typesVTableDirect/VTableIndirect) Maps —BTreeMap<K, V>and other map types with key-value pair insertionfacetdoes not yet implement mutable map types. (get_mut)Sets — Set types with element insertion- Tuples — Multi-element tuple reflection and access
- Options —
Option<T>withNone/Sometoggling
§Concurrency & Smart Pointers
- Reference counting — Transparent
Arc<T>andRc<T>dereferencing - Shared mutability —
Arc<RwLock<T>>with automatic read/write lock acquisition - Mutex support —
Arc<Mutex<T>>for synchronous locking - Box & owned pointers — Transparent navigation through
Box<T> - VTable-based locking — Dynamic dispatch for lock operations (via
facet-maybe-mut)
§Type System Capabilities
Supported types include:
- Primitives —
bool,u32,u64,i32,i64,f32,f64, and other scalar types - Strings —
String(mutable) and&'static str(static references) - User-defined types — Any struct or enum with
#[derive(Facet)] - Nested structures — Arbitrary nesting depth with recursive traversal
- Transparent wrappers — Smart pointers, locks, and other wrapper types
§Installation
Add to your Cargo.toml:
[dependencies]
facet = "0.46"
facet-egui = "0.1"
egui = "0.28"Optional: Enable std feature for full functionality:
[dependencies]
facet = { version = "0.46", features = ["std"] }
facet-egui = "0.1"§Status
Work in progress. The API is not stable.
Due to facet not yet providing safe wrapper apis for everything,
facet-egui also contains unsafe code which may not be sound.
§Credits
This crate is inspired by the great egui-probe crate which provides the same (and more) functionality with its own derive macro.
§License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
§Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Structs§
- Facet
Probe - The container that stores a
MaybeMutof the typeTthat should be shown in theUi