GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
feat(config,ipc): typed config accessors and a shared IPC socket module
config: add get_bool/get_f32/get_i64/get_string/get_color/find_key over the
cached config, collapsing per-crate load_config + .pointer() accessors.
ipc: add socket_path(prefix) + send_command(prefix, cmd) for the
/tmp/<prefix>-<WAYLAND_DISPLAY>.sock convention duplicated across daemons.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
src/config.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/ipc.rs | 29 +++++++++++++++++++++++++++++
src/lib.rs | 1 +
3 files changed, 84 insertions(+)
diff --git a/src/config.rs b/src/config.rs
index 2e5824f..b7cc9ab 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -514,6 +514,60 @@ pub fn cached_config_content() -> String {
CONFIG_CACHE.read().map(|c| c.raw_content.clone()).unwrap_or_default()
}
+// ── Typed accessors over the cached config ──────────────────────────────────
+// Each reads the mtime-cached config and extracts a value at a JSON pointer
+// (e.g. "/notifications/enable"), returning the default when absent or mistyped.
+
+/// Read a boolean at `pointer` from the cached config, or `default`.
+pub fn get_bool(pointer: &str, default: bool) -> bool {
+ cached_config().pointer(pointer).and_then(|v| v.as_bool()).unwrap_or(default)
+}
+
+/// Read an f32 at `pointer` from the cached config, or `default`.
+pub fn get_f32(pointer: &str, default: f32) -> f32 {
+ cached_config()
+ .pointer(pointer)
+ .and_then(|v| v.as_f64())
+ .map(|f| f as f32)
+ .unwrap_or(default)
+}
+
+/// Read an i64 at `pointer` from the cached config, or `default`.
+pub fn get_i64(pointer: &str, default: i64) -> i64 {
+ cached_config().pointer(pointer).and_then(|v| v.as_i64()).unwrap_or(default)
+}
+
+/// Read a string at `pointer` from the cached config.
+pub fn get_string(pointer: &str) -> Option<String> {
+ cached_config().pointer(pointer).and_then(|v| v.as_str()).map(|s| s.to_string())
+}
+
+/// Read a hex color string at `pointer` and parse it to raw sRGB RGBA (`[0,1]`).
+/// Apply [`crate::color::srgb_to_linear`] if your render target expects linear.
+pub fn get_color(pointer: &str) -> Option<[f32; 4]> {
+ get_string(pointer).as_deref().and_then(crate::color::parse_hex_rgba)
+}
+
+/// Recursively search a JSON value for the first entry whose object key equals
+/// `key`, returning a reference to its value. Depth-first over objects and arrays.
+pub fn find_key<'a>(val: &'a serde_json::Value, key: &str) -> Option<&'a serde_json::Value> {
+ match val {
+ serde_json::Value::Object(map) => {
+ if let Some(found) = map.get(key) {
+ return Some(found);
+ }
+ for v in map.values() {
+ if let Some(found) = find_key(v, key) {
+ return Some(found);
+ }
+ }
+ None
+ }
+ serde_json::Value::Array(arr) => arr.iter().find_map(|v| find_key(v, key)),
+ _ => None,
+ }
+}
+
fn perform_rolling_backup(path: &str) {
diff --git a/src/ipc.rs b/src/ipc.rs
new file mode 100644
index 0000000..ac2d678
--- /dev/null
+++ b/src/ipc.rs
@@ -0,0 +1,29 @@
+//! Helpers for the CCE Unix-socket IPC convention: `/tmp/<prefix>-<WAYLAND_DISPLAY>.sock`.
+
+use std::io::{Read, Write};
+use std::os::unix::net::UnixStream;
+
+/// Path of a CCE IPC socket for `prefix`, keyed by `$WAYLAND_DISPLAY`.
+///
+/// `socket_path("cce")` → `/tmp/cce-<display>.sock` (the compositor control socket);
+/// `socket_path("cce-status-interface")` → the status socket. Falls back to
+/// `/tmp/<prefix>.sock` when `$WAYLAND_DISPLAY` is unset.
+pub fn socket_path(prefix: &str) -> String {
+ match std::env::var("WAYLAND_DISPLAY") {
+ Ok(d) if !d.is_empty() => format!("/tmp/{}-{}.sock", prefix, d),
+ _ => format!("/tmp/{}.sock", prefix),
+ }
+}
+
+/// Connect to the `prefix` socket, send `command` (newline-terminated), and
+/// return the reply text. Errors if the socket can't be reached.
+pub fn send_command(prefix: &str, command: &str) -> std::io::Result<String> {
+ let mut stream = UnixStream::connect(socket_path(prefix))?;
+ stream.write_all(command.as_bytes())?;
+ if !command.ends_with('\n') {
+ stream.write_all(b"\n")?;
+ }
+ let mut reply = String::new();
+ stream.read_to_string(&mut reply)?;
+ Ok(reply)
+}
diff --git a/src/lib.rs b/src/lib.rs
index ec961ce..3a3de1e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -10,6 +10,7 @@ pub mod backend;
pub mod context;
pub mod process;
pub mod file_dialog;
+pub mod ipc;
pub mod colors {
pub use crate::color::*;