Skip to main content

nautilus_common/cache/
refs.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Lifetime-scoped reference newtypes for values held in the platform cache.
17//!
18//! Each reference type wraps a [`std::cell::Ref`] or [`std::cell::RefMut`] borrow into a cached
19//! cell, hiding the smart-pointer leak from public Cache accessor signatures and providing
20//! ergonomic trait impls (`Deref`, `PartialEq` against the inner value, `Display`, `Debug`).
21//!
22//! The borrow drops with the enclosing scope, which makes any attempt to hold it across a cache
23//! mutation panic at runtime: a loud failure beats the silent staleness that a stored clone
24//! would produce. Use the corresponding `*_owned` accessor on `Cache` when an owned snapshot is
25//! needed for a boundary handover.
26
27use std::{
28    cell::{Ref, RefMut},
29    fmt::{Debug, Display},
30    ops::{Deref, DerefMut},
31};
32
33use nautilus_model::{accounts::AccountAny, orders::OrderAny, position::Position};
34
35/// Lifetime-scoped read borrow of a cached account.
36///
37/// Returned by [`crate::cache::Cache::account`]. The borrow drops with the enclosing scope, which
38/// makes any attempt to hold it across a cache mutation panic at runtime: a loud failure beats the
39/// silent staleness that a stored clone would produce.
40///
41/// Method calls on the inner [`AccountAny`] resolve via [`Deref`]; comparisons against `&AccountAny`
42/// or owned `AccountAny` values are direct (`account_ref == &account`); `Debug` forwards to the
43/// inner record. Use [`cloned`](Self::cloned) when an owned snapshot is required (for example,
44/// before crossing a boundary that may dispatch events).
45pub struct AccountRef<'a>(Ref<'a, AccountAny>);
46
47impl<'a> AccountRef<'a> {
48    /// Wraps the given `Ref` borrow.
49    #[must_use]
50    pub fn new(inner: Ref<'a, AccountAny>) -> Self {
51        Self(inner)
52    }
53
54    /// Returns an owned snapshot of the borrowed account.
55    ///
56    /// Mirrors `Option::cloned` and `Iterator::cloned`; the snapshot will not reflect later
57    /// mutations of the underlying cell.
58    #[must_use]
59    pub fn cloned(&self) -> AccountAny {
60        (*self.0).clone()
61    }
62}
63
64impl Deref for AccountRef<'_> {
65    type Target = AccountAny;
66
67    fn deref(&self) -> &Self::Target {
68        &self.0
69    }
70}
71
72impl AsRef<AccountAny> for AccountRef<'_> {
73    fn as_ref(&self) -> &AccountAny {
74        &self.0
75    }
76}
77
78impl<'a> From<Ref<'a, AccountAny>> for AccountRef<'a> {
79    fn from(inner: Ref<'a, AccountAny>) -> Self {
80        Self(inner)
81    }
82}
83
84impl PartialEq<AccountAny> for AccountRef<'_> {
85    fn eq(&self, other: &AccountAny) -> bool {
86        &**self == other
87    }
88}
89
90impl PartialEq<&AccountAny> for AccountRef<'_> {
91    fn eq(&self, other: &&AccountAny) -> bool {
92        &**self == *other
93    }
94}
95
96impl Debug for AccountRef<'_> {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        Debug::fmt(&**self, f)
99    }
100}
101
102/// Lifetime-scoped exclusive write borrow of a cached account.
103///
104/// Returned by [`crate::cache::Cache::account_mut`]. While the borrow is alive, no other read or
105/// write on the same cell is permitted (enforced at runtime by the underlying [`RefMut`]).
106/// Drop the borrow before dispatching events or taking any other cache borrow that may re-enter
107/// the same account.
108pub struct AccountRefMut<'a>(RefMut<'a, AccountAny>);
109
110impl<'a> AccountRefMut<'a> {
111    /// Wraps the given `RefMut` borrow.
112    #[must_use]
113    pub fn new(inner: RefMut<'a, AccountAny>) -> Self {
114        Self(inner)
115    }
116
117    /// Returns an owned snapshot of the borrowed account.
118    #[must_use]
119    pub fn cloned(&self) -> AccountAny {
120        (*self.0).clone()
121    }
122}
123
124impl Deref for AccountRefMut<'_> {
125    type Target = AccountAny;
126
127    fn deref(&self) -> &Self::Target {
128        &self.0
129    }
130}
131
132impl DerefMut for AccountRefMut<'_> {
133    fn deref_mut(&mut self) -> &mut Self::Target {
134        &mut self.0
135    }
136}
137
138impl AsRef<AccountAny> for AccountRefMut<'_> {
139    fn as_ref(&self) -> &AccountAny {
140        &self.0
141    }
142}
143
144impl AsMut<AccountAny> for AccountRefMut<'_> {
145    fn as_mut(&mut self) -> &mut AccountAny {
146        &mut self.0
147    }
148}
149
150impl<'a> From<RefMut<'a, AccountAny>> for AccountRefMut<'a> {
151    fn from(inner: RefMut<'a, AccountAny>) -> Self {
152        Self(inner)
153    }
154}
155
156impl PartialEq<AccountAny> for AccountRefMut<'_> {
157    fn eq(&self, other: &AccountAny) -> bool {
158        &**self == other
159    }
160}
161
162impl PartialEq<&AccountAny> for AccountRefMut<'_> {
163    fn eq(&self, other: &&AccountAny) -> bool {
164        &**self == *other
165    }
166}
167
168impl Debug for AccountRefMut<'_> {
169    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
170        Debug::fmt(&**self, f)
171    }
172}
173
174/// Lifetime-scoped read borrow of a cached order.
175///
176/// Returned by [`crate::cache::Cache::order`]. The borrow drops with the enclosing scope, which
177/// makes any attempt to hold it across a cache mutation panic at runtime: a loud failure beats the
178/// silent staleness that a stored clone would produce.
179///
180/// Method calls on the inner [`OrderAny`] resolve via [`Deref`]; comparisons against `&OrderAny`
181/// or owned `OrderAny` values are direct (`order_ref == &order`); `Display` and `Debug` forward
182/// to the inner record. Use [`cloned`](Self::cloned) when an owned snapshot is required (for
183/// example, before crossing a boundary that may dispatch events).
184pub struct OrderRef<'a>(Ref<'a, OrderAny>);
185
186impl<'a> OrderRef<'a> {
187    /// Wraps the given `Ref` borrow.
188    #[must_use]
189    pub fn new(inner: Ref<'a, OrderAny>) -> Self {
190        Self(inner)
191    }
192
193    /// Returns an owned snapshot of the borrowed order.
194    ///
195    /// Mirrors `Option::cloned` and `Iterator::cloned`; the snapshot will not reflect later
196    /// mutations of the underlying cell.
197    #[must_use]
198    pub fn cloned(&self) -> OrderAny {
199        (*self.0).clone()
200    }
201}
202
203impl Deref for OrderRef<'_> {
204    type Target = OrderAny;
205
206    fn deref(&self) -> &Self::Target {
207        &self.0
208    }
209}
210
211impl AsRef<OrderAny> for OrderRef<'_> {
212    fn as_ref(&self) -> &OrderAny {
213        &self.0
214    }
215}
216
217impl<'a> From<Ref<'a, OrderAny>> for OrderRef<'a> {
218    fn from(inner: Ref<'a, OrderAny>) -> Self {
219        Self(inner)
220    }
221}
222
223impl PartialEq for OrderRef<'_> {
224    fn eq(&self, other: &Self) -> bool {
225        **self == **other
226    }
227}
228
229impl PartialEq<OrderAny> for OrderRef<'_> {
230    fn eq(&self, other: &OrderAny) -> bool {
231        &**self == other
232    }
233}
234
235impl PartialEq<&OrderAny> for OrderRef<'_> {
236    fn eq(&self, other: &&OrderAny) -> bool {
237        &**self == *other
238    }
239}
240
241impl Display for OrderRef<'_> {
242    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
243        Display::fmt(&**self, f)
244    }
245}
246
247impl Debug for OrderRef<'_> {
248    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249        Debug::fmt(&**self, f)
250    }
251}
252
253/// Lifetime-scoped exclusive write borrow of a cached order.
254///
255/// Returned by [`crate::cache::Cache::order_mut`]. While the borrow is alive, no other read or
256/// write on the same cell is permitted (enforced at runtime by the underlying [`RefMut`]).
257/// Drop the borrow before dispatching events or taking any other cache borrow that may re-enter
258/// the same order.
259pub struct OrderRefMut<'a>(RefMut<'a, OrderAny>);
260
261impl<'a> OrderRefMut<'a> {
262    /// Wraps the given `RefMut` borrow.
263    #[must_use]
264    pub fn new(inner: RefMut<'a, OrderAny>) -> Self {
265        Self(inner)
266    }
267
268    /// Returns an owned snapshot of the borrowed order.
269    #[must_use]
270    pub fn cloned(&self) -> OrderAny {
271        (*self.0).clone()
272    }
273}
274
275impl Deref for OrderRefMut<'_> {
276    type Target = OrderAny;
277
278    fn deref(&self) -> &Self::Target {
279        &self.0
280    }
281}
282
283impl DerefMut for OrderRefMut<'_> {
284    fn deref_mut(&mut self) -> &mut Self::Target {
285        &mut self.0
286    }
287}
288
289impl AsRef<OrderAny> for OrderRefMut<'_> {
290    fn as_ref(&self) -> &OrderAny {
291        &self.0
292    }
293}
294
295impl AsMut<OrderAny> for OrderRefMut<'_> {
296    fn as_mut(&mut self) -> &mut OrderAny {
297        &mut self.0
298    }
299}
300
301impl<'a> From<RefMut<'a, OrderAny>> for OrderRefMut<'a> {
302    fn from(inner: RefMut<'a, OrderAny>) -> Self {
303        Self(inner)
304    }
305}
306
307impl PartialEq<OrderAny> for OrderRefMut<'_> {
308    fn eq(&self, other: &OrderAny) -> bool {
309        &**self == other
310    }
311}
312
313impl PartialEq<&OrderAny> for OrderRefMut<'_> {
314    fn eq(&self, other: &&OrderAny) -> bool {
315        &**self == *other
316    }
317}
318
319impl Display for OrderRefMut<'_> {
320    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
321        Display::fmt(&**self, f)
322    }
323}
324
325impl Debug for OrderRefMut<'_> {
326    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
327        Debug::fmt(&**self, f)
328    }
329}
330
331/// Lifetime-scoped read borrow of a cached position.
332///
333/// Returned by [`crate::cache::Cache::position`]. The borrow drops with the enclosing scope, which
334/// makes any attempt to hold it across a cache mutation panic at runtime: a loud failure beats the
335/// silent staleness that a stored clone would produce.
336///
337/// Method calls on the inner [`Position`] resolve via [`Deref`]; comparisons against `&Position`
338/// or owned `Position` values are direct (`position_ref == &position`); `Display` and `Debug`
339/// forward to the inner record. Use [`cloned`](Self::cloned) when an owned snapshot is required
340/// (for example, before crossing a boundary that may dispatch events).
341pub struct PositionRef<'a>(Ref<'a, Position>);
342
343impl<'a> PositionRef<'a> {
344    /// Wraps the given `Ref` borrow.
345    #[must_use]
346    pub fn new(inner: Ref<'a, Position>) -> Self {
347        Self(inner)
348    }
349
350    /// Returns an owned snapshot of the borrowed position.
351    ///
352    /// Mirrors `Option::cloned` and `Iterator::cloned`; the snapshot will not reflect later
353    /// mutations of the underlying cell.
354    #[must_use]
355    pub fn cloned(&self) -> Position {
356        (*self.0).clone()
357    }
358}
359
360impl Deref for PositionRef<'_> {
361    type Target = Position;
362
363    fn deref(&self) -> &Self::Target {
364        &self.0
365    }
366}
367
368impl AsRef<Position> for PositionRef<'_> {
369    fn as_ref(&self) -> &Position {
370        &self.0
371    }
372}
373
374impl<'a> From<Ref<'a, Position>> for PositionRef<'a> {
375    fn from(inner: Ref<'a, Position>) -> Self {
376        Self(inner)
377    }
378}
379
380impl PartialEq for PositionRef<'_> {
381    fn eq(&self, other: &Self) -> bool {
382        **self == **other
383    }
384}
385
386impl PartialEq<Position> for PositionRef<'_> {
387    fn eq(&self, other: &Position) -> bool {
388        &**self == other
389    }
390}
391
392impl PartialEq<&Position> for PositionRef<'_> {
393    fn eq(&self, other: &&Position) -> bool {
394        &**self == *other
395    }
396}
397
398impl Display for PositionRef<'_> {
399    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
400        Display::fmt(&**self, f)
401    }
402}
403
404impl Debug for PositionRef<'_> {
405    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
406        Debug::fmt(&**self, f)
407    }
408}
409
410/// Lifetime-scoped exclusive write borrow of a cached position.
411///
412/// Returned by [`crate::cache::Cache::position_mut`]. While the borrow is alive, no other read or
413/// write on the same cell is permitted (enforced at runtime by the underlying [`RefMut`]).
414/// Drop the borrow before dispatching events or taking any other cache borrow that may re-enter
415/// the same position.
416pub struct PositionRefMut<'a>(RefMut<'a, Position>);
417
418impl<'a> PositionRefMut<'a> {
419    /// Wraps the given `RefMut` borrow.
420    #[must_use]
421    pub fn new(inner: RefMut<'a, Position>) -> Self {
422        Self(inner)
423    }
424
425    /// Returns an owned snapshot of the borrowed position.
426    #[must_use]
427    pub fn cloned(&self) -> Position {
428        (*self.0).clone()
429    }
430}
431
432impl Deref for PositionRefMut<'_> {
433    type Target = Position;
434
435    fn deref(&self) -> &Self::Target {
436        &self.0
437    }
438}
439
440impl DerefMut for PositionRefMut<'_> {
441    fn deref_mut(&mut self) -> &mut Self::Target {
442        &mut self.0
443    }
444}
445
446impl AsRef<Position> for PositionRefMut<'_> {
447    fn as_ref(&self) -> &Position {
448        &self.0
449    }
450}
451
452impl AsMut<Position> for PositionRefMut<'_> {
453    fn as_mut(&mut self) -> &mut Position {
454        &mut self.0
455    }
456}
457
458impl<'a> From<RefMut<'a, Position>> for PositionRefMut<'a> {
459    fn from(inner: RefMut<'a, Position>) -> Self {
460        Self(inner)
461    }
462}
463
464impl PartialEq<Position> for PositionRefMut<'_> {
465    fn eq(&self, other: &Position) -> bool {
466        &**self == other
467    }
468}
469
470impl PartialEq<&Position> for PositionRefMut<'_> {
471    fn eq(&self, other: &&Position) -> bool {
472        &**self == *other
473    }
474}
475
476impl Display for PositionRefMut<'_> {
477    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
478        Display::fmt(&**self, f)
479    }
480}
481
482impl Debug for PositionRefMut<'_> {
483    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
484        Debug::fmt(&**self, f)
485    }
486}
487
488#[cfg(test)]
489mod tests {
490    use std::{cell::RefCell, rc::Rc};
491
492    use nautilus_model::{
493        accounts::{Account, CashAccount, stubs::cash_account},
494        enums::{AccountType, OrderSide, OrderType},
495        events::{AccountState, account::stubs::cash_account_state},
496        instruments::{CurrencyPair, stubs::*},
497        orders::{Order, builder::OrderTestBuilder},
498        stubs::{stub_position_long, stub_position_short},
499        types::{Price, Quantity},
500    };
501    use rstest::rstest;
502
503    use super::*;
504
505    fn make_order(audusd_sim: &CurrencyPair) -> OrderAny {
506        OrderTestBuilder::new(OrderType::Limit)
507            .instrument_id(audusd_sim.id)
508            .side(OrderSide::Buy)
509            .price(Price::from("1.00000"))
510            .quantity(Quantity::from(100_000))
511            .build()
512    }
513
514    fn make_account(state: AccountState) -> AccountAny {
515        AccountAny::Cash(CashAccount::new(state, true, false))
516    }
517
518    #[rstest]
519    fn test_account_ref_partial_eq_against_owned(cash_account_state: AccountState) {
520        let account = make_account(cash_account_state);
521        let cell = Rc::new(RefCell::new(account.clone()));
522        let account_ref = AccountRef::from(cell.borrow());
523
524        assert_eq!(account_ref, account);
525        assert_eq!(account_ref, &account);
526    }
527
528    #[rstest]
529    fn test_account_ref_debug_matches_inner(cash_account_state: AccountState) {
530        let account = make_account(cash_account_state);
531        let cell = Rc::new(RefCell::new(account.clone()));
532        let account_ref = AccountRef::from(cell.borrow());
533
534        assert_eq!(format!("{account_ref:?}"), format!("{account:?}"));
535    }
536
537    #[rstest]
538    fn test_account_ref_cloned_is_independent(cash_account_state: AccountState) {
539        let cell = Rc::new(RefCell::new(make_account(cash_account_state)));
540        let snapshot = AccountRef::from(cell.borrow()).cloned();
541
542        assert_eq!(snapshot, *cell.borrow());
543    }
544
545    #[rstest]
546    fn test_account_ref_deref_method_call(cash_account: CashAccount) {
547        let account = AccountAny::Cash(cash_account);
548        let cell = Rc::new(RefCell::new(account.clone()));
549        let account_ref = AccountRef::from(cell.borrow());
550
551        // Methods on `AccountAny` are reachable via `Deref`.
552        assert_eq!(account_ref.id(), account.id());
553        assert_eq!(account_ref.account_type(), AccountType::Cash);
554    }
555
556    #[rstest]
557    fn test_account_ref_mut_writes_through_deref_mut(cash_account_state: AccountState) {
558        let cell = Rc::new(RefCell::new(make_account(cash_account_state.clone())));
559        let mut account_mut = AccountRefMut::from(cell.borrow_mut());
560
561        // Apply the same state event again; the apply succeeds and mutates events.
562        account_mut.apply(cash_account_state).unwrap();
563        let event_count = account_mut.events().len();
564        drop(account_mut);
565
566        assert_eq!(cell.borrow().events().len(), event_count);
567    }
568
569    #[rstest]
570    fn test_account_ref_mut_partial_eq_against_owned(cash_account_state: AccountState) {
571        let account = make_account(cash_account_state);
572        let cell = Rc::new(RefCell::new(account.clone()));
573        let account_mut = AccountRefMut::from(cell.borrow_mut());
574
575        assert_eq!(account_mut, account);
576        assert_eq!(account_mut, &account);
577    }
578
579    #[rstest]
580    fn test_order_ref_partial_eq_against_owned(audusd_sim: CurrencyPair) {
581        let order = make_order(&audusd_sim);
582        let cell = Rc::new(RefCell::new(order.clone()));
583        let order_ref = OrderRef::from(cell.borrow());
584
585        assert_eq!(order_ref, order);
586        assert_eq!(order_ref, &order);
587    }
588
589    #[rstest]
590    fn test_order_ref_display_matches_inner(audusd_sim: CurrencyPair) {
591        let order = make_order(&audusd_sim);
592        let cell = Rc::new(RefCell::new(order.clone()));
593        let order_ref = OrderRef::from(cell.borrow());
594
595        assert_eq!(format!("{order_ref}"), format!("{order}"));
596        assert_eq!(format!("{order_ref:?}"), format!("{order:?}"));
597    }
598
599    #[rstest]
600    fn test_order_ref_cloned_is_independent(audusd_sim: CurrencyPair) {
601        let cell = Rc::new(RefCell::new(make_order(&audusd_sim)));
602        let snapshot = OrderRef::from(cell.borrow()).cloned();
603        let original_qty = snapshot.quantity();
604
605        // Snapshot is independent: subsequent mutation of the cell does not affect it.
606        cell.borrow_mut().set_quantity(Quantity::from(1));
607
608        assert_eq!(snapshot.quantity(), original_qty);
609        assert_eq!(cell.borrow().quantity(), Quantity::from(1));
610    }
611
612    #[rstest]
613    fn test_order_ref_deref_method_call(audusd_sim: CurrencyPair) {
614        let order = make_order(&audusd_sim);
615        let cell = Rc::new(RefCell::new(order.clone()));
616        let order_ref = OrderRef::from(cell.borrow());
617
618        // Methods on `OrderAny` are reachable via `Deref`.
619        assert_eq!(order_ref.client_order_id(), order.client_order_id());
620        assert_eq!(order_ref.quantity(), order.quantity());
621    }
622
623    #[rstest]
624    fn test_order_ref_mut_writes_through_deref_mut(audusd_sim: CurrencyPair) {
625        let cell = Rc::new(RefCell::new(make_order(&audusd_sim)));
626        let mut order_mut = OrderRefMut::from(cell.borrow_mut());
627
628        order_mut.set_quantity(Quantity::from(7));
629        drop(order_mut);
630
631        assert_eq!(cell.borrow().quantity(), Quantity::from(7));
632    }
633
634    #[rstest]
635    fn test_order_ref_mut_partial_eq_against_owned(audusd_sim: CurrencyPair) {
636        let order = make_order(&audusd_sim);
637        let cell = Rc::new(RefCell::new(order.clone()));
638        let order_mut = OrderRefMut::from(cell.borrow_mut());
639
640        assert_eq!(order_mut, order);
641        assert_eq!(order_mut, &order);
642    }
643
644    #[rstest]
645    fn test_position_ref_partial_eq_against_owned(stub_position_long: Position) {
646        let cell = Rc::new(RefCell::new(stub_position_long.clone()));
647        let position_ref = PositionRef::from(cell.borrow());
648
649        assert_eq!(position_ref, stub_position_long);
650        assert_eq!(position_ref, &stub_position_long);
651    }
652
653    #[rstest]
654    fn test_position_ref_display_matches_inner(stub_position_long: Position) {
655        let cell = Rc::new(RefCell::new(stub_position_long.clone()));
656        let position_ref = PositionRef::from(cell.borrow());
657
658        assert_eq!(format!("{position_ref}"), format!("{stub_position_long}"));
659        assert_eq!(
660            format!("{position_ref:?}"),
661            format!("{stub_position_long:?}")
662        );
663    }
664
665    #[rstest]
666    fn test_position_ref_cloned_is_independent(stub_position_short: Position) {
667        let cell = Rc::new(RefCell::new(stub_position_short));
668        let snapshot = PositionRef::from(cell.borrow()).cloned();
669        let original_qty = snapshot.quantity;
670
671        cell.borrow_mut().quantity = Quantity::from(1);
672
673        assert_eq!(snapshot.quantity, original_qty);
674        assert_eq!(cell.borrow().quantity, Quantity::from(1));
675    }
676
677    #[rstest]
678    fn test_position_ref_deref_method_call(stub_position_long: Position) {
679        let cell = Rc::new(RefCell::new(stub_position_long.clone()));
680        let position_ref = PositionRef::from(cell.borrow());
681
682        // Fields and methods on `Position` are reachable via `Deref`.
683        assert_eq!(position_ref.id, stub_position_long.id);
684        assert_eq!(position_ref.quantity, stub_position_long.quantity);
685    }
686
687    #[rstest]
688    fn test_position_ref_mut_writes_through_deref_mut(stub_position_long: Position) {
689        let cell = Rc::new(RefCell::new(stub_position_long));
690        let mut position_mut = PositionRefMut::from(cell.borrow_mut());
691
692        position_mut.quantity = Quantity::from(7);
693        drop(position_mut);
694
695        assert_eq!(cell.borrow().quantity, Quantity::from(7));
696    }
697
698    #[rstest]
699    fn test_position_ref_mut_partial_eq_against_owned(stub_position_long: Position) {
700        let cell = Rc::new(RefCell::new(stub_position_long.clone()));
701        let position_mut = PositionRefMut::from(cell.borrow_mut());
702
703        assert_eq!(position_mut, stub_position_long);
704        assert_eq!(position_mut, &stub_position_long);
705    }
706}