// 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. //! The AST pointer //! //! Provides `P`, a frozen owned smart pointer, as a replacement for `@T` in the AST. //! //! # Motivations and benefits //! //! * **Identity**: sharing AST nodes is problematic for the various analysis passes //! (e.g. one may be able to bypass the borrow checker with a shared `ExprAddrOf` //! node taking a mutable borrow). The only reason `@T` in the AST hasn't caused //! issues is because of inefficient folding passes which would always deduplicate //! any such shared nodes. Even if the AST were to switch to an arena, this would //! still hold, i.e. it couldn't use `&'a T`, but rather a wrapper like `P<'a, T>`. //! //! * **Immutability**: `P` disallows mutating its inner `T`, unlike `Box` //! (unless it contains an `Unsafe` interior, but that may be denied later). //! This mainly prevents mistakes, but can also enforces a kind of "purity". //! //! * **Efficiency**: folding can reuse allocation space for `P` and `Vec`, //! the latter even when the input and output types differ (as it would be the //! case with arenas or a GADT AST using type parameters to toggle features). //! //! * **Maintainability**: `P` provides a fixed interface - `Deref`, //! `and_then` and `map` - which can remain fully functional even if the //! implementation changes (using a special thread-local heap, for example). //! Moreover, a switch to, e.g. `P<'a, T>` would be easy and mostly automated. use std::fmt; use std::fmt::Show; use std::hash::Hash; use std::ptr; use serialize::{Encodable, Decodable, Encoder, Decoder}; /// An owned smart pointer. pub struct P { ptr: Box } #[allow(non_snake_case)] /// Construct a `P` from a `T` value. pub fn P(value: T) -> P { P { ptr: box value } } impl P { /// Move out of the pointer. /// Intended for chaining transformations not covered by `map`. pub fn and_then(self, f: F) -> U where F: FnOnce(T) -> U, { f(*self.ptr) } /// Transform the inner value, consuming `self` and producing a new `P`. pub fn map(mut self, f: F) -> P where F: FnOnce(T) -> T, { unsafe { let p = &mut *self.ptr; // FIXME(#5016) this shouldn't need to zero to be safe. ptr::write(p, f(ptr::read_and_zero(p))); } self } } impl Deref for P { fn deref<'a>(&'a self) -> &'a T { &*self.ptr } } impl Clone for P { fn clone(&self) -> P { P((**self).clone()) } } impl PartialEq for P { fn eq(&self, other: &P) -> bool { **self == **other } } impl Eq for P {} impl Show for P { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) } } impl> Hash for P { fn hash(&self, state: &mut S) { (**self).hash(state); } } impl, T: 'static + Decodable> Decodable for P { fn decode(d: &mut D) -> Result, E> { Decodable::decode(d).map(P) } } impl, T: Encodable> Encodable for P { fn encode(&self, s: &mut S) -> Result<(), E> { (**self).encode(s) } }