aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout/flow_ref.rs
blob: 83243df2c8d0b43d2c8838aba56aef7aa1f093d9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Reference-counted pointers to flows.
//!
//! Eventually, with dynamically sized types in Rust, much of this code will be superfluous.

#![allow(unsafe_blocks)]

use flow::Flow;
use flow;

use std::mem;
use std::ops::{Deref, DerefMut};
use std::ptr;
use std::raw;
use std::sync::atomic::Ordering;

#[unsafe_no_drop_flag]
pub struct FlowRef {
    object: raw::TraitObject,
}

unsafe impl Send for FlowRef {}
unsafe impl Sync for FlowRef {}

impl FlowRef {
    pub fn new(mut flow: Box<Flow>) -> FlowRef {
        unsafe {
            let result = {
                let flow_ref: &mut Flow = &mut *flow;
                let object = mem::transmute::<&mut Flow, raw::TraitObject>(flow_ref);
                FlowRef { object: object }
            };
            mem::forget(flow);
            result
        }
    }
}

impl<'a> Deref for FlowRef {
    type Target = Flow + 'a;
    fn deref(&self) -> &(Flow + 'a) {
        unsafe {
            mem::transmute_copy::<raw::TraitObject, &(Flow + 'a)>(&self.object)
        }
    }
}

impl DerefMut for FlowRef {
    fn deref_mut<'a>(&mut self) -> &mut (Flow + 'a) {
        unsafe {
            mem::transmute_copy::<raw::TraitObject, &mut (Flow + 'a)>(&self.object)
        }
    }
}

impl Drop for FlowRef {
    fn drop(&mut self) {
        unsafe {
            if self.object.vtable.is_null() {
                return
            }
            if flow::base(&**self).ref_count().fetch_sub(1, Ordering::SeqCst) > 1 {
                return
            }
            let flow_ref: FlowRef = mem::replace(self, FlowRef {
                object: raw::TraitObject {
                    vtable: ptr::null_mut(),
                    data: ptr::null_mut(),
                }
            });
            drop(mem::transmute::<raw::TraitObject, Box<Flow>>(flow_ref.object));
            mem::forget(flow_ref);
            self.object.vtable = ptr::null_mut();
            self.object.data = ptr::null_mut();
        }
    }
}

impl Clone for FlowRef {
    fn clone(&self) -> FlowRef {
        unsafe {
            drop(flow::base(&**self).ref_count().fetch_add(1, Ordering::SeqCst));
            FlowRef {
                object: raw::TraitObject {
                    vtable: self.object.vtable,
                    data: self.object.data,
                }
            }
        }
    }
}