| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501 |
- /* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2026 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- use crate::error::{Error, Result};
- use darkfi_serial::{async_trait, Encodable, FutAsyncWriteExt, SerialDecodable, SerialEncodable};
- use std::{
- io::Write,
- sync::{Arc, Mutex as SyncMutex, Weak},
- };
- use crate::{
- expr::SExprCode,
- pubsub::{Publisher, PublisherPtr, Subscription},
- scene::{SceneNodeId, SceneNodeWeak},
- };
- mod guard;
- pub use guard::{BatchGuardPtr, PropertyAtomicGuard};
- mod wrap;
- pub use wrap::{
- PropertyBool, PropertyColor, PropertyDimension, PropertyEnum, PropertyFloat32, PropertyRect,
- PropertyStr, PropertyUint32,
- };
- #[derive(Debug, Copy, Clone, PartialEq, SerialEncodable, SerialDecodable)]
- #[repr(u8)]
- pub enum PropertyType {
- Null = 0,
- Bool = 1,
- Uint32 = 2,
- Float32 = 3,
- Str = 4,
- Enum = 5,
- SceneNodeId = 7,
- SExpr = 8,
- }
- impl PropertyType {
- fn default_value(&self) -> PropertyValue {
- match self {
- Self::Null => PropertyValue::Null,
- Self::Bool => PropertyValue::Bool(false),
- Self::Uint32 => PropertyValue::Uint32(0),
- Self::Float32 => PropertyValue::Float32(0.),
- Self::Str => PropertyValue::Str(String::new()),
- Self::Enum => PropertyValue::Enum(String::new()),
- Self::SceneNodeId => PropertyValue::SceneNodeId(0),
- Self::SExpr => PropertyValue::SExpr(Arc::new(vec![])),
- }
- }
- }
- #[derive(Debug, Copy, Clone, PartialEq, SerialEncodable, SerialDecodable)]
- #[repr(u8)]
- pub enum PropertySubType {
- Null = 0,
- Color = 1,
- // Size of something in pixels
- Pixel = 2,
- ResourceId = 3,
- Locale = 4,
- Flag = 5,
- }
- #[derive(Debug, Copy, Clone, PartialEq)]
- pub enum Role {
- User = 0,
- App = 1,
- Internal = 2,
- Ignored = 3,
- }
- #[derive(Debug, Clone, PartialEq)]
- pub enum PropertyValue {
- Unset,
- Null,
- Bool(bool),
- Uint32(u32),
- Float32(f32),
- Str(String),
- Enum(String),
- SceneNodeId(SceneNodeId),
- SExpr(Arc<SExprCode>),
- }
- impl PropertyValue {
- fn as_type(&self) -> PropertyType {
- match self {
- Self::Unset => todo!("not sure"),
- Self::Null => PropertyType::Null,
- Self::Bool(_) => PropertyType::Bool,
- Self::Uint32(_) => PropertyType::Uint32,
- Self::Float32(_) => PropertyType::Float32,
- Self::Str(_) => PropertyType::Str,
- Self::Enum(_) => PropertyType::Enum,
- Self::SceneNodeId(_) => PropertyType::SceneNodeId,
- Self::SExpr(_) => PropertyType::SExpr,
- }
- }
- pub fn is_unset(&self) -> bool {
- match self {
- Self::Unset => true,
- _ => false,
- }
- }
- pub fn is_null(&self) -> bool {
- match self {
- Self::Null => true,
- _ => false,
- }
- }
- pub fn is_expr(&self) -> bool {
- match self {
- Self::SExpr(_) => true,
- _ => false,
- }
- }
- pub fn as_bool(&self) -> Result<bool> {
- match self {
- Self::Bool(v) => Ok(*v),
- _ => Err(Error::PropertyWrongType),
- }
- }
- pub fn as_u32(&self) -> Result<u32> {
- match self {
- Self::Uint32(v) => Ok(*v),
- _ => Err(Error::PropertyWrongType),
- }
- }
- pub fn as_f32(&self) -> Result<f32> {
- match self {
- Self::Float32(v) => Ok(*v),
- _ => Err(Error::PropertyWrongType),
- }
- }
- pub fn as_str(&self) -> Result<String> {
- match self {
- Self::Str(v) => Ok(v.clone()),
- _ => Err(Error::PropertyWrongType),
- }
- }
- pub fn as_enum(&self) -> Result<String> {
- match self {
- Self::Enum(v) => Ok(v.clone()),
- _ => Err(Error::PropertyWrongType),
- }
- }
- pub fn as_node_id(&self) -> Result<SceneNodeId> {
- match self {
- Self::SceneNodeId(v) => Ok(*v),
- _ => Err(Error::PropertyWrongType),
- }
- }
- pub fn as_sexpr(&self) -> Result<Arc<SExprCode>> {
- match self {
- Self::SExpr(v) => Ok(v.clone()),
- _ => Err(Error::PropertyWrongType),
- }
- }
- }
- impl Encodable for PropertyValue {
- fn encode<S: Write>(&self, s: &mut S) -> std::result::Result<usize, std::io::Error> {
- match self {
- Self::Unset | Self::Null => {
- // do nothing
- Ok(0)
- }
- Self::Bool(v) => v.encode(s),
- Self::Uint32(v) => v.encode(s),
- Self::Float32(v) => v.encode(s),
- Self::Str(v) => v.encode(s),
- Self::Enum(v) => v.encode(s),
- Self::SceneNodeId(v) => v.encode(s),
- Self::SExpr(v) => v.encode(s),
- }
- }
- }
- #[derive(Debug, Clone)]
- pub enum ModifyAction {
- Clear,
- Set(usize),
- SetVec,
- SetCache(Vec<usize>),
- Unset(usize),
- Push(usize),
- Insert(usize),
- Remove(usize, PropertyValue),
- }
- type ModifyPublisher = PublisherPtr<(Role, ModifyAction, BatchGuardPtr)>;
- pub type PropertyPtr = Arc<Property>;
- pub type PropertyWeak = Weak<Property>;
- #[derive(Debug, Clone)]
- pub struct PropertyDepend {
- pub prop: PropertyWeak,
- pub i: usize,
- pub local_name: String,
- }
- pub struct Property {
- pub name: String,
- pub node: SyncMutex<Option<SceneNodeWeak>>,
- pub typ: PropertyType,
- pub subtype: PropertySubType,
- pub defaults: Vec<PropertyValue>,
- // either a value or an expr must be set
- pub vals: SyncMutex<Vec<PropertyValue>>,
- // only used valid when PropertyValue is an expr
- // caches the last calculated value
- pub cache: SyncMutex<Vec<PropertyValue>>,
- pub ui_name: String,
- pub desc: String,
- pub is_null_allowed: bool,
- pub is_expr_allowed: bool,
- // Use 0 for unbounded length
- pub array_len: usize,
- pub min_val: Option<PropertyValue>,
- pub max_val: Option<PropertyValue>,
- // PropertyType must be Enum
- pub enum_items: Option<Vec<String>>,
- on_modify: ModifyPublisher,
- depends: SyncMutex<Vec<PropertyDepend>>,
- }
- impl Property {
- pub fn new<S: Into<String>>(name: S, typ: PropertyType, subtype: PropertySubType) -> Self {
- Self {
- name: name.into(),
- node: SyncMutex::new(None),
- typ,
- subtype,
- defaults: vec![typ.default_value()],
- vals: SyncMutex::new(vec![PropertyValue::Unset]),
- cache: SyncMutex::new(vec![PropertyValue::Null]),
- ui_name: String::new(),
- desc: String::new(),
- is_null_allowed: false,
- is_expr_allowed: false,
- array_len: 1,
- min_val: None,
- max_val: None,
- enum_items: None,
- on_modify: Publisher::new(),
- depends: SyncMutex::new(vec![]),
- }
- }
- /// Just used for debugging
- pub fn set_parent(&self, node: SceneNodeWeak) {
- *self.node.lock().unwrap() = Some(node);
- }
- pub fn set_ui_text<S: Into<String>>(&mut self, ui_name: S, desc: S) {
- self.ui_name = ui_name.into();
- self.desc = desc.into();
- }
- pub fn set_array_len(&mut self, len: usize) {
- self.array_len = len;
- self.defaults.resize(len, self.typ.default_value());
- self.defaults.shrink_to_fit();
- let vals = &mut *self.vals.lock().unwrap();
- vals.resize(len, PropertyValue::Unset);
- vals.shrink_to_fit();
- let cache = &mut *self.cache.lock().unwrap();
- cache.resize(len, PropertyValue::Null);
- cache.shrink_to_fit();
- }
- pub fn set_unbounded(&mut self) {
- self.set_array_len(0);
- }
- pub fn set_range_u32(&mut self, min: u32, max: u32) {
- self.min_val = Some(PropertyValue::Uint32(min));
- self.max_val = Some(PropertyValue::Uint32(max));
- }
- pub fn set_range_f32(&mut self, min: f32, max: f32) {
- self.min_val = Some(PropertyValue::Float32(min));
- self.max_val = Some(PropertyValue::Float32(max));
- }
- pub fn set_enum_items<S: Into<String>>(&mut self, enum_items: Vec<S>) -> Result<()> {
- if self.typ != PropertyType::Enum {
- return Err(Error::PropertyWrongType)
- }
- self.enum_items = Some(enum_items.into_iter().map(|item| item.into()).collect());
- Ok(())
- }
- pub fn allow_null_values(&mut self) {
- self.is_null_allowed = true;
- }
- pub fn allow_exprs(&mut self) {
- self.is_expr_allowed = true;
- }
- fn check_defaults_len(&self, defaults_len: usize) -> Result<()> {
- if !self.is_bounded() || defaults_len != self.array_len {
- return Err(Error::PropertyWrongLen)
- }
- Ok(())
- }
- pub fn set_defaults_bool(&mut self, defaults: Vec<bool>) -> Result<()> {
- self.check_defaults_len(defaults.len())?;
- self.defaults = defaults.into_iter().map(|v| PropertyValue::Bool(v)).collect();
- Ok(())
- }
- pub fn set_defaults_u32(&mut self, defaults: Vec<u32>) -> Result<()> {
- self.check_defaults_len(defaults.len())?;
- self.defaults = defaults.into_iter().map(|v| PropertyValue::Uint32(v)).collect();
- Ok(())
- }
- pub fn set_defaults_f32(&mut self, defaults: Vec<f32>) -> Result<()> {
- self.check_defaults_len(defaults.len())?;
- self.defaults = defaults.into_iter().map(|v| PropertyValue::Float32(v)).collect();
- Ok(())
- }
- pub fn set_defaults_str(&mut self, defaults: Vec<String>) -> Result<()> {
- self.check_defaults_len(defaults.len())?;
- self.defaults = defaults.into_iter().map(|v| PropertyValue::Str(v)).collect();
- Ok(())
- }
- pub fn set_defaults_null(&mut self) -> Result<()> {
- if !self.is_null_allowed {
- return Err(Error::PropertyNullNotAllowed)
- }
- if !self.is_bounded() {
- return Err(Error::PropertyWrongLen)
- }
- self.defaults = (0..self.array_len).map(|_| PropertyValue::Null).collect();
- Ok(())
- }
- // Set
- /// This will clear all values, resetting them to the default
- pub fn clear_values(self: &Arc<Self>, atom: &mut PropertyAtomicGuard, role: Role) {
- {
- let vals = &mut self.vals.lock().unwrap();
- vals.clear();
- vals.resize(self.array_len, PropertyValue::Unset);
- }
- atom.add(self.clone(), role, ModifyAction::Clear);
- }
- fn set_raw_value(&self, i: usize, val: PropertyValue) -> Result<()> {
- if self.typ != val.as_type() {
- return Err(Error::PropertyWrongType)
- }
- let vals = &mut self.vals.lock().unwrap();
- if i >= vals.len() {
- return Err(Error::PropertyWrongIndex)
- }
- vals[i] = val;
- Ok(())
- }
- pub fn unset(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- i: usize,
- ) -> Result<()> {
- {
- let vals = &mut self.vals.lock().unwrap();
- if i >= vals.len() {
- return Err(Error::PropertyWrongIndex)
- }
- vals[i] = PropertyValue::Unset;
- }
- atom.add(self.clone(), role, ModifyAction::Unset(i));
- Ok(())
- }
- pub fn set_null(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- i: usize,
- ) -> Result<()> {
- if !self.is_null_allowed {
- return Err(Error::PropertyNullNotAllowed)
- }
- let mut vals = self.vals.lock().unwrap();
- if i >= vals.len() {
- return Err(Error::PropertyWrongIndex)
- }
- vals[i] = PropertyValue::Null;
- drop(vals);
- atom.add(self.clone(), role, ModifyAction::Set(i));
- Ok(())
- }
- pub fn set_bool(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- i: usize,
- val: bool,
- ) -> Result<()> {
- self.set_raw_value(i, PropertyValue::Bool(val))?;
- atom.add(self.clone(), role, ModifyAction::Set(i));
- Ok(())
- }
- pub fn set_u32(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- i: usize,
- val: u32,
- ) -> Result<()> {
- if self.min_val.is_some() {
- let min = self.min_val.as_ref().unwrap().as_u32()?;
- if val < min {
- return Err(Error::PropertyOutOfRange)
- }
- }
- if self.max_val.is_some() {
- let max = self.max_val.as_ref().unwrap().as_u32()?;
- if val > max {
- return Err(Error::PropertyOutOfRange)
- }
- }
- self.set_raw_value(i, PropertyValue::Uint32(val))?;
- atom.add(self.clone(), role, ModifyAction::Set(i));
- Ok(())
- }
- pub fn set_f32(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- i: usize,
- val: f32,
- ) -> Result<()> {
- if self.min_val.is_some() {
- let min = self.min_val.as_ref().unwrap().as_f32()?;
- if val < min {
- return Err(Error::PropertyOutOfRange)
- }
- }
- if self.max_val.is_some() {
- let max = self.max_val.as_ref().unwrap().as_f32()?;
- if val > max {
- return Err(Error::PropertyOutOfRange)
- }
- }
- self.set_raw_value(i, PropertyValue::Float32(val))?;
- atom.add(self.clone(), role, ModifyAction::Set(i));
- Ok(())
- }
- pub fn set_str<S: Into<String>>(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- i: usize,
- val: S,
- ) -> Result<()> {
- self.set_raw_value(i, PropertyValue::Str(val.into()))?;
- atom.add(self.clone(), role, ModifyAction::Set(i));
- Ok(())
- }
- pub fn set_enum<S: Into<String>>(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- i: usize,
- val: S,
- ) -> Result<()> {
- if self.typ != PropertyType::Enum {
- return Err(Error::PropertyWrongType)
- }
- let val = val.into();
- if !self.enum_items.as_ref().unwrap().contains(&val) {
- return Err(Error::PropertyWrongEnumItem)
- }
- self.set_raw_value(i, PropertyValue::Enum(val.into()))?;
- atom.add(self.clone(), role, ModifyAction::Set(i));
- Ok(())
- }
- pub fn set_node_id(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- i: usize,
- val: SceneNodeId,
- ) -> Result<()> {
- self.set_raw_value(i, PropertyValue::SceneNodeId(val))?;
- atom.add(self.clone(), role, ModifyAction::Set(i));
- Ok(())
- }
- pub fn set_expr(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- i: usize,
- val: SExprCode,
- ) -> Result<()> {
- {
- if !self.is_expr_allowed {
- return Err(Error::PropertySExprNotAllowed)
- }
- let vals = &mut self.vals.lock().unwrap();
- if i >= vals.len() {
- return Err(Error::PropertyWrongIndex)
- }
- vals[i] = PropertyValue::SExpr(Arc::new(val));
- }
- atom.add(self.clone(), role, ModifyAction::Set(i));
- Ok(())
- }
- fn set_value_vec<T, F>(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- val: Vec<T>,
- f: F,
- ) -> Result<()>
- where
- F: Fn(T) -> PropertyValue,
- {
- if self.is_bounded() {
- return Err(Error::PropertyIsBounded)
- }
- {
- let mut vals = self.vals.lock().unwrap();
- vals.clear();
- vals.extend(val.into_iter().map(f));
- }
- atom.add(self.clone(), role, ModifyAction::SetVec);
- Ok(())
- }
- pub fn set_bool_vec(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- val: Vec<bool>,
- ) -> Result<()> {
- self.set_value_vec(atom, role, val, PropertyValue::Bool)
- }
- pub fn set_u32_vec(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- val: Vec<u32>,
- ) -> Result<()> {
- self.set_value_vec(atom, role, val, PropertyValue::Uint32)
- }
- pub fn set_f32_vec(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- val: Vec<f32>,
- ) -> Result<()> {
- self.set_value_vec(atom, role, val, PropertyValue::Float32)
- }
- pub fn set_str_vec<S: Into<String>>(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- val: Vec<S>,
- ) -> Result<()> {
- self.set_value_vec(atom, role, val, |v| PropertyValue::Str(v.into()))
- }
- pub fn set_enum_vec<S: Into<String>>(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- val: Vec<S>,
- ) -> Result<()> {
- if self.typ != PropertyType::Enum {
- return Err(Error::PropertyWrongType)
- }
- self.set_value_vec(atom, role, val, |v| PropertyValue::Enum(v.into()))
- }
- pub fn set_node_id_vec(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- val: Vec<SceneNodeId>,
- ) -> Result<()> {
- self.set_value_vec(atom, role, val, PropertyValue::SceneNodeId)
- }
- fn set_cache(&self, i: usize, val: PropertyValue) -> Result<()> {
- if self.typ != val.as_type() {
- return Err(Error::PropertyWrongType)
- }
- let cache = &mut self.cache.lock().unwrap();
- if i >= cache.len() {
- return Err(Error::PropertyWrongIndex)
- }
- cache[i] = val;
- Ok(())
- }
- pub fn set_cache_f32(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- i: usize,
- val: f32,
- ) -> Result<()> {
- self.set_cache(i, PropertyValue::Float32(val))?;
- atom.add(self.clone(), role, ModifyAction::SetCache(vec![i]));
- Ok(())
- }
- pub fn set_cache_u32(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- i: usize,
- val: u32,
- ) -> Result<()> {
- self.set_cache(i, PropertyValue::Uint32(val))?;
- atom.add(self.clone(), role, ModifyAction::SetCache(vec![i]));
- Ok(())
- }
- pub fn set_cache_f32_multi(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- changes: Vec<(usize, f32)>,
- ) -> Result<()> {
- let mut idxs = vec![];
- for (idx, val) in changes {
- self.set_cache(idx, PropertyValue::Float32(val))?;
- idxs.push(idx);
- }
- atom.add(self.clone(), role, ModifyAction::SetCache(idxs));
- Ok(())
- }
- pub fn set_cache_u32_range(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- changes: Vec<(usize, u32)>,
- ) -> Result<()> {
- let mut idxs = vec![];
- for (idx, val) in changes {
- self.set_cache(idx, PropertyValue::Uint32(val))?;
- idxs.push(idx);
- }
- atom.add(self.clone(), role, ModifyAction::SetCache(idxs));
- Ok(())
- }
- // Push
- fn push_value(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- value: PropertyValue,
- ) -> Result<usize> {
- if self.is_bounded() {
- return Err(Error::PropertyIsBounded)
- }
- let mut vals = self.vals.lock().unwrap();
- let i = vals.len();
- vals.push(value);
- drop(vals);
- atom.add(self.clone(), role, ModifyAction::Push(i));
- Ok(i)
- }
- pub fn push_null(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- ) -> Result<usize> {
- self.push_value(atom, role, PropertyValue::Null)
- }
- pub fn push_bool(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- val: bool,
- ) -> Result<usize> {
- self.push_value(atom, role, PropertyValue::Bool(val))
- }
- pub fn push_u32(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- val: u32,
- ) -> Result<usize> {
- // TODO: none of these push calls are enforcing constraints that are required
- // see the set_XX calls.
- self.push_value(atom, role, PropertyValue::Uint32(val))
- }
- pub fn push_f32(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- val: f32,
- ) -> Result<usize> {
- self.push_value(atom, role, PropertyValue::Float32(val))
- }
- pub fn push_str<S: Into<String>>(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- val: S,
- ) -> Result<usize> {
- self.push_value(atom, role, PropertyValue::Str(val.into()))
- }
- pub fn push_enum<S: Into<String>>(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- val: S,
- ) -> Result<usize> {
- self.push_value(atom, role, PropertyValue::Enum(val.into()))
- }
- pub fn push_node_id(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- val: SceneNodeId,
- ) -> Result<usize> {
- self.push_value(atom, role, PropertyValue::SceneNodeId(val))
- }
- // Insert
- fn insert_value(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- index: usize,
- value: PropertyValue,
- ) -> Result<usize> {
- if self.is_bounded() {
- return Err(Error::PropertyIsBounded)
- }
- if index > self.get_len() {
- return Err(Error::PropertyWrongIndex)
- }
- let mut vals = self.vals.lock().unwrap();
- vals.insert(index, value);
- drop(vals);
- atom.add(self.clone(), role, ModifyAction::Insert(index));
- Ok(index)
- }
- pub fn insert_null(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- index: usize,
- ) -> Result<usize> {
- self.insert_value(atom, role, index, PropertyValue::Null)
- }
- pub fn insert_bool(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- index: usize,
- val: bool,
- ) -> Result<usize> {
- self.insert_value(atom, role, index, PropertyValue::Bool(val))
- }
- pub fn insert_u32(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- index: usize,
- val: u32,
- ) -> Result<usize> {
- self.insert_value(atom, role, index, PropertyValue::Uint32(val))
- }
- pub fn insert_f32(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- index: usize,
- val: f32,
- ) -> Result<usize> {
- self.insert_value(atom, role, index, PropertyValue::Float32(val))
- }
- pub fn insert_str<S: Into<String>>(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- index: usize,
- val: S,
- ) -> Result<usize> {
- self.insert_value(atom, role, index, PropertyValue::Str(val.into()))
- }
- pub fn insert_enum<S: Into<String>>(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- index: usize,
- val: S,
- ) -> Result<usize> {
- self.insert_value(atom, role, index, PropertyValue::Enum(val.into()))
- }
- pub fn insert_node_id(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- index: usize,
- val: SceneNodeId,
- ) -> Result<usize> {
- self.insert_value(atom, role, index, PropertyValue::SceneNodeId(val))
- }
- // Remove
- fn remove_value(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- index: usize,
- ) -> Result<PropertyValue> {
- if self.is_bounded() {
- return Err(Error::PropertyIsBounded)
- }
- if index >= self.get_len() {
- return Err(Error::PropertyWrongIndex)
- }
- let mut vals = self.vals.lock().unwrap();
- let value = vals.remove(index);
- drop(vals);
- atom.add(self.clone(), role, ModifyAction::Remove(index, value.clone()));
- Ok(value)
- }
- pub fn remove_null(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- index: usize,
- ) -> Result<()> {
- self.remove_value(atom, role, index)?;
- Ok(())
- }
- pub fn remove_bool(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- index: usize,
- ) -> Result<bool> {
- match self.remove_value(atom, role, index)? {
- PropertyValue::Bool(v) => Ok(v),
- _ => Err(Error::PropertyWrongType),
- }
- }
- pub fn remove_u32(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- index: usize,
- ) -> Result<u32> {
- match self.remove_value(atom, role, index)? {
- PropertyValue::Uint32(v) => Ok(v),
- _ => Err(Error::PropertyWrongType),
- }
- }
- pub fn remove_f32(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- index: usize,
- ) -> Result<f32> {
- match self.remove_value(atom, role, index)? {
- PropertyValue::Float32(v) => Ok(v),
- _ => Err(Error::PropertyWrongType),
- }
- }
- pub fn remove_str(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- index: usize,
- ) -> Result<String> {
- match self.remove_value(atom, role, index)? {
- PropertyValue::Str(v) => Ok(v),
- _ => Err(Error::PropertyWrongType),
- }
- }
- pub fn remove_enum(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- index: usize,
- ) -> Result<String> {
- match self.remove_value(atom, role, index)? {
- PropertyValue::Enum(v) => Ok(v),
- _ => Err(Error::PropertyWrongType),
- }
- }
- pub fn remove_node_id(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- index: usize,
- ) -> Result<SceneNodeId> {
- match self.remove_value(atom, role, index)? {
- PropertyValue::SceneNodeId(v) => Ok(v),
- _ => Err(Error::PropertyWrongType),
- }
- }
- // Remove by item
- pub fn remove_str_item(
- self: &Arc<Self>,
- atom: &mut PropertyAtomicGuard,
- role: Role,
- item: &str,
- ) -> Option<usize> {
- for i in 0..self.get_len() {
- if self.get_str(i).unwrap() == item {
- self.remove_str(atom, role, i).unwrap();
- return Some(i)
- }
- }
- None
- }
- // Get
- pub fn is_bounded(&self) -> bool {
- self.array_len != 0
- }
- pub fn get_len(&self) -> usize {
- // Avoid locking unless we need to
- // If array len is nonzero, then vals len should be the same.
- if !self.is_bounded() {
- return self.vals.lock().unwrap().len()
- }
- self.array_len
- }
- pub fn is_unset(&self, i: usize) -> Result<bool> {
- let val = self.get_raw_value(i)?;
- Ok(val.is_unset())
- }
- pub fn is_null(&self, i: usize) -> Result<bool> {
- let val = self.get_value(i)?;
- if val.is_unset() {
- return Ok(self.defaults[i].is_null())
- }
- Ok(val.is_null())
- }
- pub fn is_expr(&self, i: usize) -> Result<bool> {
- if !self.is_expr_allowed {
- return Ok(false)
- }
- let val = self.get_raw_value(i)?;
- Ok(val.is_expr())
- }
- pub fn get_raw_value(&self, i: usize) -> Result<PropertyValue> {
- let vals = &self.vals.lock().unwrap();
- if self.is_bounded() {
- assert_eq!(vals.len(), self.array_len);
- }
- if i >= vals.len() {
- return Err(Error::PropertyWrongIndex)
- }
- let val = vals[i].clone();
- Ok(val)
- }
- pub fn get_value(&self, i: usize) -> Result<PropertyValue> {
- let val = self.get_raw_value(i)?;
- if val.is_expr() {
- let cached = self.get_cached(i)?;
- if cached.is_null() {
- return Ok(self.defaults[i].clone())
- }
- return Ok(cached)
- }
- if val.is_unset() {
- return Ok(self.defaults[i].clone())
- }
- Ok(val)
- }
- pub fn get_bool(&self, i: usize) -> Result<bool> {
- self.get_value(i)?.as_bool()
- }
- pub fn get_bool_opt(&self, i: usize) -> Result<Option<bool>> {
- let val = self.get_value(i)?;
- if val.is_null() {
- return Ok(None)
- }
- Ok(Some(val.as_bool()?))
- }
- pub fn get_u32(&self, i: usize) -> Result<u32> {
- self.get_value(i)?.as_u32()
- }
- pub fn get_u32_opt(&self, i: usize) -> Result<Option<u32>> {
- let val = self.get_value(i)?;
- if val.is_null() {
- return Ok(None)
- }
- Ok(Some(val.as_u32()?))
- }
- pub fn get_f32(&self, i: usize) -> Result<f32> {
- self.get_value(i)?.as_f32()
- }
- pub fn get_f32_opt(&self, i: usize) -> Result<Option<f32>> {
- let val = self.get_value(i)?;
- if val.is_null() {
- return Ok(None)
- }
- Ok(Some(val.as_f32()?))
- }
- pub fn get_str(&self, i: usize) -> Result<String> {
- self.get_value(i)?.as_str()
- }
- pub fn get_str_opt(&self, i: usize) -> Result<Option<String>> {
- let val = self.get_value(i)?;
- if val.is_null() {
- return Ok(None)
- }
- Ok(Some(val.as_str()?))
- }
- pub fn get_enum(&self, i: usize) -> Result<String> {
- self.get_value(i)?.as_enum()
- }
- pub fn get_enum_opt(&self, i: usize) -> Result<Option<String>> {
- let val = self.get_value(i)?;
- if val.is_null() {
- return Ok(None)
- }
- Ok(Some(val.as_enum()?))
- }
- pub fn get_node_id(&self, i: usize) -> Result<SceneNodeId> {
- self.get_value(i)?.as_node_id()
- }
- pub fn get_node_id_opt(&self, i: usize) -> Result<Option<SceneNodeId>> {
- let val = self.get_value(i)?;
- if val.is_null() {
- return Ok(None)
- }
- Ok(Some(val.as_node_id()?))
- }
- pub fn get_expr(&self, i: usize) -> Result<Arc<SExprCode>> {
- self.get_raw_value(i)?.as_sexpr()
- }
- pub fn get_cached(&self, i: usize) -> Result<PropertyValue> {
- let cache = &self.cache.lock().unwrap();
- if self.is_bounded() {
- assert_eq!(cache.len(), self.array_len);
- }
- if i >= cache.len() {
- return Err(Error::PropertyWrongIndex)
- }
- Ok(cache[i].clone())
- }
- fn get_value_vec<T, F>(&self, f: F) -> Result<Vec<T>>
- where
- F: Fn(&PropertyValue) -> Option<T>,
- {
- if self.is_bounded() {
- return Err(Error::PropertyIsBounded)
- }
- let vals = self.vals.lock().unwrap();
- let mut result = Vec::with_capacity(vals.len());
- for val in vals.iter() {
- match f(val) {
- Some(v) => result.push(v),
- None => return Err(Error::PropertyWrongType),
- }
- }
- Ok(result)
- }
- pub fn get_bool_vec(&self) -> Result<Vec<bool>> {
- self.get_value_vec(|val| match val {
- PropertyValue::Bool(v) => Some(*v),
- _ => None,
- })
- }
- pub fn get_u32_vec(&self) -> Result<Vec<u32>> {
- self.get_value_vec(|val| match val {
- PropertyValue::Uint32(v) => Some(*v),
- _ => None,
- })
- }
- pub fn get_f32_vec(&self) -> Result<Vec<f32>> {
- self.get_value_vec(|val| match val {
- PropertyValue::Float32(v) => Some(*v),
- _ => None,
- })
- }
- pub fn get_str_vec(&self) -> Result<Vec<String>> {
- self.get_value_vec(|val| match val {
- PropertyValue::Str(v) => Some(v.clone()),
- _ => None,
- })
- }
- pub fn get_enum_vec(&self) -> Result<Vec<String>> {
- self.get_value_vec(|val| match val {
- PropertyValue::Enum(v) => Some(v.clone()),
- _ => None,
- })
- }
- pub fn get_node_id_vec(&self) -> Result<Vec<SceneNodeId>> {
- self.get_value_vec(|val| match val {
- PropertyValue::SceneNodeId(v) => Some(*v),
- _ => None,
- })
- }
- // Contains
- pub fn contains_str(&self, s: &str) -> bool {
- for i in 0..self.get_len() {
- if let Ok(item) = self.get_str(i) {
- if item == s {
- return true
- }
- }
- }
- false
- }
- // Subs
- pub fn subscribe_modify(&self) -> Subscription<(Role, ModifyAction, BatchGuardPtr)> {
- self.on_modify.clone().subscribe()
- }
- // Dependencies
- pub fn add_depend<S: Into<String>>(&self, prop: &PropertyPtr, i: usize, local_name: S) {
- self.depends.lock().unwrap().push(PropertyDepend {
- prop: Arc::downgrade(prop),
- i,
- local_name: local_name.into(),
- });
- }
- pub fn get_depends(&self) -> Vec<PropertyDepend> {
- self.depends.lock().unwrap().clone()
- }
- }
- impl std::fmt::Debug for Property {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let node = {
- let mut null_name = || write!(f, "<null>:{}", self.name);
- let Ok(node) = self.node.lock() else { return null_name() };
- let Some(node) = node.clone() else { return null_name() };
- let Some(node) = node.upgrade() else { return null_name() };
- node
- };
- write!(f, "{:?}:{}", node, self.name)
- }
- }
- #[cfg(test)]
- mod tests {
- use super::*;
- use crate::expr::Op;
- #[test]
- fn test_getset() {
- let prop = Arc::new(Property::new("foo", PropertyType::Float32, PropertySubType::Null));
- let atom = &mut PropertyAtomicGuard::none();
- assert!(prop.set_f32(atom, Role::App, 1, 4.).is_err());
- assert!(prop.is_unset(0).unwrap());
- assert!(prop.set_f32(atom, Role::App, 0, 4.).is_ok());
- assert_eq!(prop.get_f32(0).unwrap(), 4.);
- assert!(!prop.is_unset(0).unwrap());
- prop.unset(atom, Role::App, 0).unwrap();
- assert!(prop.is_unset(0).unwrap());
- assert_eq!(prop.get_f32(0).unwrap(), 0.);
- }
- #[test]
- fn test_nullable() {
- // default len is 1
- let mut prop_temp = Property::new("foo", PropertyType::Float32, PropertySubType::Null);
- assert!(prop_temp.set_defaults_f32(vec![1.0, 0.0]).is_err());
- assert!(prop_temp.set_defaults_f32(vec![2.0]).is_ok());
- prop_temp.allow_null_values();
- let prop = Arc::new(prop_temp);
- let atom = &mut PropertyAtomicGuard::none();
- prop.set_null(atom, Role::App, 0).unwrap();
- assert!(prop.get_f32_opt(1).is_err());
- assert!(prop.get_f32_opt(0).is_ok());
- assert!(prop.get_f32_opt(0).unwrap().is_none());
- prop.clear_values(atom, Role::App);
- assert!(prop.get_f32(0).is_ok());
- assert!(prop.get_f32_opt(0).unwrap().is_some());
- assert_eq!(prop.get_f32(0).unwrap(), 2.0);
- }
- #[test]
- fn test_nonnullable() {
- let prop = Arc::new(Property::new("foo", PropertyType::Float32, PropertySubType::Null));
- let atom = &mut PropertyAtomicGuard::none();
- assert!(prop.set_null(atom, Role::App, 0).is_err());
- assert!(prop.is_unset(0).unwrap());
- }
- #[test]
- fn test_unbounded() {
- let mut prop_temp = Property::new("foo", PropertyType::Float32, PropertySubType::Null);
- prop_temp.set_unbounded();
- prop_temp.allow_null_values();
- let prop = Arc::new(prop_temp);
- let atom = &mut PropertyAtomicGuard::none();
- assert_eq!(prop.get_len(), 0);
- prop.push_f32(atom, Role::App, 2.0).unwrap();
- prop.push_f32(atom, Role::App, 3.0).unwrap();
- assert_eq!(prop.get_len(), 2);
- prop.clear_values(atom, Role::App);
- assert_eq!(prop.get_len(), 0);
- prop.push_null(atom, Role::App).unwrap();
- prop.push_f32(atom, Role::App, 4.0).unwrap();
- prop.push_f32(atom, Role::App, 5.0).unwrap();
- assert_eq!(prop.get_len(), 3);
- assert!(prop.get_f32_opt(0).unwrap().is_none());
- assert!(prop.get_f32_opt(1).unwrap().is_some());
- assert!(prop.get_f32_opt(2).unwrap().is_some());
- assert!(prop.get_f32_opt(3).is_err());
- let prop2 = Arc::new(Property::new("foo", PropertyType::Float32, PropertySubType::Null));
- let atom2 = &mut PropertyAtomicGuard::none();
- assert!(prop2.push_f32(atom2, Role::App, 4.0).is_err());
- }
- #[test]
- fn test_range() {
- let mut prop_temp = Property::new("foo", PropertyType::Float32, PropertySubType::Null);
- let half_pi = 3.1415926535 / 2.;
- prop_temp.set_range_f32(-half_pi, half_pi);
- let prop = Arc::new(prop_temp);
- let atom = &mut PropertyAtomicGuard::none();
- assert!(prop.set_f32(atom, Role::App, 0, 6.).is_err());
- assert!(prop.set_f32(atom, Role::App, 0, 1.).is_ok());
- }
- #[test]
- fn test_enum() {
- let mut prop_temp = Property::new("foo", PropertyType::Enum, PropertySubType::Null);
- prop_temp.set_enum_items(vec!["ABC", "XYZ", "FOO"]).unwrap();
- let prop = Arc::new(prop_temp);
- let atom = &mut PropertyAtomicGuard::none();
- assert!(prop.set_enum(atom, Role::App, 0, "ABC").is_ok());
- assert!(prop.set_enum(atom, Role::App, 0, "BAR").is_err());
- }
- #[test]
- fn test_expr() {
- let mut prop_temp = Property::new("foo", PropertyType::Float32, PropertySubType::Null);
- prop_temp.allow_exprs();
- let prop = Arc::new(prop_temp);
- let atom = &mut PropertyAtomicGuard::none();
- assert_eq!(prop.get_f32(0).unwrap(), 0.);
- let code = vec![Op::ConstFloat32(4.)];
- prop.set_expr(atom, Role::App, 0, code).unwrap();
- let val = prop.get_cached(0).unwrap();
- assert!(val.is_null());
- prop.set_cache_f32(atom, Role::App, 0, 4.).unwrap();
- let val = prop.get_cached(0).unwrap();
- assert_eq!(val.as_f32().unwrap(), 4.);
- }
- fn setup_test_property() -> Arc<Property> {
- let mut prop_temp = Property::new("test", PropertyType::Str, PropertySubType::Null);
- prop_temp.set_unbounded();
- let prop = Arc::new(prop_temp);
- let atom = &mut PropertyAtomicGuard::none();
- prop.push_str(atom, Role::Internal, "Item 1").unwrap();
- prop.push_str(atom, Role::Internal, "Item 2").unwrap();
- prop.push_str(atom, Role::Internal, "Item 3").unwrap();
- prop
- }
- #[test]
- fn test_insert_at_beginning() {
- let prop = setup_test_property();
- let atom = &mut PropertyAtomicGuard::none();
- prop.insert_str(atom, Role::App, 0, "NEW").unwrap();
- assert_eq!(prop.get_len(), 4);
- assert_eq!(prop.get_str(0).unwrap(), "NEW");
- assert_eq!(prop.get_str(1).unwrap(), "Item 1");
- assert_eq!(prop.get_str(2).unwrap(), "Item 2");
- assert_eq!(prop.get_str(3).unwrap(), "Item 3");
- }
- #[test]
- fn test_insert_at_end() {
- let prop = setup_test_property();
- let atom = &mut PropertyAtomicGuard::none();
- prop.insert_str(atom, Role::App, 3, "NEW").unwrap();
- assert_eq!(prop.get_len(), 4);
- assert_eq!(prop.get_str(0).unwrap(), "Item 1");
- assert_eq!(prop.get_str(1).unwrap(), "Item 2");
- assert_eq!(prop.get_str(2).unwrap(), "Item 3");
- assert_eq!(prop.get_str(3).unwrap(), "NEW");
- }
- #[test]
- fn test_insert_in_middle() {
- let prop = setup_test_property();
- let atom = &mut PropertyAtomicGuard::none();
- prop.insert_str(atom, Role::App, 1, "NEW").unwrap();
- assert_eq!(prop.get_len(), 4);
- assert_eq!(prop.get_str(0).unwrap(), "Item 1");
- assert_eq!(prop.get_str(1).unwrap(), "NEW");
- assert_eq!(prop.get_str(2).unwrap(), "Item 2");
- assert_eq!(prop.get_str(3).unwrap(), "Item 3");
- }
- #[test]
- fn test_insert_bounded_fails() {
- let mut prop_temp = Property::new("test", PropertyType::Str, PropertySubType::Null);
- prop_temp.set_array_len(3);
- let prop = Arc::new(prop_temp);
- let atom = &mut PropertyAtomicGuard::none();
- let result = prop.insert_str(atom, Role::App, 0, "NEW");
- assert!(matches!(result, Err(Error::PropertyIsBounded)));
- }
- #[test]
- fn test_insert_out_of_bounds_fails() {
- let prop = setup_test_property();
- let atom = &mut PropertyAtomicGuard::none();
- let result = prop.insert_str(atom, Role::App, 10, "NEW");
- assert!(matches!(result, Err(Error::PropertyWrongIndex)));
- }
- #[test]
- fn test_remove_from_beginning() {
- let prop = setup_test_property();
- let atom = &mut PropertyAtomicGuard::none();
- let removed = prop.remove_str(atom, Role::App, 0).unwrap();
- assert_eq!(removed, "Item 1");
- assert_eq!(prop.get_len(), 2);
- assert_eq!(prop.get_str(0).unwrap(), "Item 2");
- assert_eq!(prop.get_str(1).unwrap(), "Item 3");
- }
- #[test]
- fn test_remove_from_end() {
- let prop = setup_test_property();
- let atom = &mut PropertyAtomicGuard::none();
- let removed = prop.remove_str(atom, Role::App, 2).unwrap();
- assert_eq!(removed, "Item 3");
- assert_eq!(prop.get_len(), 2);
- assert_eq!(prop.get_str(0).unwrap(), "Item 1");
- assert_eq!(prop.get_str(1).unwrap(), "Item 2");
- }
- #[test]
- fn test_remove_from_middle() {
- let prop = setup_test_property();
- let atom = &mut PropertyAtomicGuard::none();
- let removed = prop.remove_str(atom, Role::App, 1).unwrap();
- assert_eq!(removed, "Item 2");
- assert_eq!(prop.get_len(), 2);
- assert_eq!(prop.get_str(0).unwrap(), "Item 1");
- assert_eq!(prop.get_str(1).unwrap(), "Item 3");
- }
- #[test]
- fn test_remove_bounded_fails() {
- let mut prop_temp = Property::new("test", PropertyType::Str, PropertySubType::Null);
- prop_temp.set_array_len(3);
- let prop = Arc::new(prop_temp);
- let atom = &mut PropertyAtomicGuard::none();
- let result = prop.remove_str(atom, Role::App, 0);
- assert!(matches!(result, Err(Error::PropertyIsBounded)));
- }
- #[test]
- fn test_remove_out_of_bounds_fails() {
- let prop = setup_test_property();
- let atom = &mut PropertyAtomicGuard::none();
- let result = prop.remove_str(atom, Role::App, 10);
- assert!(matches!(result, Err(Error::PropertyWrongIndex)));
- }
- #[test]
- fn test_insert_remove_mixed_types() {
- let mut prop_temp = Property::new("test", PropertyType::Float32, PropertySubType::Null);
- prop_temp.set_unbounded();
- let prop = Arc::new(prop_temp);
- let atom = &mut PropertyAtomicGuard::none();
- prop.push_f32(atom, Role::App, 1.0).unwrap();
- prop.push_f32(atom, Role::App, 3.0).unwrap();
- prop.insert_f32(atom, Role::App, 1, 2.0).unwrap();
- assert_eq!(prop.get_f32(0).unwrap(), 1.0);
- assert_eq!(prop.get_f32(1).unwrap(), 2.0);
- assert_eq!(prop.get_f32(2).unwrap(), 3.0);
- let removed = prop.remove_f32(atom, Role::App, 1).unwrap();
- assert_eq!(removed, 2.0);
- assert_eq!(prop.get_len(), 2);
- assert_eq!(prop.get_f32(0).unwrap(), 1.0);
- assert_eq!(prop.get_f32(1).unwrap(), 3.0);
- }
- }
|