1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-25 22:33:52 +03:00
wezterm/wezterm-dynamic/src/object.rs
2022-05-18 13:39:51 -07:00

170 lines
4.0 KiB
Rust

use crate::Value;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::ops::{Deref, DerefMut};
/// We'd like to avoid allocating when resolving struct fields,
/// so this is the borrowed version of Value.
/// It's a bit involved to make this work; more details can be
/// found in the excellent guide here:
/// <https://github.com/sunshowers/borrow-complex-key-example/blob/master/src/lib.rs>
#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq, Ord, PartialOrd)]
pub enum BorrowedKey<'a> {
Value(&'a Value),
Str(&'a str),
}
pub trait ObjectKeyTrait {
fn key<'k>(&'k self) -> BorrowedKey<'k>;
}
impl ObjectKeyTrait for Value {
fn key<'k>(&'k self) -> BorrowedKey<'k> {
match self {
Value::String(s) => BorrowedKey::Str(s.as_str()),
v => BorrowedKey::Value(v),
}
}
}
impl<'a> ObjectKeyTrait for BorrowedKey<'a> {
fn key<'k>(&'k self) -> BorrowedKey<'k> {
*self
}
}
impl<'a> std::borrow::Borrow<dyn ObjectKeyTrait + 'a> for Value {
fn borrow(&self) -> &(dyn ObjectKeyTrait + 'a) {
self
}
}
impl<'a> PartialEq for (dyn ObjectKeyTrait + 'a) {
fn eq(&self, other: &Self) -> bool {
self.key().eq(&other.key())
}
}
impl<'a> Eq for (dyn ObjectKeyTrait + 'a) {}
impl<'a> PartialOrd for (dyn ObjectKeyTrait + 'a) {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.key().partial_cmp(&other.key())
}
}
impl<'a> Ord for (dyn ObjectKeyTrait + 'a) {
fn cmp(&self, other: &Self) -> Ordering {
self.key().cmp(&other.key())
}
}
impl<'a> std::hash::Hash for (dyn ObjectKeyTrait + 'a) {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.key().hash(state)
}
}
#[derive(Clone, Default, PartialEq, Eq, Hash)]
pub struct Object {
inner: BTreeMap<Value, Value>,
}
impl Object {
pub fn get_by_str(&self, field_name: &str) -> Option<&Value> {
self.inner
.get(&BorrowedKey::Str(field_name) as &dyn ObjectKeyTrait)
}
}
impl std::fmt::Debug for Object {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
self.inner.fmt(fmt)
}
}
impl Ord for Object {
fn cmp(&self, other: &Self) -> Ordering {
let self_ptr = self as *const Self;
let other_ptr = other as *const Self;
self_ptr.cmp(&other_ptr)
}
}
impl PartialOrd for Object {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Drop for Object {
fn drop(&mut self) {
for (_, child) in std::mem::replace(&mut self.inner, BTreeMap::new()) {
crate::drop::safely(child);
}
}
}
impl From<BTreeMap<Value, Value>> for Object {
fn from(inner: BTreeMap<Value, Value>) -> Self {
Self { inner }
}
}
impl Deref for Object {
type Target = BTreeMap<Value, Value>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for Object {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
fn take(object: Object) -> BTreeMap<Value, Value> {
let object = core::mem::ManuallyDrop::new(object);
unsafe { core::ptr::read(&object.inner) }
}
impl IntoIterator for Object {
type Item = (Value, Value);
type IntoIter = <BTreeMap<Value, Value> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
take(self).into_iter()
}
}
impl<'a> IntoIterator for &'a Object {
type Item = (&'a Value, &'a Value);
type IntoIter = <&'a BTreeMap<Value, Value> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a> IntoIterator for &'a mut Object {
type Item = (&'a Value, &'a mut Value);
type IntoIter = <&'a mut BTreeMap<Value, Value> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl FromIterator<(Value, Value)> for Object {
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = (Value, Value)>,
{
Object {
inner: BTreeMap::from_iter(iter),
}
}
}