1use std::{
2 cell::RefCell,
3 collections::HashMap,
4 fmt::Debug,
5 hash::{Hash, Hasher},
6 rc::Rc,
7};
8
9use crate::{errors::OutOfRangeError, BehaviourPtr, Named, UUIDd};
10use anyhow::Result;
11use by_address::ByAddress;
12use uuid::Uuid;
13
14pub type BeliefPtr = ByAddress<Rc<RefCell<dyn Belief>>>;
16
17impl From<BasicBelief> for BeliefPtr {
18 fn from(b: BasicBelief) -> Self {
43 ByAddress(Rc::new(RefCell::new(b)))
44 }
45}
46
47pub trait Belief: Named + UUIDd {
49 fn get_perception(&self, behaviour: &BehaviourPtr) -> Option<f64>;
62
63 fn set_perception(
80 &mut self,
81 behaviour: BehaviourPtr,
82 perception: Option<f64>,
83 ) -> Result<(), OutOfRangeError>;
84
85 fn get_relationship(&self, belief: &BeliefPtr) -> Option<f64>;
99
100 fn set_relationship(
118 &mut self,
119 belief: BeliefPtr,
120 relationship: Option<f64>,
121 ) -> Result<(), OutOfRangeError>;
122}
123
124#[derive(Clone)]
126pub struct BasicBelief {
127 name: String,
128 uuid: Uuid,
129 perception: HashMap<BehaviourPtr, f64>,
130 relationship: HashMap<BeliefPtr, f64>,
131}
132
133impl Debug for BasicBelief {
134 #[cfg(not(tarpaulin_include))]
135 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136 f.debug_struct("BasicBelief")
137 .field("name", &self.name)
138 .field("uuid", &self.uuid)
139 .finish()
140 }
141}
142
143impl BasicBelief {
144 pub fn new(name: String) -> Self {
161 Self::new_with_uuid(name, Uuid::new_v4())
162 }
163
164 pub fn new_with_uuid(name: String, uuid: Uuid) -> Self {
182 Self {
183 name,
184 uuid,
185 perception: HashMap::new(),
186 relationship: HashMap::new(),
187 }
188 }
189}
190
191impl Belief for BasicBelief {
192 fn get_perception(&self, behaviour: &BehaviourPtr) -> Option<f64> {
216 self.perception.get(behaviour).cloned()
217 }
218
219 fn set_perception(
247 &mut self,
248 behaviour: BehaviourPtr,
249 perception: Option<f64>,
250 ) -> Result<(), OutOfRangeError> {
251 match perception {
252 None => {
253 self.perception.remove(&behaviour);
254 Ok(())
255 }
256 Some(x) if x > 1.0 => Err(OutOfRangeError::TooHigh {
257 found: x,
258 min: -1.0,
259 max: 1.0,
260 }),
261 Some(x) if x < -1.0 => Err(OutOfRangeError::TooLow {
262 found: x,
263 min: -1.0,
264 max: 1.0,
265 }),
266 Some(x) => {
267 self.perception.insert(behaviour, x);
268 Ok(())
269 }
270 }
271 }
272
273 fn get_relationship(&self, belief: &BeliefPtr) -> Option<f64> {
299 self.relationship.get(belief).cloned()
300 }
301
302 fn set_relationship(
332 &mut self,
333 belief: BeliefPtr,
334 relationship: Option<f64>,
335 ) -> Result<(), OutOfRangeError> {
336 match relationship {
337 None => {
338 self.relationship.remove(&belief);
339 Ok(())
340 }
341 Some(x) if x > 1.0 => Err(OutOfRangeError::TooHigh {
342 found: x,
343 min: -1.0,
344 max: 1.0,
345 }),
346 Some(x) if x < -1.0 => Err(OutOfRangeError::TooLow {
347 found: x,
348 min: -1.0,
349 max: 1.0,
350 }),
351 Some(x) => {
352 self.relationship.insert(belief, x);
353 Ok(())
354 }
355 }
356 }
357}
358
359impl Named for BasicBelief {
360 fn name(&self) -> &str {
362 return &self.name;
363 }
364
365 fn set_name(&mut self, name: String) {
367 self.name = name;
368 }
369}
370
371impl UUIDd for BasicBelief {
372 fn uuid(&self) -> &Uuid {
374 return &self.uuid;
375 }
376
377 fn set_uuid(&mut self, u: Uuid) {
379 self.uuid = u;
380 }
381}
382
383impl PartialEq for BasicBelief {
384 fn eq(&self, other: &Self) -> bool {
386 self.uuid == other.uuid
387 }
388}
389
390impl Hash for BasicBelief {
391 fn hash<H: Hasher>(&self, state: &mut H) {
392 self.uuid.hash(state);
393 }
394}
395
396impl Eq for BasicBelief {}
397
398#[cfg(test)]
399mod tests {
400 use crate::BasicBehaviour;
401 use std::collections::hash_map::DefaultHasher;
402
403 use super::*;
404
405 #[test]
406 fn new_with_uuid_assigns_uuid() {
407 let uuid = Uuid::new_v4();
408 let b = BasicBelief::new_with_uuid("b".to_string(), uuid.clone());
409 assert_eq!(b.uuid(), &uuid);
410 }
411
412 #[test]
413 fn new_with_uuid_assigns_name() {
414 let b = BasicBelief::new_with_uuid("b".to_string(), Uuid::new_v4());
415 assert_eq!(b.name(), "b");
416 }
417
418 #[test]
419 fn new_assigns_random_uuid() {
420 let b1 = BasicBelief::new("b1".to_string());
421 let b2 = BasicBelief::new("b2".to_string());
422 assert_ne!(b1.uuid(), b2.uuid());
423 }
424
425 #[test]
426 fn new_assigns_name() {
427 let b = BasicBelief::new("b".to_string());
428 assert_eq!(b.name(), "b");
429 }
430
431 #[test]
432 fn name_returns_name() {
433 let b = BasicBelief::new("b".to_string());
434 assert_eq!(b.name(), "b");
435 }
436
437 #[test]
438 fn set_name_sets_name() {
439 let mut b = BasicBelief::new("b".to_string());
440 assert_eq!(b.name(), "b");
441 b.set_name("bnew".to_string());
442 assert_eq!(b.name(), "bnew");
443 }
444
445 #[test]
446 fn uuid_returns_uuid() {
447 let uuid = Uuid::new_v4();
448 let mut b = BasicBelief::new_with_uuid("b".to_string(), uuid.clone());
449 assert_eq!(b.uuid(), &uuid);
450 let uuid2 = Uuid::new_v4();
451 b.set_uuid(uuid2.clone());
452 assert_eq!(b.uuid(), &uuid2);
453 }
454
455 #[test]
456 fn set_when_valid_and_get_relationship_when_exists() {
457 let b = BasicBelief::new("belief".to_string());
458 let b_ptr: BeliefPtr = b.into();
459 assert!(!b_ptr
460 .borrow_mut()
461 .set_relationship(b_ptr.clone(), Some(0.2))
462 .is_err());
463 assert_eq!(b_ptr.borrow().get_relationship(&b_ptr).unwrap(), 0.2);
464 }
465
466 #[test]
467 fn get_relationship_when_not_exists() {
468 let b = BasicBelief::new("belief".to_string());
469 let b_ptr: BeliefPtr = b.into();
470 assert_eq!(b_ptr.borrow().get_relationship(&b_ptr.clone()), None);
471 }
472
473 #[test]
474 fn set_delete_when_valid_and_get_relationship_when_not_exists() {
475 let b = BasicBelief::new("belief".to_string());
476 let b_ptr: BeliefPtr = b.into();
477 assert!(!b_ptr
478 .borrow_mut()
479 .set_relationship(b_ptr.clone(), Some(0.2))
480 .is_err());
481 assert_eq!(b_ptr.borrow().get_relationship(&b_ptr).unwrap(), 0.2);
482 assert!(!b_ptr
483 .borrow_mut()
484 .set_relationship(b_ptr.clone(), None)
485 .is_err());
486 assert_eq!(b_ptr.borrow().get_relationship(&b_ptr), None);
487 }
488
489 #[test]
490 fn set_relationship_when_too_low() {
491 let b = BasicBelief::new("belief".to_string());
492 let b_ptr: BeliefPtr = b.into();
493 let res = b_ptr
494 .borrow_mut()
495 .set_relationship(b_ptr.clone(), Some(-1.1));
496 let expected_error = OutOfRangeError::TooLow {
497 found: -1.1,
498 min: -1.0,
499 max: 1.0,
500 };
501 assert_eq!(res.unwrap_err(), expected_error);
502 }
503
504 #[test]
505 fn set_relationship_when_too_high() {
506 let b = BasicBelief::new("belief".to_string());
507 let b_ptr: BeliefPtr = b.into();
508 let res = b_ptr
509 .borrow_mut()
510 .set_relationship(b_ptr.clone(), Some(1.1));
511 let expected_error = OutOfRangeError::TooHigh {
512 found: 1.1,
513 min: -1.0,
514 max: 1.0,
515 };
516 assert_eq!(res.unwrap_err(), expected_error);
517 }
518
519 #[test]
520 fn set_when_valid_and_get_perception_when_exists() {
521 let mut b = BasicBelief::new("belief".to_string());
522 let beh = BasicBehaviour::new("behaviour".to_string());
523 let beh_ptr: BehaviourPtr = beh.into();
524 assert!(!b.set_perception(beh_ptr.clone(), Some(0.1)).is_err());
525 assert_eq!(b.get_perception(&beh_ptr).unwrap(), 0.1);
526 }
527
528 #[test]
529 fn get_perception_when_not_exists() {
530 let b = BasicBelief::new("belief".to_string());
531 let beh = BasicBehaviour::new("behaviour".to_string());
532 let beh_ptr: BehaviourPtr = beh.into();
533 assert_eq!(b.get_perception(&beh_ptr), None);
534 }
535
536 #[test]
537 fn set_when_valid_delete_and_get_perception_when_not_exists() {
538 let mut b = BasicBelief::new("belief".to_string());
539 let beh = BasicBehaviour::new("behaviour".to_string());
540 let beh_ptr: BehaviourPtr = beh.into();
541 assert!(!b.set_perception(beh_ptr.clone(), Some(0.1)).is_err());
542 assert_eq!(b.get_perception(&beh_ptr).unwrap(), 0.1);
543 assert!(!b.set_perception(beh_ptr.clone(), None).is_err());
544 assert_eq!(b.get_perception(&beh_ptr), None);
545 }
546
547 #[test]
548 fn set_perception_when_too_low() {
549 let mut b = BasicBelief::new("belief".to_string());
550 let beh = BasicBehaviour::new("behaviour".to_string());
551 let beh_ptr: BehaviourPtr = beh.into();
552 let res = b.set_perception(beh_ptr.clone(), Some(-1.1));
553 let expected_error = OutOfRangeError::TooLow {
554 found: -1.1,
555 min: -1.0,
556 max: 1.0,
557 };
558 assert_eq!(res.unwrap_err(), expected_error);
559 }
560
561 #[test]
562 fn set_perception_when_too_high() {
563 let mut b = BasicBelief::new("belief".to_string());
564 let beh = BasicBehaviour::new("behaviour".to_string());
565 let beh_ptr: BehaviourPtr = beh.into();
566 let res = b.set_perception(beh_ptr.clone(), Some(1.1));
567 let expected_error = OutOfRangeError::TooHigh {
568 found: 1.1,
569 min: -1.0,
570 max: 1.0,
571 };
572
573 assert_eq!(res.unwrap_err(), expected_error);
574 }
575
576 #[test]
577 fn test_equals_when_uuids_match_but_name_doesnt() {
578 let uuid1 = Uuid::new_v4();
579 let b1 = BasicBelief::new_with_uuid("b1".to_string(), uuid1);
580 let b2 = BasicBelief::new_with_uuid("b2".to_string(), uuid1);
581 assert_eq!(b1, b2);
582 }
583
584 #[test]
585 fn test_equals_when_uuids_dont_match() {
586 let uuid1 = Uuid::new_v4();
587 let uuid2 = Uuid::new_v4();
588 let b1 = BasicBelief::new_with_uuid("b1".to_string(), uuid1);
589 let b2 = BasicBelief::new_with_uuid("b2".to_string(), uuid2);
590 assert_ne!(b1, b2);
591 }
592
593 #[test]
594 fn test_hash_when_uuids_match_but_name_doesnt() {
595 let uuid1 = Uuid::new_v4();
596 let b1 = BasicBelief::new_with_uuid("b1".to_string(), uuid1);
597 let b2 = BasicBelief::new_with_uuid("b2".to_string(), uuid1);
598 let mut hasher1 = DefaultHasher::new();
599 let mut hasher2 = DefaultHasher::new();
600 b1.hash(&mut hasher1);
601 b2.hash(&mut hasher2);
602 assert_eq!(hasher1.finish(), hasher2.finish());
603 }
604
605 #[test]
606 fn test_hash_when_uuids_dont_match() {
607 let uuid1 = Uuid::new_v4();
608 let uuid2 = Uuid::new_v4();
609 let b1 = BasicBelief::new_with_uuid("b1".to_string(), uuid1);
610 let b2 = BasicBelief::new_with_uuid("b2".to_string(), uuid2);
611 let mut hasher1 = DefaultHasher::new();
612 let mut hasher2 = DefaultHasher::new();
613 b1.hash(&mut hasher1);
614 b2.hash(&mut hasher2);
615 assert_ne!(hasher1.finish(), hasher2.finish());
616 }
617
618 #[test]
619 fn test_from() {
620 let b = BasicBelief::new("b1".to_string());
621 let b_ptr: BeliefPtr = BeliefPtr::from(b);
622 assert_eq!(b_ptr.borrow().name(), "b1");
623 }
624
625 #[test]
626 fn test_into() {
627 let b = BasicBelief::new("b1".to_string());
628 let b_ptr: BeliefPtr = b.into();
629 assert_eq!(b_ptr.borrow().name(), "b1");
630 }
631}