dvcompute/simulation/
ref_comp.rs

1// Copyright (c) 2020-2022  David Sorokin <davsor@mail.ru>, based in Yoshkar-Ola, Russia
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
7use std::cell::UnsafeCell;
8use std::ptr;
9
10use crate::simulation;
11use crate::simulation::point::Point;
12use crate::simulation::event::Event;
13
14use dvcompute_utils::grc::Grc;
15
16/// A mutable cell computation synchronized with the event queue.
17pub struct RefComp<T> {
18
19    /// The underlying cell.
20    cell: UnsafeCell<T>
21}
22
23impl<T> RefComp<T> {
24
25    /// Create a new mutable cell by the initial value.
26    #[inline]
27    pub fn new(val: T) -> RefComp<T> {
28        RefComp { cell: UnsafeCell::new(val) }
29    }
30
31    /// Read the contents of the mutable cell at the specified time point.
32    #[inline]
33    pub fn read_at(&self, _p: &Point) -> T
34        where T: Clone
35    {
36        let p = self.cell.get();
37        unsafe {
38            (*p).clone()
39        }
40    }
41
42    /// Read the contents of the mutable cell within the `Event` computation.
43    #[inline]
44    pub fn read(comp: Grc<Self>) -> Read<T>
45        where T: Clone
46    {
47        Read { comp: comp }
48    }
49
50    /// Swap the contents of the mutable cell at the specified time point.
51    #[inline]
52    pub fn swap_at(&self, val: T, _p: &Point) -> T {
53        let mut t = val;
54        unsafe {
55            ptr::swap(&mut t, self.cell.get());
56        }
57        t
58    }
59
60    /// Swap the contents of the mutable cell within the `Event` computation.
61    #[inline]
62    pub fn swap(comp: Grc<Self>, val: T) -> Swap<T> {
63        Swap { comp: comp, val: val }
64    }
65
66    /// Write into the contents of the mutable cell at the specified time point.
67    #[inline]
68    pub fn write_at(&self, val: T, _p: &Point) {
69        let p = self.cell.get();
70        unsafe {
71            *p = val;
72        }
73    }
74
75    /// Write into the contents of the mutable cell within the `Event` computation.
76    #[inline]
77    pub fn write(comp: Grc<Self>, val: T) -> Write<T> {
78        Write { comp: comp, val: val }
79    }
80
81    /// Mutate the contents of the mutable cell at the specified time point.
82    #[inline]
83    pub fn modify_at<F>(&self, f: F, _p: &Point)
84        where F: FnOnce(&T) -> T,
85              T: Clone
86    {
87        let p = self.cell.get();
88        unsafe {
89            let t = (*p).clone();
90            *p = f(&t);
91        }
92    }
93
94    /// Mutate the contents of the mutable cell within the `Event` computation.
95    #[inline]
96    pub fn modify<F>(comp: Grc<Self>, f: F) -> Modify<T, F>
97        where F: FnOnce(&T) -> T,
98              T: Clone
99    {
100        Modify { comp: comp, f: f }
101    }
102}
103
104impl<T> PartialEq for RefComp<T> {
105
106    fn eq(&self, other: &Self) -> bool {
107        self.cell.get() == other.cell.get()
108    }
109}
110
111impl<T> Eq for RefComp<T> {}
112
113impl<T: Clone> Clone for RefComp<T> {
114
115    fn clone(&self) -> Self {
116        let p = self.cell.get();
117        unsafe {
118            let val = (*p).clone();
119            RefComp { cell: UnsafeCell::new(val) }
120        }
121    }
122}
123
124/// It reads the contents of the mutable cell within the `Event` computation.
125#[must_use = "computations are lazy and do nothing unless to be run"]
126#[derive(Clone)]
127pub struct Read<T> where T: 'static {
128
129    /// The corresponding reference.
130    comp: Grc<RefComp<T>>
131}
132
133impl<T: Clone> Event for Read<T> {
134
135    type Item = T;
136
137    #[inline]
138    fn call_event(self, p: &Point) -> simulation::Result<Self::Item> {
139        let Read { comp } = self;
140        Result::Ok(comp.read_at(p))
141    }
142}
143
144/// It swaps the contents of the mutable cell within the `Event` computation.
145#[must_use = "computations are lazy and do nothing unless to be run"]
146#[derive(Clone)]
147pub struct Swap<T> where T: 'static {
148
149    /// The corresponding reference.
150    comp: Grc<RefComp<T>>,
151
152    /// A new value.
153    val: T
154}
155
156impl<T> Event for Swap<T> {
157
158    type Item = T;
159
160    #[inline]
161    fn call_event(self, p: &Point) -> simulation::Result<Self::Item> {
162        let Swap { comp, val } = self;
163        Result::Ok(comp.swap_at(val, p))
164    }
165}
166
167/// It writes into the contents of the mutable cell within the `Event` computation.
168#[must_use = "computations are lazy and do nothing unless to be run"]
169#[derive(Clone)]
170pub struct Write<T> where T: 'static {
171
172    /// The corresponding reference.
173    comp: Grc<RefComp<T>>,
174
175    /// A new value.
176    val: T
177}
178
179impl<T> Event for Write<T> {
180
181    type Item = ();
182
183    #[inline]
184    fn call_event(self, p: &Point) -> simulation::Result<Self::Item> {
185        let Write { comp, val } = self;
186        Result::Ok(comp.write_at(val, p))
187    }
188}
189
190/// It mutates the contents of the mutable cell within the `Event` computation.
191#[must_use = "computations are lazy and do nothing unless to be run"]
192#[derive(Clone)]
193pub struct Modify<T, F> where T: 'static {
194
195    /// The corresponding reference.
196    comp: Grc<RefComp<T>>,
197
198    /// A mutator.
199    f: F
200}
201
202impl<T, F> Event for Modify<T, F>
203    where F: FnOnce(&T) -> T,
204          T: Clone
205{
206    type Item = ();
207
208    #[inline]
209    fn call_event(self, p: &Point) -> simulation::Result<Self::Item> {
210        let Modify { comp, f } = self;
211        Result::Ok(comp.modify_at(f, p))
212    }
213}