1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
//! Easily import Glade-generated UI files into Rust code.
//!
//! ```
//! use gtk::prelude::*;
//! use gladis::Gladis;
//!
//! const GLADE_SRC: &str = r#"
//! <?xml version="1.0" encoding="UTF-8"?>
//! <!-- Generated with glade 3.22.2 -->
//! <interface>
//! <requires lib="gtk+" version="3.20"/>
//! <object class="GtkApplicationWindow" id="window">
//! <property name="can_focus">False</property>
//! <child type="titlebar">
//! <placeholder/>
//! </child>
//! <child>
//! <object class="GtkLabel" id="label">
//! <property name="visible">True</property>
//! <property name="can_focus">False</property>
//! <property name="label" translatable="yes">label</property>
//! </object>
//! </child>
//! </object>
//! </interface>"#;
//!
//! #[derive(Gladis, Clone)]
//! pub struct Window {
//! pub window: gtk::ApplicationWindow,
//! pub label: gtk::Label,
//! }
//!
//! gtk::init().unwrap();
//! let _ui = Window::from_string(GLADE_SRC).unwrap();
//! ```
use std::{error::Error, fmt::Display};
#[derive(Debug, Clone)]
pub struct NotFoundError {
pub identifier: String,
pub typ: String,
}
impl Display for NotFoundError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"identifier {} of type {} was not found",
self.identifier, self.typ
)
}
}
impl Error for NotFoundError {}
#[derive(Debug, Clone)]
pub enum GladisError {
NotFound(NotFoundError),
}
impl Display for GladisError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GladisError::NotFound(e) => write!(f, "not found error: {}", e),
}
}
}
impl Error for GladisError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
GladisError::NotFound(e) => Some(e),
}
}
}
impl GladisError {
pub fn not_found<T>(identifier: T, typ: T) -> Self
where
T: ToString,
{
let identifier = identifier.to_string();
let typ = typ.to_string();
GladisError::NotFound(NotFoundError { identifier, typ })
}
}
pub type Result<T> = std::result::Result<T, GladisError>;
pub trait Gladis {
//! A trait to load a struct from a builder.
//!
//! # Automatic implementation
//!
//! This trait wakes little sense alone, but truly show its power when used
//! with the [gladis_proc_macro](https://docs.rs/gladis_proc_macro) crate
//! and its `#[derive(Gladis)]` macro.
//!
//! ```
//! use gtk::prelude::*;
//! use gladis::Gladis;
//!
//! #[derive(Gladis, Clone)]
//! pub struct Window {
//! pub window: gtk::ApplicationWindow,
//! pub label: gtk::Label,
//! }
//! ```
//!
//! # Manual implementation
//!
//! Below is an example of manual implementation of the trait.
//!
//! ```
//! use gtk::prelude::*;
//! use gladis::{Gladis, Result, GladisError};
//!
//! pub struct Window {
//! pub window: gtk::ApplicationWindow,
//! pub label: gtk::Label,
//! }
//!
//! impl Gladis for Window {
//! fn from_builder(builder: gtk::Builder) -> Result<Self> {
//! let window: gtk::ApplicationWindow = builder
//! .object("window")
//! .ok_or(GladisError::not_found("window", "gtk::ApplicationWindow"))?;
//!
//! let label: gtk::Label = builder
//! .object("label")
//! .ok_or(GladisError::not_found("label", "gtk::Label"))?;
//!
//! Ok(Self { window, label })
//! }
//! }
//! ```
/// Populate struct from a builder.
///
/// This method should not be called directly but is used as a common
/// function for the `from_string` and `from_resource` functions to
/// share the same code.
fn from_builder(builder: gtk::Builder) -> Result<Self>
where
Self: std::marker::Sized;
/// Populate struct from a Glade document.
fn from_string(src: &str) -> Result<Self>
where
Self: std::marker::Sized,
{
let builder = gtk::Builder::from_string(src);
Gladis::from_builder(builder)
}
/// Populate struct from a Glade document as a resource.
fn from_resource(resource_path: &str) -> Result<Self>
where
Self: std::marker::Sized,
{
let builder = gtk::Builder::from_resource(resource_path);
Gladis::from_builder(builder)
}
}
// Re-export #[derive(Gladis)].
#[cfg(feature = "derive")]
#[doc(hidden)]
pub use gladis_proc_macro::Gladis;
#[cfg(test)]
mod tests {
use crate::{GladisError, NotFoundError};
#[test]
fn fmt_not_found_error() {
let err = NotFoundError {
identifier: "foo".to_string(),
typ: "bar".to_string(),
};
assert_eq!(err.to_string(), "identifier foo of type bar was not found");
}
#[test]
fn fmt_gladis_error() {
let err = GladisError::NotFound(NotFoundError {
identifier: "foo".to_string(),
typ: "bar".to_string(),
});
assert_eq!(
err.to_string(),
"not found error: identifier foo of type bar was not found"
);
}
}