Skip to main content

Crate facet_egui

Crate facet_egui 

Source
Expand description

§facet-egui

MHC Solutions GmbH

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.

Crates.io Docs.rs CI License

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:

FacetProbe Screenshot

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 between None and Some(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>> and Arc<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’s Display implementation

§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 detectionshape.is_default() to check if type implements Default

§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 iterationfields() method on structs and enums for safe traversal
  • Collection access — Length queries and iteration over lists, maps, sets
  • Pointer dereferencinginnermost_peek() for transparent navigation through smart pointers
  • Scalar type detectionscalar_type() for primitive value handling
  • Enum inspection — Access to active variant and variant fields

§Mutable Reflection (facet-reflect::Poke)

  • Mutable accesspoke.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 operationspush_from_heap(), pop(), swap() for vector manipulation
  • Map operationsinsert_from_heap() for adding key-value pairs
  • Option mutationset_none() and set_some_from_heap() for option toggling
  • Reborrowingtry_reborrow() to handle transparent wrapper types

§Collection Support

Handles all standard Rust collections transparently:

  • VectorsVec<T> with full push/pop/swap support (via Default trait provided in a types VTableDirect/VTableIndirect)
  • MapsBTreeMap<K, V> and other map types with key-value pair insertion facet does not yet implement mutable map types. (get_mut)
  • Sets — Set types with element insertion
  • Tuples — Multi-element tuple reflection and access
  • OptionsOption<T> with None/Some toggling

§Concurrency & Smart Pointers

  • Reference counting — Transparent Arc<T> and Rc<T> dereferencing
  • Shared mutabilityArc<RwLock<T>> with automatic read/write lock acquisition
  • Mutex supportArc<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:

  • Primitivesbool, u32, u64, i32, i64, f32, f64, and other scalar types
  • StringsString (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

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§

FacetProbe
The container that stores a MaybeMut of the type T that should be shown in the Ui

Enums§

Attr
MaybeMut
Some reference to a type that implements Facet that may be mut or not.
MaybeMutT