Guest User

Untitled

a guest
May 20th, 2018
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.32 KB | None | 0 0
  1. #![allow(dead_code)]
  2.  
  3. use std::ops::Drop;
  4. use std::rc::Rc;
  5.  
  6. enum Value {
  7. Number(i64),
  8. Cons(Cons),
  9. Null,
  10. }
  11.  
  12. impl Value {
  13. // Takes ownership of the `Value`, leaving `Value::Null` in its place.
  14. fn take(&mut self) -> Value {
  15. std::mem::replace(self, Value::Null)
  16. }
  17.  
  18. // Returns the `ConsInternals` of the `Value` if it is a `Value::Cons` that
  19. // is uniquely owned. Returns the original `Value` as an error otherwise.
  20. fn try_unwrap_cons(self) -> Result<ConsInternals, Value> {
  21. match self {
  22. Value::Cons(cons) => Rc::try_unwrap(cons.0).map_err(|rc| Value::Cons(Cons(rc))),
  23. value => Err(value),
  24. }
  25. }
  26.  
  27. // Returns a mutable reference to the `ConsInternals` of the `Value` if it
  28. // is a `Value::Cons` that is uniquely owned. Otherwise, returns `None`.
  29. fn get_cons_mut(&mut self) -> Option<&mut ConsInternals> {
  30. match *self {
  31. Value::Cons(ref mut cons) => Rc::get_mut(&mut cons.0),
  32. _ => None,
  33. }
  34. }
  35. }
  36.  
  37. struct Cons(Rc<ConsInternals>);
  38.  
  39. impl Cons {
  40. fn new(left: Value, right: Value) -> Value {
  41. Value::Cons(Cons(Rc::new(ConsInternals { left, right })))
  42. }
  43. }
  44.  
  45. struct ConsInternals {
  46. left: Value,
  47. right: Value,
  48. }
  49.  
  50. impl Drop for ConsInternals {
  51. // Drops a `Cons` list by repeatedly unlinking the head from the tail.
  52. // Handles tree-like structures by chaining together any lists encountered
  53. // in the `left` branch. The right-most leaf of the chain of left-values is
  54. // replaced with each left-value encountered in the original `Cons` list
  55. // until that list is empty, and then this chain of left-values is unlinked
  56. // in the same way as the original `Cons` list.
  57. //
  58. // A tail lefts tail lefts tail tail lefts tail
  59. // / \ -> B—C E—F -> C E—D -> E—D -> D G -> G
  60. // E B | | | |
  61. // / \ / \ D G G G
  62. // G F D C
  63. //
  64. fn drop(&mut self) {
  65. let mut tail = self.right.take();
  66. let mut left_chain = self.left.take();
  67. while let Value::Cons(_) = tail {
  68. {
  69. let mut left_chain_foot = &mut left_chain;
  70.  
  71. while let Ok(mut tail_internals) = tail.try_unwrap_cons() {
  72. tail = tail_internals.right.take();
  73.  
  74. // `get_cons_mut` currently has to be called twice to
  75. // satisfy the borrow checker.
  76. while let Some(_) = left_chain_foot.get_cons_mut() {
  77. left_chain_foot = &mut moved(left_chain_foot).get_cons_mut().unwrap().right;
  78. }
  79.  
  80. *left_chain_foot = tail_internals.left.take();
  81. }
  82. }
  83.  
  84. tail = left_chain;
  85. left_chain = Value::Null;
  86. }
  87. }
  88. }
  89.  
  90. // Helper to move `&mut` references rather than reborrowing them. Can also be
  91. // spelled `{ value }`.
  92. fn moved<T>(value: T) -> T {
  93. value
  94. }
  95.  
  96. fn main() {
  97. use Value::Number;
  98. // Leaves are numbered in order of dropping
  99. Cons::new(
  100. Cons::new(
  101. Cons::new(Number(8), Number(4)),
  102. Cons::new(Number(5), Number(1)),
  103. ),
  104. Cons::new(
  105. Cons::new(Number(7), Number(2)),
  106. Cons::new(Number(6), Number(3)),
  107. ),
  108. );
  109. }
Add Comment
Please, Sign In to add comment