// Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use std::cell::Cell; use std::ops::{Deref, DerefMut}; use std::vec::Vec; struct DerefCounter { count_imm: Cell, count_mut: uint, value: T } impl DerefCounter { fn new(value: T) -> DerefCounter { DerefCounter { count_imm: Cell::new(0), count_mut: 0, value: value } } fn counts(&self) -> (uint, uint) { (self.count_imm.get(), self.count_mut) } } impl Deref for DerefCounter { fn deref<'a>(&'a self) -> &'a T { self.count_imm.set(self.count_imm.get() + 1); &self.value } } impl DerefMut for DerefCounter { fn deref_mut<'a>(&'a mut self) -> &'a mut T { self.count_mut += 1; &mut self.value } } pub fn main() { let mut n = DerefCounter::new(0); let mut v = DerefCounter::new(Vec::new()); let _ = *n; // Immutable deref + copy a POD. assert_eq!(n.counts(), (1, 0)); let _ = (&*n, &*v); // Immutable deref + borrow. assert_eq!(n.counts(), (2, 0)); assert_eq!(v.counts(), (1, 0)); let _ = (&mut *n, &mut *v); // Mutable deref + mutable borrow. assert_eq!(n.counts(), (2, 1)); assert_eq!(v.counts(), (1, 1)); let mut v2 = Vec::new(); v2.push(1); *n = 5; *v = v2; // Mutable deref + assignment. assert_eq!(n.counts(), (2, 2)); assert_eq!(v.counts(), (1, 2)); *n -= 3; // Mutable deref + assignment with binary operation. assert_eq!(n.counts(), (2, 3)); // Mutable deref used for calling a method taking &self. // N.B. This is required because method lookup hasn't been performed so // we don't know whether the called method takes mutable self, before // the dereference itself is type-checked (a chicken-and-egg problem). (*n).to_str(); assert_eq!(n.counts(), (2, 4)); // Mutable deref used for calling a method taking &mut self. (*v).push(2); assert_eq!(v.counts(), (1, 3)); // Check the final states. assert_eq!(*n, 2); assert_eq!((*v).as_slice(), &[1, 2]); }