From 938058b0040e3c482e10b78eeef7afb941b2b64e Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 18 Dec 2012 20:48:23 -0800 Subject: [PATCH 01/22] Fix vec::flat_map_to_vec method --- src/libcore/vec.rs | 126 ++++++++++++++++++++++ src/test/run-pass/iter-flat-map-to-vec.rs | 27 +++-- 2 files changed, 139 insertions(+), 14 deletions(-) diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index c091f48728f98..5071fb903d91d 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -2024,6 +2024,32 @@ impl &[A]: iter::BaseIter { pure fn size_hint(&self) -> Option { Some(len(*self)) } } +// FIXME(#4148): This should be redundant +impl ~[A]: iter::BaseIter { + pub pure fn each(&self, blk: fn(v: &A) -> bool) { + // FIXME(#2263)---should be able to call each(self, blk) + for each(*self) |e| { + if (!blk(e)) { + return; + } + } + } + pure fn size_hint(&self) -> Option { Some(len(*self)) } +} + +// FIXME(#4148): This should be redundant +impl @[A]: iter::BaseIter { + pub pure fn each(&self, blk: fn(v: &A) -> bool) { + // FIXME(#2263)---should be able to call each(self, blk) + for each(*self) |e| { + if (!blk(e)) { + return; + } + } + } + pure fn size_hint(&self) -> Option { Some(len(*self)) } +} + impl &[A]: iter::ExtendedIter { pub pure fn eachi(&self, blk: fn(uint, v: &A) -> bool) { iter::eachi(self, blk) @@ -2049,11 +2075,75 @@ impl &[A]: iter::ExtendedIter { } } +// FIXME(#4148): This should be redundant +impl ~[A]: iter::ExtendedIter { + pub pure fn eachi(&self, blk: fn(uint, v: &A) -> bool) { + iter::eachi(self, blk) + } + pub pure fn all(&self, blk: fn(&A) -> bool) -> bool { + iter::all(self, blk) + } + pub pure fn any(&self, blk: fn(&A) -> bool) -> bool { + iter::any(self, blk) + } + pub pure fn foldl(&self, b0: B, blk: fn(&B, &A) -> B) -> B { + iter::foldl(self, b0, blk) + } + pub pure fn position(&self, f: fn(&A) -> bool) -> Option { + iter::position(self, f) + } + pure fn map_to_vec(&self, op: fn(&A) -> B) -> ~[B] { + iter::map_to_vec(self, op) + } + pure fn flat_map_to_vec>(&self, op: fn(&A) -> IB) + -> ~[B] { + iter::flat_map_to_vec(self, op) + } +} + +// FIXME(#4148): This should be redundant +impl @[A]: iter::ExtendedIter { + pub pure fn eachi(&self, blk: fn(uint, v: &A) -> bool) { + iter::eachi(self, blk) + } + pub pure fn all(&self, blk: fn(&A) -> bool) -> bool { + iter::all(self, blk) + } + pub pure fn any(&self, blk: fn(&A) -> bool) -> bool { + iter::any(self, blk) + } + pub pure fn foldl(&self, b0: B, blk: fn(&B, &A) -> B) -> B { + iter::foldl(self, b0, blk) + } + pub pure fn position(&self, f: fn(&A) -> bool) -> Option { + iter::position(self, f) + } + pure fn map_to_vec(&self, op: fn(&A) -> B) -> ~[B] { + iter::map_to_vec(self, op) + } + pure fn flat_map_to_vec>(&self, op: fn(&A) -> IB) + -> ~[B] { + iter::flat_map_to_vec(self, op) + } +} + impl &[A]: iter::EqIter { pub pure fn contains(&self, x: &A) -> bool { iter::contains(self, x) } pub pure fn count(&self, x: &A) -> uint { iter::count(self, x) } } +// FIXME(#4148): This should be redundant +impl ~[A]: iter::EqIter { + pub pure fn contains(&self, x: &A) -> bool { iter::contains(self, x) } + pub pure fn count(&self, x: &A) -> uint { iter::count(self, x) } +} + +// FIXME(#4148): This should be redundant +impl @[A]: iter::EqIter { + pub pure fn contains(&self, x: &A) -> bool { iter::contains(self, x) } + pub pure fn count(&self, x: &A) -> uint { iter::count(self, x) } +} + impl &[A]: iter::CopyableIter { pure fn filter_to_vec(&self, pred: fn(&A) -> bool) -> ~[A] { iter::filter_to_vec(self, pred) @@ -2064,11 +2154,45 @@ impl &[A]: iter::CopyableIter { } } +// FIXME(#4148): This should be redundant +impl ~[A]: iter::CopyableIter { + pure fn filter_to_vec(&self, pred: fn(&A) -> bool) -> ~[A] { + iter::filter_to_vec(self, pred) + } + pure fn to_vec(&self) -> ~[A] { iter::to_vec(self) } + pub pure fn find(&self, f: fn(&A) -> bool) -> Option { + iter::find(self, f) + } +} + +// FIXME(#4148): This should be redundant +impl @[A]: iter::CopyableIter { + pure fn filter_to_vec(&self, pred: fn(&A) -> bool) -> ~[A] { + iter::filter_to_vec(self, pred) + } + pure fn to_vec(&self) -> ~[A] { iter::to_vec(self) } + pub pure fn find(&self, f: fn(&A) -> bool) -> Option { + iter::find(self, f) + } +} + impl &[A]: iter::CopyableOrderedIter { pure fn min(&self) -> A { iter::min(self) } pure fn max(&self) -> A { iter::max(self) } } +// FIXME(#4148): This should be redundant +impl ~[A]: iter::CopyableOrderedIter { + pure fn min(&self) -> A { iter::min(self) } + pure fn max(&self) -> A { iter::max(self) } +} + +// FIXME(#4148): This should be redundant +impl @[A]: iter::CopyableOrderedIter { + pure fn min(&self) -> A { iter::min(self) } + pure fn max(&self) -> A { iter::max(self) } +} + impl &[A] : iter::CopyableNonstrictIter { pure fn each_val(&const self, f: fn(A) -> bool) { let mut i = 0; @@ -2079,6 +2203,7 @@ impl &[A] : iter::CopyableNonstrictIter { } } +// FIXME(#4148): This should be redundant impl ~[A] : iter::CopyableNonstrictIter { pure fn each_val(&const self, f: fn(A) -> bool) { let mut i = 0; @@ -2089,6 +2214,7 @@ impl ~[A] : iter::CopyableNonstrictIter { } } +// FIXME(#4148): This should be redundant impl @[A] : iter::CopyableNonstrictIter { pure fn each_val(&const self, f: fn(A) -> bool) { let mut i = 0; diff --git a/src/test/run-pass/iter-flat-map-to-vec.rs b/src/test/run-pass/iter-flat-map-to-vec.rs index 2177066a03374..a90206188e388 100644 --- a/src/test/run-pass/iter-flat-map-to-vec.rs +++ b/src/test/run-pass/iter-flat-map-to-vec.rs @@ -8,23 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test -- flat_map_to_vec currently disable -fn repeat(x: &uint) -> ~[uint] { ~[x, x] } +fn repeat(x: &uint) -> ~[uint] { ~[*x, *x] } -fn incd_if_even(x: &uint) -> option { - if (x % 2u) == 0u {some(x + 1u)} else {none} +fn incd_if_even(x: &uint) -> Option { + if (*x % 2u) == 0u {Some(*x + 1u)} else {None} } fn main() { - assert ~[1u, 3u].flat_map_to_vec(repeat) == ~[1u, 1u, 3u, 3u]; - assert ~[].flat_map_to_vec(repeat) == ~[]; - assert none.flat_map_to_vec(repeat) == ~[]; - assert some(1u).flat_map_to_vec(repeat) == ~[1u, 1u]; - assert some(2u).flat_map_to_vec(repeat) == ~[2u, 2u]; + assert (~[1u, 3u]).flat_map_to_vec(repeat) == ~[1u, 1u, 3u, 3u]; + assert (~[]).flat_map_to_vec(repeat) == ~[]; + assert None.flat_map_to_vec(repeat) == ~[]; + assert Some(1u).flat_map_to_vec(repeat) == ~[1u, 1u]; + assert Some(2u).flat_map_to_vec(repeat) == ~[2u, 2u]; - assert ~[1u, 2u, 5u].flat_map_to_vec(incd_if_even) == ~[3u]; - assert ~[].flat_map_to_vec(incd_if_even) == ~[]; - assert none.flat_map_to_vec(incd_if_even) == ~[]; - assert some(1u).flat_map_to_vec(incd_if_even) == ~[]; - assert some(2u).flat_map_to_vec(incd_if_even) == ~[3u]; + assert (~[1u, 2u, 5u]).flat_map_to_vec(incd_if_even) == ~[3u]; + assert (~[]).flat_map_to_vec(incd_if_even) == ~[]; + assert None.flat_map_to_vec(incd_if_even) == ~[]; + assert Some(1u).flat_map_to_vec(incd_if_even) == ~[]; + assert Some(2u).flat_map_to_vec(incd_if_even) == ~[3u]; } From a0ef334179714e0c3f1a3c7276543a0305db2c95 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 18 Dec 2012 18:55:19 -0800 Subject: [PATCH 02/22] core: use movable self to clean up option/result. --- src/libcore/option.rs | 98 +++++++++++++++++++++++++------------------ src/libcore/pipes.rs | 4 +- src/libcore/result.rs | 87 +++++++++++++++++++------------------- 3 files changed, 103 insertions(+), 86 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index f7de25bf021a5..a4f385ea12cd8 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -96,19 +96,6 @@ pub pure fn get_ref(opt: &r/Option) -> &r/T { } } -pub pure fn expect(opt: Option, reason: ~str) -> T { - /*! - * Gets the value out of an option without copying, printing a - * specified message on failure. - * - * # Failure - * - * Fails if the value equals `none` - */ - if opt.is_some() { move option::unwrap(move opt) } - else { fail reason } -} - pub pure fn map(opt: &Option, f: fn(x: &T) -> U) -> Option { //! Maps a `some` value by reference from one type to another @@ -235,35 +222,46 @@ pub fn swap_unwrap(opt: &mut Option) -> T { unwrap(util::replace(opt, None)) } -pub pure fn unwrap_expect(opt: Option, reason: &str) -> T { +pub pure fn expect(opt: Option, reason: &str) -> T { //! As unwrap, but with a specified failure message. - if opt.is_none() { fail reason.to_owned(); } - unwrap(move opt) + match move opt { + Some(move val) => val, + None => fail reason.to_owned(), + } } -// Some of these should change to be &Option, some should not. See below. impl Option { /// Returns true if the option equals `none` - pure fn is_none() -> bool { is_none(&self) } + #[inline(always)] + pure fn is_none(&self) -> bool { is_none(self) } + /// Returns true if the option contains some value - pure fn is_some() -> bool { is_some(&self) } -} + #[inline(always)] + pure fn is_some(&self) -> bool { is_some(self) } -impl &Option { /** * Update an optional value by optionally running its content by reference * through a function that returns an option. */ - pure fn chain_ref(f: fn(x: &T) -> Option) -> Option { + #[inline(always)] + pure fn chain_ref(&self, f: fn(x: &T) -> Option) -> Option { chain_ref(self, f) } + + /// Maps a `some` value from one type to another by reference + #[inline(always)] + pure fn map(&self, f: fn(x: &T) -> U) -> Option { map(self, f) } + /// Applies a function to the contained value or returns a default - pure fn map_default(def: U, f: fn(x: &T) -> U) -> U - { map_default(self, move def, f) } + #[inline(always)] + pure fn map_default(&self, def: U, f: fn(x: &T) -> U) -> U { + map_default(self, move def, f) + } + /// Performs an operation on the contained value by reference - pure fn iter(f: fn(x: &T)) { iter(self, f) } - /// Maps a `some` value from one type to another by reference - pure fn map(f: fn(x: &T) -> U) -> Option { map(self, f) } + #[inline(always)] + pure fn iter(&self, f: fn(x: &T)) { iter(self, f) } + /** Gets an immutable reference to the value inside an option. @@ -278,7 +276,29 @@ impl &Option { Instead, prefer to use pattern matching and handle the `None` case explicitly. */ - pure fn get_ref() -> &self/T { get_ref(self) } + #[inline(always)] + pure fn get_ref(&self) -> &self/T { get_ref(self) } + + /** + * Gets the value out of an option without copying. + * + * # Failure + * + * Fails if the value equals `none` + */ + #[inline(always)] + pure fn unwrap(self) -> T { unwrap(self) } + + /** + * Gets the value out of an option, printing a specified message on + * failure + * + * # Failure + * + * Fails if the value equals `none` + */ + #[inline(always)] + pure fn expect(self, reason: &str) -> T { expect(self, reason) } } impl Option { @@ -296,19 +316,17 @@ impl Option { Instead, prefer to use pattern matching and handle the `None` case explicitly. */ - pure fn get() -> T { get(self) } - pure fn get_default(def: T) -> T { get_default(self, def) } - /** - * Gets the value out of an option, printing a specified message on - * failure - * - * # Failure - * - * Fails if the value equals `none` - */ - pure fn expect(reason: ~str) -> T { expect(self, move reason) } + #[inline(always)] + pure fn get(self) -> T { get(self) } + + #[inline(always)] + pure fn get_default(self, def: T) -> T { get_default(self, def) } + /// Applies a function zero or more times until the result is none. - pure fn while_some(blk: fn(v: T) -> Option) { while_some(self, blk) } + #[inline(always)] + pure fn while_some(self, blk: fn(v: T) -> Option) { + while_some(self, blk) + } } #[test] diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index 914530c065309..59d59d3351896 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -412,7 +412,7 @@ Fails if the sender closes the connection. */ pub fn recv( p: RecvPacketBuffered) -> T { - option::unwrap_expect(try_recv(move p), "connection closed") + try_recv(move p).expect("connection closed") } /** Attempts to receive a message from a pipe. @@ -1102,7 +1102,7 @@ impl PortSet : GenericPort { } fn recv() -> T { - option::unwrap_expect(self.try_recv(), "port_set: endpoints closed") + self.try_recv().expect("port_set: endpoints closed") } } diff --git a/src/libcore/result.rs b/src/libcore/result.rs index a1e7df28872a8..26064345b59f2 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -114,7 +114,7 @@ pub pure fn to_either(res: &Result) * ok(parse_bytes(buf)) * } */ -pub fn chain(res: Result, op: fn(t: T) +pub pure fn chain(res: Result, op: fn(T) -> Result) -> Result { match move res { Ok(move t) => op(move t), @@ -130,7 +130,7 @@ pub fn chain(res: Result, op: fn(t: T) * immediately returned. This function can be used to pass through a * successful result while handling an error. */ -pub fn chain_err( +pub pure fn chain_err( res: Result, op: fn(t: V) -> Result) -> Result { @@ -154,7 +154,7 @@ pub fn chain_err( * print_buf(buf) * } */ -pub fn iter(res: &Result, f: fn(&T)) { +pub pure fn iter(res: &Result, f: fn(&T)) { match *res { Ok(ref t) => f(t), Err(_) => () @@ -169,7 +169,7 @@ pub fn iter(res: &Result, f: fn(&T)) { * This function can be used to pass through a successful result while * handling an error. */ -pub fn iter_err(res: &Result, f: fn(&E)) { +pub pure fn iter_err(res: &Result, f: fn(&E)) { match *res { Ok(_) => (), Err(ref e) => f(e) @@ -190,7 +190,7 @@ pub fn iter_err(res: &Result, f: fn(&E)) { * parse_bytes(buf) * } */ -pub fn map(res: &Result, op: fn(&T) -> U) +pub pure fn map(res: &Result, op: fn(&T) -> U) -> Result { match *res { Ok(ref t) => Ok(op(t)), @@ -206,7 +206,7 @@ pub fn map(res: &Result, op: fn(&T) -> U) * is immediately returned. This function can be used to pass through a * successful result while handling an error. */ -pub fn map_err(res: &Result, op: fn(&E) -> F) +pub pure fn map_err(res: &Result, op: fn(&E) -> F) -> Result { match *res { Ok(copy t) => Ok(t), @@ -215,58 +215,55 @@ pub fn map_err(res: &Result, op: fn(&E) -> F) } impl Result { + #[inline(always)] pure fn get_ref(&self) -> &self/T { get_ref(self) } - pure fn is_ok() -> bool { is_ok(&self) } + #[inline(always)] + pure fn is_ok(&self) -> bool { is_ok(self) } - pure fn is_err() -> bool { is_err(&self) } + #[inline(always)] + pure fn is_err(&self) -> bool { is_err(self) } - pure fn iter(f: fn(&T)) { - match self { - Ok(ref t) => f(t), - Err(_) => () - } + #[inline(always)] + pure fn iter(&self, f: fn(&T)) { iter(self, f) } + + #[inline(always)] + pure fn iter_err(&self, f: fn(&E)) { iter_err(self, f) } + + #[inline(always)] + pure fn unwrap(self) -> T { unwrap(self) } + + #[inline(always)] + pure fn unwrap_err(self) -> T { unwrap(self) } + + #[inline(always)] + pure fn chain(self, op: fn(T) -> Result) -> Result { + chain(self, op) } - fn iter_err(f: fn(&E)) { - match self { - Ok(_) => (), - Err(ref e) => f(e) - } + #[inline(always)] + pure fn chain_err(self, op: fn(E) -> Result) -> Result { + chain_err(self, op) } } impl Result { - pure fn get() -> T { get(&self) } + #[inline(always)] + pure fn get(&self) -> T { get(self) } - fn map_err(op: fn(&E) -> F) -> Result { - match self { - Ok(copy t) => Ok(t), - Err(ref e) => Err(op(e)) - } + #[inline(always)] + pure fn map_err(&self, op: fn(&E) -> F) -> Result { + map_err(self, op) } } impl Result { - pure fn get_err() -> E { get_err(&self) } - - fn map(op: fn(&T) -> U) -> Result { - match self { - Ok(ref t) => Ok(op(t)), - Err(copy e) => Err(e) - } - } -} - -impl Result { - fn chain(op: fn(t: T) -> Result) -> Result { - // XXX: Bad copy - chain(copy self, op) - } + #[inline(always)] + pure fn get_err(&self) -> E { get_err(self) } - fn chain_err(op: fn(t: E) -> Result) -> Result { - // XXX: Bad copy - chain_err(copy self, op) + #[inline(always)] + pure fn map(&self, op: fn(&T) -> U) -> Result { + map(self, op) } } @@ -360,7 +357,8 @@ pub fn iter_vec2(ss: &[S], ts: &[T], } /// Unwraps a result, assuming it is an `ok(T)` -pub fn unwrap(res: Result) -> T { +#[inline(always)] +pub pure fn unwrap(res: Result) -> T { match move res { Ok(move t) => move t, Err(_) => fail ~"unwrap called on an err result" @@ -368,7 +366,8 @@ pub fn unwrap(res: Result) -> T { } /// Unwraps a result, assuming it is an `err(U)` -pub fn unwrap_err(res: Result) -> U { +#[inline(always)] +pub pure fn unwrap_err(res: Result) -> U { match move res { Err(move u) => move u, Ok(_) => fail ~"unwrap called on an ok result" From 82a983de6803c7b1026ba0b553186306e842e427 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 18 Dec 2012 18:55:36 -0800 Subject: [PATCH 03/22] Remove superfluous parentheses. --- src/libstd/par.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libstd/par.rs b/src/libstd/par.rs index 55f88d4427cef..10cbcaa0c3b3a 100644 --- a/src/libstd/par.rs +++ b/src/libstd/par.rs @@ -85,7 +85,7 @@ fn map_slices( /// A parallel version of map. pub fn map( - xs: &[A], f: fn~((&A)) -> B) -> ~[B] { + xs: &[A], f: fn~(&A) -> B) -> ~[B] { vec::concat(map_slices(xs, || { fn~(_base: uint, slice : &[A], copy f) -> ~[B] { vec::map(slice, |x| f(x)) @@ -95,7 +95,7 @@ pub fn map( /// A parallel version of mapi. pub fn mapi(xs: &[A], - f: fn~(uint, (&A)) -> B) -> ~[B] { + f: fn~(uint, &A) -> B) -> ~[B] { let slices = map_slices(xs, || { fn~(base: uint, slice : &[A], copy f) -> ~[B] { vec::mapi(slice, |i, x| { @@ -132,7 +132,7 @@ pub fn mapi_factory( } /// Returns true if the function holds for all elements in the vector. -pub fn alli(xs: &[A], f: fn~(uint, (&A)) -> bool) -> bool { +pub fn alli(xs: &[A], f: fn~(uint, &A) -> bool) -> bool { do vec::all(map_slices(xs, || { fn~(base: uint, slice : &[A], copy f) -> bool { vec::alli(slice, |i, x| { @@ -143,7 +143,7 @@ pub fn alli(xs: &[A], f: fn~(uint, (&A)) -> bool) -> bool { } /// Returns true if the function holds for any elements in the vector. -pub fn any(xs: &[A], f: fn~(&(A)) -> bool) -> bool { +pub fn any(xs: &[A], f: fn~(&A) -> bool) -> bool { do vec::any(map_slices(xs, || { fn~(_base : uint, slice: &[A], copy f) -> bool { vec::any(slice, |x| f(x)) From 2ad41b881cb8389cb690c643e41c27f6c34270d5 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 18 Dec 2012 18:54:25 -0800 Subject: [PATCH 04/22] core: add unwrap methods to dvec, either, and mutable --- src/libcore/dvec.rs | 3 +++ src/libcore/either.rs | 8 ++++++++ src/libcore/mutable.rs | 3 +++ 3 files changed, 14 insertions(+) diff --git a/src/libcore/dvec.rs b/src/libcore/dvec.rs index 874a36eb9f0cb..b02a6f5c8b538 100644 --- a/src/libcore/dvec.rs +++ b/src/libcore/dvec.rs @@ -110,6 +110,9 @@ priv impl DVec { self.data = move data; } } + + #[inline(always)] + fn unwrap(self) -> ~[A] { unwrap(self) } } // In theory, most everything should work with any A, but in practice diff --git a/src/libcore/either.rs b/src/libcore/either.rs index 74b29f3a5f1ca..6c0254ff77902 100644 --- a/src/libcore/either.rs +++ b/src/libcore/either.rs @@ -142,6 +142,14 @@ pub pure fn unwrap_right(eith: Either) -> U { } } +impl Either { + #[inline(always)] + fn unwrap_left(self) -> T { unwrap_left(self) } + + #[inline(always)] + fn unwrap_right(self) -> U { unwrap_right(self) } +} + #[test] fn test_either_left() { let val = Left(10); diff --git a/src/libcore/mutable.rs b/src/libcore/mutable.rs index ccefda41fdad5..e5090f02b41bc 100644 --- a/src/libcore/mutable.rs +++ b/src/libcore/mutable.rs @@ -73,6 +73,9 @@ impl Data { op(unsafe{transmute_immut(&mut self.value)}) } } + + #[inline(always)] + fn unwrap(self) -> T { unwrap(self) } } #[test] From 63232d6cf16ea2c4503b580c23a9fe8e31671a0d Mon Sep 17 00:00:00 2001 From: Isaac Aggrey Date: Wed, 19 Dec 2012 12:46:24 -0600 Subject: [PATCH 05/22] Fix doc typo --- doc/tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tutorial.md b/doc/tutorial.md index 7ba24197678e9..de1b1a56f1c87 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -1924,7 +1924,7 @@ types by the compiler, and may not be overridden: Additionally, the `Drop` trait is used to define destructors. This trait defines one method called `finalize`, which is automatically -called when value of the a type that implements this trait is +called when a value of the type that implements this trait is destroyed, either because the value went out of scope or because the garbage collector reclaimed it. From 327c1f58adb6ab9c1dbd663f2dc7646dfb601975 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 19 Dec 2012 12:15:48 -0800 Subject: [PATCH 06/22] Add Isaac Aggrey to AUTHORS --- AUTHORS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index e4199ac5c57b4..645d6be9babee 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -57,6 +57,7 @@ Grahame Bowland Haitao Li Huon Wilson Ian D. Bollinger +Isaac Aggrey Ivano Coppola Jacob Harris Cryer Kragh Jacob Parker From 78dc226617d18bbdfbe202c79af6ec0575d6186d Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 19 Dec 2012 12:30:36 -0800 Subject: [PATCH 07/22] Register snapshots --- src/snapshots.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/snapshots.txt b/src/snapshots.txt index 4c37c3f4027dc..1baf5728a58fb 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,11 @@ +S 2012-12-18 9057e98 + linux-i386 9af73f943484188db6723d027f1cd9bdcb8d7598 + linux-x86_64 f7046c4bd5e0ce792f030fb87f7ee1d489181e36 + macos-i386 9ca811bf461d52878eaaebe24c8a17cbeed4536f + macos-x86_64 ebdd7ba76f24bb7a345cb9cdb5b41455858b8b25 + winnt-i386 da8074c67dc6843818353341bfa83069f9383b88 + freebsd-x86_64 5c13f1231eb0c9fef76465b9dbcb0f3865300e78 + S 2012-12-14 dbc52ce macos-i386 994697c57810b8f139d71df47024512970db860c macos-x86_64 f8faa6a80b0b98b27ceee6fec71ded7ca058104d From dac88fa7e6b9ca14d352981183073e0f8d7d96ae Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 19 Dec 2012 14:17:53 -0800 Subject: [PATCH 08/22] Remove transitional path2 attribute --- src/librustc/rustc.rc | 4 ++-- src/libsyntax/parse/parser.rs | 22 ++++++++-------------- src/libsyntax/syntax.rc | 4 ++-- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc index ae37c160cbad3..85d440ebff9cc 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rc @@ -104,7 +104,7 @@ mod middle { mod ty; #[legacy_exports] mod resolve; - #[path2 = "typeck/mod.rs"] + #[path = "typeck/mod.rs"] pub mod typeck; #[legacy_exports] mod check_loop; @@ -114,7 +114,7 @@ mod middle { mod check_const; #[legacy_exports] mod lint; - #[path2 = "borrowck/mod.rs"] + #[path = "borrowck/mod.rs"] pub mod borrowck; #[legacy_exports] mod mem_categorization; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 8622222e49bf8..2b83404e065e2 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3038,23 +3038,17 @@ impl Parser { let prefix = prefix.dir_path(); let mod_path = Path(".").push_many(self.mod_path_stack); let default_path = self.sess.interner.get(id) + ~".rs"; - // XXX path2 and path are synonyms. Remove path2 after snapshot let file_path = match ::attr::first_attr_value_str_by_name( - outer_attrs, ~"path2") { - - Some(ref d) => mod_path.push(*d), - None => match ::attr::first_attr_value_str_by_name( - outer_attrs, ~"path") { - Some(ref d) => { - let path = Path(*d); - if !path.is_absolute { - mod_path.push(*d) - } else { - path - } + outer_attrs, ~"path") { + Some(ref d) => { + let path = Path(*d); + if !path.is_absolute { + mod_path.push(*d) + } else { + path } - None => mod_path.push(default_path) } + None => mod_path.push(default_path) }; self.eval_src_mod_from_path(prefix, file_path, diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rc index 50dcf5de63db9..12d93b4b5c931 100644 --- a/src/libsyntax/syntax.rc +++ b/src/libsyntax/syntax.rc @@ -55,7 +55,7 @@ mod fold; mod util { #[legacy_exports]; #[legacy_exports] - #[path2 = "interner.rs"] + #[path = "interner.rs"] mod interner; } @@ -110,7 +110,7 @@ mod ext { mod source_util; #[legacy_exports] - #[path2 = "pipes/mod.rs"] + #[path = "pipes/mod.rs"] mod pipes; #[legacy_exports] From bb66fce3671f28a880ac7e8b2bfd8d76fe0eb4db Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 19 Dec 2012 14:43:47 -0800 Subject: [PATCH 09/22] Mention module/type namespace merge in release notes --- RELEASES.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RELEASES.txt b/RELEASES.txt index cafbe059b4435..b3b81964d85ad 100644 --- a/RELEASES.txt +++ b/RELEASES.txt @@ -26,6 +26,9 @@ Version 0.5 (December 2012) * `&T` may now be coerced to `*T` * Coercions happen in `let` statements as well as function calls * `use` statements now take crate-relative paths + * The module and type namespaces have been merged so that static + method names can be resolved under the trait in which they are + declared * Improved support for language features * Trait inheritance works in many scenarios From 46766974c73ff17a3b2cd4f2fb2cb06b7845ded4 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 19 Dec 2012 16:55:34 -0800 Subject: [PATCH 10/22] doc: mention moved and copied types. cc: #4217 --- doc/rust.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/doc/rust.md b/doc/rust.md index c22756657b76a..b521eb7983572 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -1465,6 +1465,14 @@ when evaluated in an _rvalue context_, it denotes the value held _in_ that memor When an rvalue is used in lvalue context, a temporary un-named lvalue is created and used instead. A temporary's lifetime equals the largest lifetime of any borrowed pointer that points to it. +#### Moved and copied types + +When a [local variable](#memory-slots) is used as an [rvalue](#lvalues-rvalues-and-temporaries) +the variable will either be [moved](#move-expressions) or [copied](#copy-expressions), +depending on its type. +For types that contain mutable fields or [owning pointers](#owning-pointers), the variable is moved. +All other types are copied. + ### Literal expressions @@ -1787,7 +1795,7 @@ y.z <-> b.c; An _assignment expression_ consists of an [lvalue](#lvalues-rvalues-and-temporaries) expression followed by an equals sign (`=`) and an [rvalue](#lvalues-rvalues-and-temporaries) expression. -Evaluating an assignment expression copies the expression on the right-hand side and stores it in the location on the left-hand side. +Evaluating an assignment expression [either copies or moves](#moved-and-copied-types) its right-hand operand to its left-hand operand. ~~~~ # let mut x = 0; @@ -1860,7 +1868,7 @@ copy. as are raw and borrowed pointers. [Owned boxes](#pointer-types), [owned vectors](#vector-types) and similar owned types are deep-copied. -Since the binary [assignment operator](#assignment-expressions) `=` performs a copy implicitly, +Since the binary [assignment operator](#assignment-expressions) `=` performs a copy or move implicitly, the unary copy operator is typically only used to cause an argument to a function to be copied and passed by value. An example of a copy expression: @@ -1884,13 +1892,17 @@ move_expr : "move" expr ; ~~~~~~~~ A _unary move expression_ is similar to a [unary copy](#unary-copy-expressions) expression, -except that it can only be applied to an [lvalue](#lvalues-rvalues-and-temporaries), +except that it can only be applied to a [local variable](#memory-slots), and it performs a _move_ on its operand, rather than a copy. That is, the memory location denoted by its operand is de-initialized after evaluation, and the resulting value is a shallow copy of the operand, even if the operand is an [owning type](#type-kinds). +> **Note:** In future versions of Rust, `move` may be removed as a separate operator; +> moves are now [automatically performed](#moved-and-copied-types) for most cases `move` would be appropriate. + + ### Call expressions ~~~~~~~~ {.abnf .gram} From e0072e39a788ada2a636ab88a0b97534544c4125 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 19 Dec 2012 17:24:19 -0800 Subject: [PATCH 11/22] doc: structure expressions. cc: #4217 --- doc/rust.md | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/doc/rust.md b/doc/rust.md index b521eb7983572..c73211acef937 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -1503,6 +1503,39 @@ values. ("a", 4u, true); ~~~~~~~~ +### Structure expressions + +~~~~~~~~{.ebnf .gram} +struct_expr : expr_path '{' ident ':' expr + [ ',' ident ':' expr ] * + [ ".." expr ] '}' +~~~~~~~~ + +A _structure expression_ consists of the [path](#paths) of a [structure item](#structures), +followed by a brace-enclosed list of one or more comma-separated name-value pairs, +providing the field values of a new instance of the structure. +A field name can be any identifier, and is separated from its value expression by a colon. +To indicate that a field is mutable, the `mut` keyword is written before its name. + +The following are examples of structure expressions: + +~~~~ +Point {x: 10f, y: 20f}; +game::User {name: "Joe", age: 35u, mut score: 100_000}; +~~~~ + +A structure expression forms a new value of the named structure type. + +A structure expression can terminate with the syntax `..` followed by an expression to denote a functional update. +The expression following `..` (the base) must be of the same structure type as the new structure type being formed. +A new structure will be created, of the same type as the base expression, with the given values for the fields that were explicitly specified, +and the values in the base record for all other fields. + +~~~~ +let base = Point3d {x: 1, y: 2, z: 3}; +Point3d {y: 0, z: 10, .. base}; +~~~~ + ### Record expressions ~~~~~~~~{.ebnf .gram} @@ -1511,9 +1544,11 @@ rec_expr : '{' ident ':' expr [ ".." expr ] '}' ~~~~~~~~ +> **Note:** In future versions of Rust, record expressions and [record types](#record-types) will be removed. + A [_record_](#record-types) _expression_ is one or more comma-separated -name-value pairs enclosed by braces. A fieldname can be any identifier -(including keywords), and is separated from its value expression by a +name-value pairs enclosed by braces. A fieldname can be any identifier, +and is separated from its value expression by a colon. To indicate that a field is mutable, the `mut` keyword is written before its name. From 6742c982a46fb9fcad190d6b9c2c2fc1370a354b Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 19 Dec 2012 18:03:03 -0800 Subject: [PATCH 12/22] Bump version numbers in docs --- README.md | 10 +++++----- doc/tutorial.md | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 9f875ac346e1c..1c0a86b1fdfbb 100644 --- a/README.md +++ b/README.md @@ -42,9 +42,9 @@ packages: Assuming you're on a relatively modern *nix system and have met the prerequisites, something along these lines should work. - $ wget http://dl.rust-lang.org/dist/rust-0.4.tar.gz - $ tar -xzf rust-0.4.tar.gz - $ cd rust-0.4 + $ wget http://dl.rust-lang.org/dist/rust-0.5.tar.gz + $ tar -xzf rust-0.5.tar.gz + $ cd rust-0.5 $ ./configure $ make && make install @@ -59,8 +59,8 @@ When complete, `make install` will place several programs into API-documentation tool, and `cargo`, the Rust package manager. [wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust -[tarball]: http://dl.rust-lang.org/dist/rust-0.4.tar.gz -[win-exe]: http://dl.rust-lang.org/dist/rust-0.4-install.exe +[tarball]: http://dl.rust-lang.org/dist/rust-0.5.tar.gz +[win-exe]: http://dl.rust-lang.org/dist/rust-0.5-install.exe ## License diff --git a/doc/tutorial.md b/doc/tutorial.md index de1b1a56f1c87..b7eab9b792163 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -100,9 +100,9 @@ If you've fulfilled those prerequisites, something along these lines should work. ~~~~ {.notrust} -$ curl -O http://dl.rust-lang.org/dist/rust-0.4.tar.gz -$ tar -xzf rust-0.4.tar.gz -$ cd rust-0.4 +$ curl -O http://dl.rust-lang.org/dist/rust-0.5.tar.gz +$ tar -xzf rust-0.5.tar.gz +$ cd rust-0.5 $ ./configure $ make && make install ~~~~ @@ -118,8 +118,8 @@ When complete, `make install` will place several programs into API-documentation tool, and `cargo`, the Rust package manager. [wiki-start]: https://github.com/mozilla/rust/wiki/Note-getting-started-developing-Rust -[tarball]: http://dl.rust-lang.org/dist/rust-0.4.tar.gz -[win-exe]: http://dl.rust-lang.org/dist/rust-0.4-install.exe +[tarball]: http://dl.rust-lang.org/dist/rust-0.5.tar.gz +[win-exe]: http://dl.rust-lang.org/dist/rust-0.5-install.exe ## Compiling your first program From 9c673b246c69d1cdcffbaf0e5cf012941b0b78e2 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Mon, 10 Dec 2012 08:11:56 -0800 Subject: [PATCH 13/22] Remove the old serialization code Closes #3713. --- src/libstd/serialization.rs | 585 --------------- src/libstd/std.rc | 6 +- src/libsyntax/ext/auto_serialize.rs | 1028 --------------------------- src/libsyntax/ext/base.rs | 6 - src/libsyntax/syntax.rc | 2 - 5 files changed, 1 insertion(+), 1626 deletions(-) delete mode 100644 src/libstd/serialization.rs delete mode 100644 src/libsyntax/ext/auto_serialize.rs diff --git a/src/libstd/serialization.rs b/src/libstd/serialization.rs deleted file mode 100644 index 8a3e6213325a7..0000000000000 --- a/src/libstd/serialization.rs +++ /dev/null @@ -1,585 +0,0 @@ -// Copyright 2012 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. - -//! Support code for serialization. - -/* -Core serialization interfaces. -*/ - -#[forbid(deprecated_mode)]; -#[forbid(non_camel_case_types)]; - -pub trait Serializer { - // Primitive types: - fn emit_nil(&self); - fn emit_uint(&self, v: uint); - fn emit_u64(&self, v: u64); - fn emit_u32(&self, v: u32); - fn emit_u16(&self, v: u16); - fn emit_u8(&self, v: u8); - fn emit_int(&self, v: int); - fn emit_i64(&self, v: i64); - fn emit_i32(&self, v: i32); - fn emit_i16(&self, v: i16); - fn emit_i8(&self, v: i8); - fn emit_bool(&self, v: bool); - fn emit_float(&self, v: float); - fn emit_f64(&self, v: f64); - fn emit_f32(&self, v: f32); - fn emit_char(&self, v: char); - fn emit_borrowed_str(&self, v: &str); - fn emit_owned_str(&self, v: &str); - fn emit_managed_str(&self, v: &str); - - // Compound types: - fn emit_borrowed(&self, f: fn()); - fn emit_owned(&self, f: fn()); - fn emit_managed(&self, f: fn()); - - fn emit_enum(&self, name: &str, f: fn()); - fn emit_enum_variant(&self, v_name: &str, v_id: uint, sz: uint, f: fn()); - fn emit_enum_variant_arg(&self, idx: uint, f: fn()); - - fn emit_borrowed_vec(&self, len: uint, f: fn()); - fn emit_owned_vec(&self, len: uint, f: fn()); - fn emit_managed_vec(&self, len: uint, f: fn()); - fn emit_vec_elt(&self, idx: uint, f: fn()); - - fn emit_rec(&self, f: fn()); - fn emit_struct(&self, name: &str, f: fn()); - fn emit_field(&self, f_name: &str, f_idx: uint, f: fn()); - - fn emit_tup(&self, len: uint, f: fn()); - fn emit_tup_elt(&self, idx: uint, f: fn()); -} - -pub trait Deserializer { - // Primitive types: - fn read_nil(&self) -> (); - fn read_uint(&self) -> uint; - fn read_u64(&self) -> u64; - fn read_u32(&self) -> u32; - fn read_u16(&self) -> u16; - fn read_u8(&self) -> u8; - fn read_int(&self) -> int; - fn read_i64(&self) -> i64; - fn read_i32(&self) -> i32; - fn read_i16(&self) -> i16; - fn read_i8(&self) -> i8; - fn read_bool(&self) -> bool; - fn read_f64(&self) -> f64; - fn read_f32(&self) -> f32; - fn read_float(&self) -> float; - fn read_char(&self) -> char; - fn read_owned_str(&self) -> ~str; - fn read_managed_str(&self) -> @str; - - // Compound types: - fn read_enum(&self, name: &str, f: fn() -> T) -> T; - fn read_enum_variant(&self, f: fn(uint) -> T) -> T; - fn read_enum_variant_arg(&self, idx: uint, f: fn() -> T) -> T; - - fn read_owned(&self, f: fn() -> T) -> T; - fn read_managed(&self, f: fn() -> T) -> T; - - fn read_owned_vec(&self, f: fn(uint) -> T) -> T; - fn read_managed_vec(&self, f: fn(uint) -> T) -> T; - fn read_vec_elt(&self, idx: uint, f: fn() -> T) -> T; - - fn read_rec(&self, f: fn() -> T) -> T; - fn read_struct(&self, name: &str, f: fn() -> T) -> T; - fn read_field(&self, name: &str, idx: uint, f: fn() -> T) -> T; - - fn read_tup(&self, sz: uint, f: fn() -> T) -> T; - fn read_tup_elt(&self, idx: uint, f: fn() -> T) -> T; -} - -pub mod traits { -pub trait Serializable { - fn serialize(&self, s: &S); -} - -pub trait Deserializable { - static fn deserialize(&self, d: &D) -> self; -} - -pub impl uint: Serializable { - fn serialize(&self, s: &S) { s.emit_uint(*self) } -} - -pub impl uint: Deserializable { - static fn deserialize(&self, d: &D) -> uint { - d.read_uint() - } -} - -pub impl u8: Serializable { - fn serialize(&self, s: &S) { s.emit_u8(*self) } -} - -pub impl u8: Deserializable { - static fn deserialize(&self, d: &D) -> u8 { - d.read_u8() - } -} - -pub impl u16: Serializable { - fn serialize(&self, s: &S) { s.emit_u16(*self) } -} - -pub impl u16: Deserializable { - static fn deserialize(&self, d: &D) -> u16 { - d.read_u16() - } -} - -pub impl u32: Serializable { - fn serialize(&self, s: &S) { s.emit_u32(*self) } -} - -pub impl u32: Deserializable { - static fn deserialize(&self, d: &D) -> u32 { - d.read_u32() - } -} - -pub impl u64: Serializable { - fn serialize(&self, s: &S) { s.emit_u64(*self) } -} - -pub impl u64: Deserializable { - static fn deserialize(&self, d: &D) -> u64 { - d.read_u64() - } -} - -pub impl int: Serializable { - fn serialize(&self, s: &S) { s.emit_int(*self) } -} - -pub impl int: Deserializable { - static fn deserialize(&self, d: &D) -> int { - d.read_int() - } -} - -pub impl i8: Serializable { - fn serialize(&self, s: &S) { s.emit_i8(*self) } -} - -pub impl i8: Deserializable { - static fn deserialize(&self, d: &D) -> i8 { - d.read_i8() - } -} - -pub impl i16: Serializable { - fn serialize(&self, s: &S) { s.emit_i16(*self) } -} - -pub impl i16: Deserializable { - static fn deserialize(&self, d: &D) -> i16 { - d.read_i16() - } -} - -pub impl i32: Serializable { - fn serialize(&self, s: &S) { s.emit_i32(*self) } -} - -pub impl i32: Deserializable { - static fn deserialize(&self, d: &D) -> i32 { - d.read_i32() - } -} - -pub impl i64: Serializable { - fn serialize(&self, s: &S) { s.emit_i64(*self) } -} - -pub impl i64: Deserializable { - static fn deserialize(&self, d: &D) -> i64 { - d.read_i64() - } -} - -pub impl &str: Serializable { - fn serialize(&self, s: &S) { s.emit_borrowed_str(*self) } -} - -pub impl ~str: Serializable { - fn serialize(&self, s: &S) { s.emit_owned_str(*self) } -} - -pub impl ~str: Deserializable { - static fn deserialize(&self, d: &D) -> ~str { - d.read_owned_str() - } -} - -pub impl @str: Serializable { - fn serialize(&self, s: &S) { s.emit_managed_str(*self) } -} - -pub impl @str: Deserializable { - static fn deserialize(&self, d: &D) -> @str { - d.read_managed_str() - } -} - -pub impl float: Serializable { - fn serialize(&self, s: &S) { s.emit_float(*self) } -} - -pub impl float: Deserializable { - static fn deserialize(&self, d: &D) -> float { - d.read_float() - } -} - -pub impl f32: Serializable { - fn serialize(&self, s: &S) { s.emit_f32(*self) } -} - -pub impl f32: Deserializable { - static fn deserialize(&self, d: &D) -> f32 { - d.read_f32() } -} - -pub impl f64: Serializable { - fn serialize(&self, s: &S) { s.emit_f64(*self) } -} - -pub impl f64: Deserializable { - static fn deserialize(&self, d: &D) -> f64 { - d.read_f64() - } -} - -pub impl bool: Serializable { - fn serialize(&self, s: &S) { s.emit_bool(*self) } -} - -pub impl bool: Deserializable { - static fn deserialize(&self, d: &D) -> bool { - d.read_bool() - } -} - -pub impl (): Serializable { - fn serialize(&self, s: &S) { s.emit_nil() } -} - -pub impl (): Deserializable { - static fn deserialize(&self, d: &D) -> () { - d.read_nil() - } -} - -pub impl> &T: Serializable { - fn serialize(&self, s: &S) { - s.emit_borrowed(|| (**self).serialize(s)) - } -} - -pub impl> ~T: Serializable { - fn serialize(&self, s: &S) { - s.emit_owned(|| (**self).serialize(s)) - } -} - -pub impl> ~T: Deserializable { - static fn deserialize(&self, d: &D) -> ~T { - d.read_owned(|| ~deserialize(d)) - } -} - -pub impl> @T: Serializable { - fn serialize(&self, s: &S) { - s.emit_managed(|| (**self).serialize(s)) - } -} - -pub impl> @T: Deserializable { - static fn deserialize(&self, d: &D) -> @T { - d.read_managed(|| @deserialize(d)) - } -} - -pub impl> &[T]: Serializable { - fn serialize(&self, s: &S) { - do s.emit_borrowed_vec(self.len()) { - for self.eachi |i, e| { - s.emit_vec_elt(i, || e.serialize(s)) - } - } - } -} - -pub impl> ~[T]: Serializable { - fn serialize(&self, s: &S) { - do s.emit_owned_vec(self.len()) { - for self.eachi |i, e| { - s.emit_vec_elt(i, || e.serialize(s)) - } - } - } -} - -pub impl> ~[T]: Deserializable { - static fn deserialize(&self, d: &D) -> ~[T] { - do d.read_owned_vec |len| { - do vec::from_fn(len) |i| { - d.read_vec_elt(i, || deserialize(d)) - } - } - } -} - -pub impl> @[T]: Serializable { - fn serialize(&self, s: &S) { - do s.emit_managed_vec(self.len()) { - for self.eachi |i, e| { - s.emit_vec_elt(i, || e.serialize(s)) - } - } - } -} - -pub impl> @[T]: Deserializable { - static fn deserialize(&self, d: &D) -> @[T] { - do d.read_managed_vec |len| { - do at_vec::from_fn(len) |i| { - d.read_vec_elt(i, || deserialize(d)) - } - } - } -} - -pub impl> Option: Serializable { - fn serialize(&self, s: &S) { - do s.emit_enum(~"option") { - match *self { - None => do s.emit_enum_variant(~"none", 0u, 0u) { - }, - - Some(ref v) => do s.emit_enum_variant(~"some", 1u, 1u) { - s.emit_enum_variant_arg(0u, || v.serialize(s)) - } - } - } - } -} - -pub impl> Option: Deserializable { - static fn deserialize(&self, d: &D) -> Option { - do d.read_enum(~"option") { - do d.read_enum_variant |i| { - match i { - 0 => None, - 1 => Some(d.read_enum_variant_arg(0u, || deserialize(d))), - _ => fail(fmt!("Bad variant for option: %u", i)) - } - } - } - } -} - -pub impl< - S: Serializer, - T0: Serializable, - T1: Serializable -> (T0, T1): Serializable { - fn serialize(&self, s: &S) { - match *self { - (ref t0, ref t1) => { - do s.emit_tup(2) { - s.emit_tup_elt(0, || t0.serialize(s)); - s.emit_tup_elt(1, || t1.serialize(s)); - } - } - } - } -} - -pub impl< - D: Deserializer, - T0: Deserializable, - T1: Deserializable -> (T0, T1): Deserializable { - static fn deserialize(&self, d: &D) -> (T0, T1) { - do d.read_tup(2) { - ( - d.read_tup_elt(0, || deserialize(d)), - d.read_tup_elt(1, || deserialize(d)) - ) - } - } -} - -pub impl< - S: Serializer, - T0: Serializable, - T1: Serializable, - T2: Serializable -> (T0, T1, T2): Serializable { - fn serialize(&self, s: &S) { - match *self { - (ref t0, ref t1, ref t2) => { - do s.emit_tup(3) { - s.emit_tup_elt(0, || t0.serialize(s)); - s.emit_tup_elt(1, || t1.serialize(s)); - s.emit_tup_elt(2, || t2.serialize(s)); - } - } - } - } -} - -pub impl< - D: Deserializer, - T0: Deserializable, - T1: Deserializable, - T2: Deserializable -> (T0, T1, T2): Deserializable { - static fn deserialize(&self, d: &D) -> (T0, T1, T2) { - do d.read_tup(3) { - ( - d.read_tup_elt(0, || deserialize(d)), - d.read_tup_elt(1, || deserialize(d)), - d.read_tup_elt(2, || deserialize(d)) - ) - } - } -} - -pub impl< - S: Serializer, - T0: Serializable, - T1: Serializable, - T2: Serializable, - T3: Serializable -> (T0, T1, T2, T3): Serializable { - fn serialize(&self, s: &S) { - match *self { - (ref t0, ref t1, ref t2, ref t3) => { - do s.emit_tup(4) { - s.emit_tup_elt(0, || t0.serialize(s)); - s.emit_tup_elt(1, || t1.serialize(s)); - s.emit_tup_elt(2, || t2.serialize(s)); - s.emit_tup_elt(3, || t3.serialize(s)); - } - } - } - } -} - -pub impl< - D: Deserializer, - T0: Deserializable, - T1: Deserializable, - T2: Deserializable, - T3: Deserializable -> (T0, T1, T2, T3): Deserializable { - static fn deserialize(&self, d: &D) -> (T0, T1, T2, T3) { - do d.read_tup(4) { - ( - d.read_tup_elt(0, || deserialize(d)), - d.read_tup_elt(1, || deserialize(d)), - d.read_tup_elt(2, || deserialize(d)), - d.read_tup_elt(3, || deserialize(d)) - ) - } - } -} - -pub impl< - S: Serializer, - T0: Serializable, - T1: Serializable, - T2: Serializable, - T3: Serializable, - T4: Serializable -> (T0, T1, T2, T3, T4): Serializable { - fn serialize(&self, s: &S) { - match *self { - (ref t0, ref t1, ref t2, ref t3, ref t4) => { - do s.emit_tup(5) { - s.emit_tup_elt(0, || t0.serialize(s)); - s.emit_tup_elt(1, || t1.serialize(s)); - s.emit_tup_elt(2, || t2.serialize(s)); - s.emit_tup_elt(3, || t3.serialize(s)); - s.emit_tup_elt(4, || t4.serialize(s)); - } - } - } - } -} - -pub impl< - D: Deserializer, - T0: Deserializable, - T1: Deserializable, - T2: Deserializable, - T3: Deserializable, - T4: Deserializable -> (T0, T1, T2, T3, T4): Deserializable { - static fn deserialize(&self, d: &D) - -> (T0, T1, T2, T3, T4) { - do d.read_tup(5) { - ( - d.read_tup_elt(0, || deserialize(d)), - d.read_tup_elt(1, || deserialize(d)), - d.read_tup_elt(2, || deserialize(d)), - d.read_tup_elt(3, || deserialize(d)), - d.read_tup_elt(4, || deserialize(d)) - ) - } - } -} - -// ___________________________________________________________________________ -// Helper routines -// -// In some cases, these should eventually be coded as traits. - -pub trait SerializerHelpers { - fn emit_from_vec(&self, v: ~[T], f: fn(v: &T)); -} - -pub impl S: SerializerHelpers { - fn emit_from_vec(&self, v: ~[T], f: fn(v: &T)) { - do self.emit_owned_vec(v.len()) { - for v.eachi |i, e| { - do self.emit_vec_elt(i) { - f(e) - } - } - } - } -} - -pub trait DeserializerHelpers { - fn read_to_vec(&self, f: fn() -> T) -> ~[T]; -} - -pub impl D: DeserializerHelpers { - fn read_to_vec(&self, f: fn() -> T) -> ~[T] { - do self.read_owned_vec |len| { - do vec::from_fn(len) |i| { - self.read_vec_elt(i, || f()) - } - } - } -} -} - -pub use serialization::traits::*; diff --git a/src/libstd/std.rc b/src/libstd/std.rc index 918781cffb5d5..eb3a741082801 100644 --- a/src/libstd/std.rc +++ b/src/libstd/std.rc @@ -30,7 +30,7 @@ not required in or otherwise suitable for the core library. #[allow(vecs_implicitly_copyable)]; #[deny(non_camel_case_types)]; -// XXX this is set to allow because there are two methods in serialization +// XXX this is set to allow because there are two methods in encoding // that can't be silenced otherwise. Most every module is set to forbid #[allow(deprecated_mode)]; #[forbid(deprecated_pattern)]; @@ -107,8 +107,6 @@ mod unicode; pub mod test; pub mod serialize; -#[cfg(stage0)] -pub mod serialization; // A curious inner-module that's not exported that contains the binding // 'std' so that macro-expanded references to std::serialize and such @@ -116,8 +114,6 @@ pub mod serialization; #[doc(hidden)] // FIXME #3538 mod std { pub use serialize; - #[cfg(stage0)] - pub use serialization; } // Local Variables: diff --git a/src/libsyntax/ext/auto_serialize.rs b/src/libsyntax/ext/auto_serialize.rs deleted file mode 100644 index 4c1725b10000c..0000000000000 --- a/src/libsyntax/ext/auto_serialize.rs +++ /dev/null @@ -1,1028 +0,0 @@ -// Copyright 2012 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 compiler code necessary to implement the #[auto_serialize] and -#[auto_deserialize] extension. The idea here is that type-defining items may -be tagged with #[auto_serialize] and #[auto_deserialize], which will cause -us to generate a little companion module with the same name as the item. - -For example, a type like: - - #[auto_serialize] - #[auto_deserialize] - struct Node {id: uint} - -would generate two implementations like: - - impl node_id: Serializable { - fn serialize(s: &S) { - do s.emit_struct("Node") { - s.emit_field("id", 0, || s.emit_uint(self)) - } - } - } - - impl node_id: Deserializable { - static fn deserialize(d: &D) -> Node { - do d.read_struct("Node") { - Node { - id: d.read_field(~"x", 0, || deserialize(d)) - } - } - } - } - -Other interesting scenarios are whe the item has type parameters or -references other non-built-in types. A type definition like: - - #[auto_serialize] - #[auto_deserialize] - type spanned = {node: T, span: span}; - -would yield functions like: - - impl< - S: Serializer, - T: Serializable - > spanned: Serializable { - fn serialize(s: &S) { - do s.emit_rec { - s.emit_field("node", 0, || self.node.serialize(s)); - s.emit_field("span", 1, || self.span.serialize(s)); - } - } - } - - impl< - D: Deserializer, - T: Deserializable - > spanned: Deserializable { - static fn deserialize(d: &D) -> spanned { - do d.read_rec { - { - node: d.read_field(~"node", 0, || deserialize(d)), - span: d.read_field(~"span", 1, || deserialize(d)), - } - } - } - } - -FIXME (#2810)--Hygiene. Search for "__" strings. We also assume "std" is the -standard library. - -Misc notes: ------------ - -I use move mode arguments for ast nodes that will get inserted as is -into the tree. This is intended to prevent us from inserting the same -node twice. - -*/ - -use ext::base::*; -use codemap::span; -use std::map; -use std::map::HashMap; - -export expand_auto_serialize; -export expand_auto_deserialize; - -// Transitional reexports so qquote can find the paths it is looking for -mod syntax { - pub use ext; - pub use parse; -} - -fn expand_auto_serialize( - cx: ext_ctxt, - span: span, - _mitem: ast::meta_item, - in_items: ~[@ast::item] -) -> ~[@ast::item] { - fn is_auto_serialize(a: &ast::attribute) -> bool { - attr::get_attr_name(*a) == ~"auto_serialize" - } - - fn filter_attrs(item: @ast::item) -> @ast::item { - @{attrs: vec::filter(item.attrs, |a| !is_auto_serialize(a)), - .. *item} - } - - do vec::flat_map(in_items) |item| { - if item.attrs.any(is_auto_serialize) { - match item.node { - ast::item_ty(@{node: ast::ty_rec(ref fields), _}, tps) => { - let ser_impl = mk_rec_ser_impl( - cx, - item.span, - item.ident, - (*fields), - tps - ); - - ~[filter_attrs(*item), ser_impl] - }, - ast::item_struct(@{ fields, _}, tps) => { - let ser_impl = mk_struct_ser_impl( - cx, - item.span, - item.ident, - fields, - tps - ); - - ~[filter_attrs(*item), ser_impl] - }, - ast::item_enum(ref enum_def, tps) => { - let ser_impl = mk_enum_ser_impl( - cx, - item.span, - item.ident, - (*enum_def), - tps - ); - - ~[filter_attrs(*item), ser_impl] - }, - _ => { - cx.span_err(span, ~"#[auto_serialize] can only be \ - applied to structs, record types, \ - and enum definitions"); - ~[*item] - } - } - } else { - ~[*item] - } - } -} - -fn expand_auto_deserialize( - cx: ext_ctxt, - span: span, - _mitem: ast::meta_item, - in_items: ~[@ast::item] -) -> ~[@ast::item] { - fn is_auto_deserialize(a: &ast::attribute) -> bool { - attr::get_attr_name(*a) == ~"auto_deserialize" - } - - fn filter_attrs(item: @ast::item) -> @ast::item { - @{attrs: vec::filter(item.attrs, |a| !is_auto_deserialize(a)), - .. *item} - } - - do vec::flat_map(in_items) |item| { - if item.attrs.any(is_auto_deserialize) { - match item.node { - ast::item_ty(@{node: ast::ty_rec(ref fields), _}, tps) => { - let deser_impl = mk_rec_deser_impl( - cx, - item.span, - item.ident, - (*fields), - tps - ); - - ~[filter_attrs(*item), deser_impl] - }, - ast::item_struct(@{ fields, _}, tps) => { - let deser_impl = mk_struct_deser_impl( - cx, - item.span, - item.ident, - fields, - tps - ); - - ~[filter_attrs(*item), deser_impl] - }, - ast::item_enum(ref enum_def, tps) => { - let deser_impl = mk_enum_deser_impl( - cx, - item.span, - item.ident, - (*enum_def), - tps - ); - - ~[filter_attrs(*item), deser_impl] - }, - _ => { - cx.span_err(span, ~"#[auto_deserialize] can only be \ - applied to structs, record types, \ - and enum definitions"); - ~[*item] - } - } - } else { - ~[*item] - } - } -} - -fn mk_impl( - cx: ext_ctxt, - span: span, - ident: ast::ident, - ty_param: ast::ty_param, - path: @ast::path, - tps: ~[ast::ty_param], - f: fn(@ast::Ty) -> @ast::method -) -> @ast::item { - // All the type parameters need to bound to the trait. - let mut trait_tps = vec::append( - ~[ty_param], - do tps.map |tp| { - let t_bound = ast::ty_param_bound(@{ - id: cx.next_id(), - node: ast::ty_path(path, cx.next_id()), - span: span, - }); - - { - ident: tp.ident, - id: cx.next_id(), - bounds: @vec::append(~[t_bound], *tp.bounds) - } - } - ); - - let opt_trait = Some(@{ - path: path, - ref_id: cx.next_id(), - }); - - let ty = cx.ty_path( - span, - ~[ident], - tps.map(|tp| cx.ty_path(span, ~[tp.ident], ~[])) - ); - - @{ - // This is a new-style impl declaration. - // XXX: clownshoes - ident: ast::token::special_idents::clownshoes_extensions, - attrs: ~[], - id: cx.next_id(), - node: ast::item_impl(trait_tps, opt_trait, ty, ~[f(ty)]), - vis: ast::public, - span: span, - } -} - -fn mk_ser_impl( - cx: ext_ctxt, - span: span, - ident: ast::ident, - tps: ~[ast::ty_param], - body: @ast::expr -) -> @ast::item { - // Make a path to the std::serialization::Serializable typaram. - let ty_param = cx.bind_path( - span, - cx.ident_of(~"__S"), - cx.path( - span, - ~[ - cx.ident_of(~"std"), - cx.ident_of(~"serialization"), - cx.ident_of(~"Serializer"), - ] - ), - @~[] - ); - - // Make a path to the std::serialization::Serializable trait. - let path = cx.path_tps( - span, - ~[ - cx.ident_of(~"std"), - cx.ident_of(~"serialization"), - cx.ident_of(~"Serializable"), - ], - ~[cx.ty_path(span, ~[cx.ident_of(~"__S")], ~[])] - ); - - mk_impl( - cx, - span, - ident, - ty_param, - path, - tps, - |_ty| mk_ser_method(cx, span, cx.expr_blk(body)) - ) -} - -fn mk_deser_impl( - cx: ext_ctxt, - span: span, - ident: ast::ident, - tps: ~[ast::ty_param], - body: @ast::expr -) -> @ast::item { - // Make a path to the std::serialization::Deserializable typaram. - let ty_param = cx.bind_path( - span, - cx.ident_of(~"__D"), - cx.path( - span, - ~[ - cx.ident_of(~"std"), - cx.ident_of(~"serialization"), - cx.ident_of(~"Deserializer"), - ] - ), - @~[] - ); - - // Make a path to the std::serialization::Deserializable trait. - let path = cx.path_tps( - span, - ~[ - cx.ident_of(~"std"), - cx.ident_of(~"serialization"), - cx.ident_of(~"Deserializable"), - ], - ~[cx.ty_path(span, ~[cx.ident_of(~"__D")], ~[])] - ); - - mk_impl( - cx, - span, - ident, - ty_param, - path, - tps, - |ty| mk_deser_method(cx, span, ty, cx.expr_blk(body)) - ) -} - -fn mk_ser_method( - cx: ext_ctxt, - span: span, - ser_body: ast::blk -) -> @ast::method { - let ty_s = @{ - id: cx.next_id(), - node: ast::ty_rptr( - @{ - id: cx.next_id(), - node: ast::re_anon, - }, - { - ty: cx.ty_path(span, ~[cx.ident_of(~"__S")], ~[]), - mutbl: ast::m_imm - } - ), - span: span, - }; - - let ser_inputs = ~[{ - mode: ast::infer(cx.next_id()), - ty: ty_s, - pat: @{id: cx.next_id(), - node: ast::pat_ident( - ast::bind_by_value, - ast_util::ident_to_path(span, cx.ident_of(~"__s")), - None), - span: span}, - id: cx.next_id(), - }]; - - let ser_output = @{ - id: cx.next_id(), - node: ast::ty_nil, - span: span, - }; - - let ser_decl = { - inputs: ser_inputs, - output: ser_output, - cf: ast::return_val, - }; - - @{ - ident: cx.ident_of(~"serialize"), - attrs: ~[], - tps: ~[], - self_ty: { node: ast::sty_region(ast::m_imm), span: span }, - purity: ast::impure_fn, - decl: ser_decl, - body: ser_body, - id: cx.next_id(), - span: span, - self_id: cx.next_id(), - vis: ast::public, - } -} - -fn mk_deser_method( - cx: ext_ctxt, - span: span, - ty: @ast::Ty, - deser_body: ast::blk -) -> @ast::method { - let ty_d = @{ - id: cx.next_id(), - node: ast::ty_rptr( - @{ - id: cx.next_id(), - node: ast::re_anon, - }, - { - ty: cx.ty_path(span, ~[cx.ident_of(~"__D")], ~[]), - mutbl: ast::m_imm - } - ), - span: span, - }; - - let deser_inputs = ~[{ - mode: ast::infer(cx.next_id()), - ty: ty_d, - pat: @{id: cx.next_id(), - node: ast::pat_ident( - ast::bind_by_value, - ast_util::ident_to_path(span, cx.ident_of(~"__d")), - None), - span: span}, - id: cx.next_id(), - }]; - - let deser_decl = { - inputs: deser_inputs, - output: ty, - cf: ast::return_val, - }; - - @{ - ident: cx.ident_of(~"deserialize"), - attrs: ~[], - tps: ~[], - self_ty: { node: ast::sty_static, span: span }, - purity: ast::impure_fn, - decl: deser_decl, - body: deser_body, - id: cx.next_id(), - span: span, - self_id: cx.next_id(), - vis: ast::public, - } -} - -fn mk_rec_ser_impl( - cx: ext_ctxt, - span: span, - ident: ast::ident, - fields: ~[ast::ty_field], - tps: ~[ast::ty_param] -) -> @ast::item { - let fields = mk_ser_fields(cx, span, mk_rec_fields(fields)); - - // ast for `__s.emit_rec(|| $(fields))` - let body = cx.expr_call( - span, - cx.expr_field( - span, - cx.expr_var(span, ~"__s"), - cx.ident_of(~"emit_rec") - ), - ~[cx.lambda_stmts(span, fields)] - ); - - mk_ser_impl(cx, span, ident, tps, body) -} - -fn mk_rec_deser_impl( - cx: ext_ctxt, - span: span, - ident: ast::ident, - fields: ~[ast::ty_field], - tps: ~[ast::ty_param] -) -> @ast::item { - let fields = mk_deser_fields(cx, span, mk_rec_fields(fields)); - - // ast for `read_rec(|| $(fields))` - let body = cx.expr_call( - span, - cx.expr_field( - span, - cx.expr_var(span, ~"__d"), - cx.ident_of(~"read_rec") - ), - ~[ - cx.lambda_expr( - cx.expr( - span, - ast::expr_rec(fields, None) - ) - ) - ] - ); - - mk_deser_impl(cx, span, ident, tps, body) -} - -fn mk_struct_ser_impl( - cx: ext_ctxt, - span: span, - ident: ast::ident, - fields: ~[@ast::struct_field], - tps: ~[ast::ty_param] -) -> @ast::item { - let fields = mk_ser_fields(cx, span, mk_struct_fields(fields)); - - // ast for `__s.emit_struct($(name), || $(fields))` - let ser_body = cx.expr_call( - span, - cx.expr_field( - span, - cx.expr_var(span, ~"__s"), - cx.ident_of(~"emit_struct") - ), - ~[ - cx.lit_str(span, @cx.str_of(ident)), - cx.lambda_stmts(span, fields), - ] - ); - - mk_ser_impl(cx, span, ident, tps, ser_body) -} - -fn mk_struct_deser_impl( - cx: ext_ctxt, - span: span, - ident: ast::ident, - fields: ~[@ast::struct_field], - tps: ~[ast::ty_param] -) -> @ast::item { - let fields = mk_deser_fields(cx, span, mk_struct_fields(fields)); - - // ast for `read_struct($(name), || $(fields))` - let body = cx.expr_call( - span, - cx.expr_field( - span, - cx.expr_var(span, ~"__d"), - cx.ident_of(~"read_struct") - ), - ~[ - cx.lit_str(span, @cx.str_of(ident)), - cx.lambda_expr( - cx.expr( - span, - ast::expr_struct( - cx.path(span, ~[ident]), - fields, - None - ) - ) - ), - ] - ); - - mk_deser_impl(cx, span, ident, tps, body) -} - -// Records and structs don't have the same fields types, but they share enough -// that if we extract the right subfields out we can share the serialization -// generator code. -type field = { span: span, ident: ast::ident, mutbl: ast::mutability }; - -fn mk_rec_fields(fields: ~[ast::ty_field]) -> ~[field] { - do fields.map |field| { - { - span: field.span, - ident: field.node.ident, - mutbl: field.node.mt.mutbl, - } - } -} - -fn mk_struct_fields(fields: ~[@ast::struct_field]) -> ~[field] { - do fields.map |field| { - let (ident, mutbl) = match field.node.kind { - ast::named_field(ident, mutbl, _) => (ident, mutbl), - _ => fail ~"[auto_serialize] does not support \ - unnamed fields", - }; - - { - span: field.span, - ident: ident, - mutbl: match mutbl { - ast::struct_mutable => ast::m_mutbl, - ast::struct_immutable => ast::m_imm, - }, - } - } -} - -fn mk_ser_fields( - cx: ext_ctxt, - span: span, - fields: ~[field] -) -> ~[@ast::stmt] { - do fields.mapi |idx, field| { - // ast for `|| self.$(name).serialize(__s)` - let expr_lambda = cx.lambda_expr( - cx.expr_call( - span, - cx.expr_field( - span, - cx.expr_field( - span, - cx.expr_var(span, ~"self"), - field.ident - ), - cx.ident_of(~"serialize") - ), - ~[cx.expr_var(span, ~"__s")] - ) - ); - - // ast for `__s.emit_field($(name), $(idx), $(expr_lambda))` - cx.stmt( - cx.expr_call( - span, - cx.expr_field( - span, - cx.expr_var(span, ~"__s"), - cx.ident_of(~"emit_field") - ), - ~[ - cx.lit_str(span, @cx.str_of(field.ident)), - cx.lit_uint(span, idx), - expr_lambda, - ] - ) - ) - } -} - -fn mk_deser_fields( - cx: ext_ctxt, - span: span, - fields: ~[{ span: span, ident: ast::ident, mutbl: ast::mutability }] -) -> ~[ast::field] { - do fields.mapi |idx, field| { - // ast for `|| std::serialization::deserialize(__d)` - let expr_lambda = cx.lambda( - cx.expr_blk( - cx.expr_call( - span, - cx.expr_path(span, ~[ - cx.ident_of(~"std"), - cx.ident_of(~"serialization"), - cx.ident_of(~"deserialize"), - ]), - ~[cx.expr_var(span, ~"__d")] - ) - ) - ); - - // ast for `__d.read_field($(name), $(idx), $(expr_lambda))` - let expr: @ast::expr = cx.expr_call( - span, - cx.expr_field( - span, - cx.expr_var(span, ~"__d"), - cx.ident_of(~"read_field") - ), - ~[ - cx.lit_str(span, @cx.str_of(field.ident)), - cx.lit_uint(span, idx), - expr_lambda, - ] - ); - - { - node: { mutbl: field.mutbl, ident: field.ident, expr: expr }, - span: span, - } - } -} - -fn mk_enum_ser_impl( - cx: ext_ctxt, - span: span, - ident: ast::ident, - enum_def: ast::enum_def, - tps: ~[ast::ty_param] -) -> @ast::item { - let body = mk_enum_ser_body( - cx, - span, - ident, - enum_def.variants - ); - - mk_ser_impl(cx, span, ident, tps, body) -} - -fn mk_enum_deser_impl( - cx: ext_ctxt, - span: span, - ident: ast::ident, - enum_def: ast::enum_def, - tps: ~[ast::ty_param] -) -> @ast::item { - let body = mk_enum_deser_body( - cx, - span, - ident, - enum_def.variants - ); - - mk_deser_impl(cx, span, ident, tps, body) -} - -fn ser_variant( - cx: ext_ctxt, - span: span, - v_name: ast::ident, - v_idx: uint, - args: ~[ast::variant_arg] -) -> ast::arm { - // Name the variant arguments. - let names = args.mapi(|i, _arg| cx.ident_of(fmt!("__v%u", i))); - - // Bind the names to the variant argument type. - let pats = args.mapi(|i, arg| cx.binder_pat(arg.ty.span, names[i])); - - let pat_node = if pats.is_empty() { - ast::pat_ident( - ast::bind_by_ref(ast::m_imm), - cx.path(span, ~[v_name]), - None - ) - } else { - ast::pat_enum( - cx.path(span, ~[v_name]), - Some(pats) - ) - }; - - let pat = @{ - id: cx.next_id(), - node: pat_node, - span: span, - }; - - let stmts = do args.mapi |a_idx, _arg| { - // ast for `__s.emit_enum_variant_arg` - let expr_emit = cx.expr_field( - span, - cx.expr_var(span, ~"__s"), - cx.ident_of(~"emit_enum_variant_arg") - ); - - // ast for `|| $(v).serialize(__s)` - let expr_serialize = cx.lambda_expr( - cx.expr_call( - span, - cx.expr_field( - span, - cx.expr_path(span, ~[names[a_idx]]), - cx.ident_of(~"serialize") - ), - ~[cx.expr_var(span, ~"__s")] - ) - ); - - // ast for `$(expr_emit)($(a_idx), $(expr_serialize))` - cx.stmt( - cx.expr_call( - span, - expr_emit, - ~[cx.lit_uint(span, a_idx), expr_serialize] - ) - ) - }; - - // ast for `__s.emit_enum_variant($(name), $(idx), $(sz), $(lambda))` - let body = cx.expr_call( - span, - cx.expr_field( - span, - cx.expr_var(span, ~"__s"), - cx.ident_of(~"emit_enum_variant") - ), - ~[ - cx.lit_str(span, @cx.str_of(v_name)), - cx.lit_uint(span, v_idx), - cx.lit_uint(span, stmts.len()), - cx.lambda_stmts(span, stmts), - ] - ); - - { pats: ~[pat], guard: None, body: cx.expr_blk(body) } -} - -fn mk_enum_ser_body( - cx: ext_ctxt, - span: span, - name: ast::ident, - variants: ~[ast::variant] -) -> @ast::expr { - let arms = do variants.mapi |v_idx, variant| { - match variant.node.kind { - ast::tuple_variant_kind(args) => - ser_variant(cx, span, variant.node.name, v_idx, args), - ast::struct_variant_kind(*) => - fail ~"struct variants unimplemented", - ast::enum_variant_kind(*) => - fail ~"enum variants unimplemented", - } - }; - - // ast for `match *self { $(arms) }` - let match_expr = cx.expr( - span, - ast::expr_match( - cx.expr( - span, - ast::expr_unary(ast::deref, cx.expr_var(span, ~"self")) - ), - arms - ) - ); - - // ast for `__s.emit_enum($(name), || $(match_expr))` - cx.expr_call( - span, - cx.expr_field( - span, - cx.expr_var(span, ~"__s"), - cx.ident_of(~"emit_enum") - ), - ~[ - cx.lit_str(span, @cx.str_of(name)), - cx.lambda_expr(match_expr), - ] - ) -} - -fn mk_enum_deser_variant_nary( - cx: ext_ctxt, - span: span, - name: ast::ident, - args: ~[ast::variant_arg] -) -> @ast::expr { - let args = do args.mapi |idx, _arg| { - // ast for `|| std::serialization::deserialize(__d)` - let expr_lambda = cx.lambda_expr( - cx.expr_call( - span, - cx.expr_path(span, ~[ - cx.ident_of(~"std"), - cx.ident_of(~"serialization"), - cx.ident_of(~"deserialize"), - ]), - ~[cx.expr_var(span, ~"__d")] - ) - ); - - // ast for `__d.read_enum_variant_arg($(a_idx), $(expr_lambda))` - cx.expr_call( - span, - cx.expr_field( - span, - cx.expr_var(span, ~"__d"), - cx.ident_of(~"read_enum_variant_arg") - ), - ~[cx.lit_uint(span, idx), expr_lambda] - ) - }; - - // ast for `$(name)($(args))` - cx.expr_call(span, cx.expr_path(span, ~[name]), args) -} - -fn mk_enum_deser_body( - cx: ext_ctxt, - span: span, - name: ast::ident, - variants: ~[ast::variant] -) -> @ast::expr { - let mut arms = do variants.mapi |v_idx, variant| { - let body = match variant.node.kind { - ast::tuple_variant_kind(args) => { - if args.is_empty() { - // for a nullary variant v, do "v" - cx.expr_path(span, ~[variant.node.name]) - } else { - // for an n-ary variant v, do "v(a_1, ..., a_n)" - mk_enum_deser_variant_nary( - cx, - span, - variant.node.name, - args - ) - } - }, - ast::struct_variant_kind(*) => - fail ~"struct variants unimplemented", - ast::enum_variant_kind(*) => - fail ~"enum variants unimplemented", - }; - - let pat = @{ - id: cx.next_id(), - node: ast::pat_lit(cx.lit_uint(span, v_idx)), - span: span, - }; - - { - pats: ~[pat], - guard: None, - body: cx.expr_blk(body), - } - }; - - let impossible_case = { - pats: ~[@{ id: cx.next_id(), node: ast::pat_wild, span: span}], - guard: None, - - // FIXME(#3198): proper error message - body: cx.expr_blk(cx.expr(span, ast::expr_fail(None))), - }; - - arms.push(impossible_case); - - // ast for `|i| { match i { $(arms) } }` - let expr_lambda = cx.expr( - span, - ast::expr_fn_block( - { - inputs: ~[{ - mode: ast::infer(cx.next_id()), - ty: @{ - id: cx.next_id(), - node: ast::ty_infer, - span: span - }, - pat: @{id: cx.next_id(), - node: ast::pat_ident( - ast::bind_by_value, - ast_util::ident_to_path(span, - cx.ident_of(~"i")), - None), - span: span}, - id: cx.next_id(), - }], - output: @{ - id: cx.next_id(), - node: ast::ty_infer, - span: span, - }, - cf: ast::return_val, - }, - cx.expr_blk( - cx.expr( - span, - ast::expr_match(cx.expr_var(span, ~"i"), arms) - ) - ), - @~[] - ) - ); - - // ast for `__d.read_enum_variant($(expr_lambda))` - let expr_lambda = cx.lambda_expr( - cx.expr_call( - span, - cx.expr_field( - span, - cx.expr_var(span, ~"__d"), - cx.ident_of(~"read_enum_variant") - ), - ~[expr_lambda] - ) - ); - - // ast for `__d.read_enum($(e_name), $(expr_lambda))` - cx.expr_call( - span, - cx.expr_field( - span, - cx.expr_var(span, ~"__d"), - cx.ident_of(~"read_enum") - ), - ~[ - cx.lit_str(span, @cx.str_of(name)), - expr_lambda - ] - ) -} diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index d245aa1c050c4..cf994e0ea5224 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -73,12 +73,6 @@ fn syntax_expander_table() -> HashMap<~str, syntax_extension> { ext::tt::macro_rules::add_new_extension)); syntax_expanders.insert(~"fmt", builtin_normal_tt(ext::fmt::expand_syntax_ext)); - syntax_expanders.insert( - ~"auto_serialize", - item_decorator(ext::auto_serialize::expand_auto_serialize)); - syntax_expanders.insert( - ~"auto_deserialize", - item_decorator(ext::auto_serialize::expand_auto_deserialize)); syntax_expanders.insert( ~"auto_encode", item_decorator(ext::auto_encode::expand_auto_encode)); diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rc index 12d93b4b5c931..522e46422d62c 100644 --- a/src/libsyntax/syntax.rc +++ b/src/libsyntax/syntax.rc @@ -105,8 +105,6 @@ mod ext { #[legacy_exports] mod auto_encode; #[legacy_exports] - mod auto_serialize; - #[legacy_exports] mod source_util; #[legacy_exports] From c14105bb8a9a36428a67ac508464b54259675f69 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Wed, 19 Dec 2012 16:08:48 -0800 Subject: [PATCH 14/22] Remove serialize::traits submodule. --- src/librustc/metadata/decoder.rs | 4 + src/librustc/middle/astencode.rs | 4 + src/libstd/ebml.rs | 2 +- src/libstd/serialize.rs | 603 +++++++++++++++++++++++++++++++ src/libsyntax/ext/auto_encode.rs | 2 - src/test/run-pass/auto-encode.rs | 2 +- 6 files changed, 613 insertions(+), 4 deletions(-) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index b907d8ea2146a..08023f5371d57 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -25,7 +25,11 @@ use reader = std::ebml::reader; use std::ebml; use std::map::HashMap; use std::map; +#[cfg(stage0)] use std::serialize::traits::Decodable; +#[cfg(stage1)] +#[cfg(stage2)] +use std::serialize::Decodable; use syntax::ast_map; use syntax::attr; use syntax::diagnostic::span_handler; diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index e2f80aeeb6ac9..9e23276c8a437 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -29,7 +29,11 @@ use std::ebml; use std::map::HashMap; use std::serialize; use std::serialize::{Encodable, EncoderHelpers, DecoderHelpers}; +#[cfg(stage0)] use std::serialize::traits::Decodable; +#[cfg(stage1)] +#[cfg(stage2)] +use std::serialize::Decodable; use syntax::ast; use syntax::ast_map; use syntax::ast_util; diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs index e72eaa08c3e3e..59e0a1e84fe8f 100644 --- a/src/libstd/ebml.rs +++ b/src/libstd/ebml.rs @@ -657,7 +657,7 @@ mod tests { }; let ebml_doc = reader::Doc(@bytes); let deser = reader::Decoder(ebml_doc); - let v1 = serialize::traits::Decodable::decode(&deser); + let v1 = serialize::Decodable::decode(&deser); debug!("v1 == %?", v1); assert v == v1; } diff --git a/src/libstd/serialize.rs b/src/libstd/serialize.rs index e32dda045794c..79ceab6241f31 100644 --- a/src/libstd/serialize.rs +++ b/src/libstd/serialize.rs @@ -102,6 +102,7 @@ pub trait Decoder { fn read_tup_elt(&self, idx: uint, f: fn() -> T) -> T; } +#[cfg(stage0)] pub mod traits { pub trait Encodable { fn encode(&self, s: &S); @@ -583,4 +584,606 @@ pub impl D: DecoderHelpers { } } +#[cfg(stage0)] pub use serialize::traits::*; + +#[cfg(stage1)] +#[cfg(stage2)] +pub trait Encodable { + fn encode(&self, s: &S); +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub trait Decodable { + static fn decode(&self, d: &D) -> self; +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl uint: Encodable { + fn encode(&self, s: &S) { s.emit_uint(*self) } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl uint: Decodable { + static fn decode(&self, d: &D) -> uint { + d.read_uint() + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl u8: Encodable { + fn encode(&self, s: &S) { s.emit_u8(*self) } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl u8: Decodable { + static fn decode(&self, d: &D) -> u8 { + d.read_u8() + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl u16: Encodable { + fn encode(&self, s: &S) { s.emit_u16(*self) } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl u16: Decodable { + static fn decode(&self, d: &D) -> u16 { + d.read_u16() + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl u32: Encodable { + fn encode(&self, s: &S) { s.emit_u32(*self) } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl u32: Decodable { + static fn decode(&self, d: &D) -> u32 { + d.read_u32() + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl u64: Encodable { + fn encode(&self, s: &S) { s.emit_u64(*self) } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl u64: Decodable { + static fn decode(&self, d: &D) -> u64 { + d.read_u64() + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl int: Encodable { + fn encode(&self, s: &S) { s.emit_int(*self) } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl int: Decodable { + static fn decode(&self, d: &D) -> int { + d.read_int() + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl i8: Encodable { + fn encode(&self, s: &S) { s.emit_i8(*self) } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl i8: Decodable { + static fn decode(&self, d: &D) -> i8 { + d.read_i8() + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl i16: Encodable { + fn encode(&self, s: &S) { s.emit_i16(*self) } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl i16: Decodable { + static fn decode(&self, d: &D) -> i16 { + d.read_i16() + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl i32: Encodable { + fn encode(&self, s: &S) { s.emit_i32(*self) } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl i32: Decodable { + static fn decode(&self, d: &D) -> i32 { + d.read_i32() + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl i64: Encodable { + fn encode(&self, s: &S) { s.emit_i64(*self) } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl i64: Decodable { + static fn decode(&self, d: &D) -> i64 { + d.read_i64() + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl &str: Encodable { + fn encode(&self, s: &S) { s.emit_borrowed_str(*self) } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl ~str: Encodable { + fn encode(&self, s: &S) { s.emit_owned_str(*self) } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl ~str: Decodable { + static fn decode(&self, d: &D) -> ~str { + d.read_owned_str() + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl @str: Encodable { + fn encode(&self, s: &S) { s.emit_managed_str(*self) } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl @str: Decodable { + static fn decode(&self, d: &D) -> @str { + d.read_managed_str() + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl float: Encodable { + fn encode(&self, s: &S) { s.emit_float(*self) } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl float: Decodable { + static fn decode(&self, d: &D) -> float { + d.read_float() + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl f32: Encodable { + fn encode(&self, s: &S) { s.emit_f32(*self) } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl f32: Decodable { + static fn decode(&self, d: &D) -> f32 { + d.read_f32() } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl f64: Encodable { + fn encode(&self, s: &S) { s.emit_f64(*self) } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl f64: Decodable { + static fn decode(&self, d: &D) -> f64 { + d.read_f64() + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl bool: Encodable { + fn encode(&self, s: &S) { s.emit_bool(*self) } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl bool: Decodable { + static fn decode(&self, d: &D) -> bool { + d.read_bool() + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl (): Encodable { + fn encode(&self, s: &S) { s.emit_nil() } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl (): Decodable { + static fn decode(&self, d: &D) -> () { + d.read_nil() + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl> &T: Encodable { + fn encode(&self, s: &S) { + s.emit_borrowed(|| (**self).encode(s)) + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl> ~T: Encodable { + fn encode(&self, s: &S) { + s.emit_owned(|| (**self).encode(s)) + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl> ~T: Decodable { + static fn decode(&self, d: &D) -> ~T { + d.read_owned(|| ~Decodable::decode(d)) + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl> @T: Encodable { + fn encode(&self, s: &S) { + s.emit_managed(|| (**self).encode(s)) + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl> @T: Decodable { + static fn decode(&self, d: &D) -> @T { + d.read_managed(|| @Decodable::decode(d)) + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl> &[T]: Encodable { + fn encode(&self, s: &S) { + do s.emit_borrowed_vec(self.len()) { + for self.eachi |i, e| { + s.emit_vec_elt(i, || e.encode(s)) + } + } + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl> ~[T]: Encodable { + fn encode(&self, s: &S) { + do s.emit_owned_vec(self.len()) { + for self.eachi |i, e| { + s.emit_vec_elt(i, || e.encode(s)) + } + } + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl> ~[T]: Decodable { + static fn decode(&self, d: &D) -> ~[T] { + do d.read_owned_vec |len| { + do vec::from_fn(len) |i| { + d.read_vec_elt(i, || Decodable::decode(d)) + } + } + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl> @[T]: Encodable { + fn encode(&self, s: &S) { + do s.emit_managed_vec(self.len()) { + for self.eachi |i, e| { + s.emit_vec_elt(i, || e.encode(s)) + } + } + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl> @[T]: Decodable { + static fn decode(&self, d: &D) -> @[T] { + do d.read_managed_vec |len| { + do at_vec::from_fn(len) |i| { + d.read_vec_elt(i, || Decodable::decode(d)) + } + } + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl> Option: Encodable { + fn encode(&self, s: &S) { + do s.emit_enum(~"option") { + match *self { + None => do s.emit_enum_variant(~"none", 0u, 0u) { + }, + + Some(ref v) => do s.emit_enum_variant(~"some", 1u, 1u) { + s.emit_enum_variant_arg(0u, || v.encode(s)) + } + } + } + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl> Option: Decodable { + static fn decode(&self, d: &D) -> Option { + do d.read_enum(~"option") { + do d.read_enum_variant |i| { + match i { + 0 => None, + 1 => Some(d.read_enum_variant_arg( + 0u, || Decodable::decode(d))), + _ => fail(fmt!("Bad variant for option: %u", i)) + } + } + } + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl< + S: Encoder, + T0: Encodable, + T1: Encodable +> (T0, T1): Encodable { + fn encode(&self, s: &S) { + match *self { + (ref t0, ref t1) => { + do s.emit_tup(2) { + s.emit_tup_elt(0, || t0.encode(s)); + s.emit_tup_elt(1, || t1.encode(s)); + } + } + } + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl< + D: Decoder, + T0: Decodable, + T1: Decodable +> (T0, T1): Decodable { + static fn decode(&self, d: &D) -> (T0, T1) { + do d.read_tup(2) { + ( + d.read_tup_elt(0, || Decodable::decode(d)), + d.read_tup_elt(1, || Decodable::decode(d)) + ) + } + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl< + S: Encoder, + T0: Encodable, + T1: Encodable, + T2: Encodable +> (T0, T1, T2): Encodable { + fn encode(&self, s: &S) { + match *self { + (ref t0, ref t1, ref t2) => { + do s.emit_tup(3) { + s.emit_tup_elt(0, || t0.encode(s)); + s.emit_tup_elt(1, || t1.encode(s)); + s.emit_tup_elt(2, || t2.encode(s)); + } + } + } + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl< + D: Decoder, + T0: Decodable, + T1: Decodable, + T2: Decodable +> (T0, T1, T2): Decodable { + static fn decode(&self, d: &D) -> (T0, T1, T2) { + do d.read_tup(3) { + ( + d.read_tup_elt(0, || Decodable::decode(d)), + d.read_tup_elt(1, || Decodable::decode(d)), + d.read_tup_elt(2, || Decodable::decode(d)) + ) + } + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl< + S: Encoder, + T0: Encodable, + T1: Encodable, + T2: Encodable, + T3: Encodable +> (T0, T1, T2, T3): Encodable { + fn encode(&self, s: &S) { + match *self { + (ref t0, ref t1, ref t2, ref t3) => { + do s.emit_tup(4) { + s.emit_tup_elt(0, || t0.encode(s)); + s.emit_tup_elt(1, || t1.encode(s)); + s.emit_tup_elt(2, || t2.encode(s)); + s.emit_tup_elt(3, || t3.encode(s)); + } + } + } + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl< + D: Decoder, + T0: Decodable, + T1: Decodable, + T2: Decodable, + T3: Decodable +> (T0, T1, T2, T3): Decodable { + static fn decode(&self, d: &D) -> (T0, T1, T2, T3) { + do d.read_tup(4) { + ( + d.read_tup_elt(0, || Decodable::decode(d)), + d.read_tup_elt(1, || Decodable::decode(d)), + d.read_tup_elt(2, || Decodable::decode(d)), + d.read_tup_elt(3, || Decodable::decode(d)) + ) + } + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl< + S: Encoder, + T0: Encodable, + T1: Encodable, + T2: Encodable, + T3: Encodable, + T4: Encodable +> (T0, T1, T2, T3, T4): Encodable { + fn encode(&self, s: &S) { + match *self { + (ref t0, ref t1, ref t2, ref t3, ref t4) => { + do s.emit_tup(5) { + s.emit_tup_elt(0, || t0.encode(s)); + s.emit_tup_elt(1, || t1.encode(s)); + s.emit_tup_elt(2, || t2.encode(s)); + s.emit_tup_elt(3, || t3.encode(s)); + s.emit_tup_elt(4, || t4.encode(s)); + } + } + } + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl< + D: Decoder, + T0: Decodable, + T1: Decodable, + T2: Decodable, + T3: Decodable, + T4: Decodable +> (T0, T1, T2, T3, T4): Decodable { + static fn decode(&self, d: &D) + -> (T0, T1, T2, T3, T4) { + do d.read_tup(5) { + ( + d.read_tup_elt(0, || Decodable::decode(d)), + d.read_tup_elt(1, || Decodable::decode(d)), + d.read_tup_elt(2, || Decodable::decode(d)), + d.read_tup_elt(3, || Decodable::decode(d)), + d.read_tup_elt(4, || Decodable::decode(d)) + ) + } + } +} + +// ___________________________________________________________________________ +// Helper routines +// +// In some cases, these should eventually be coded as traits. + +#[cfg(stage1)] +#[cfg(stage2)] +pub trait EncoderHelpers { + fn emit_from_vec(&self, v: ~[T], f: fn(v: &T)); +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl S: EncoderHelpers { + fn emit_from_vec(&self, v: ~[T], f: fn(v: &T)) { + do self.emit_owned_vec(v.len()) { + for v.eachi |i, e| { + do self.emit_vec_elt(i) { + f(e) + } + } + } + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub trait DecoderHelpers { + fn read_to_vec(&self, f: fn() -> T) -> ~[T]; +} + +#[cfg(stage1)] +#[cfg(stage2)] +pub impl D: DecoderHelpers { + fn read_to_vec(&self, f: fn() -> T) -> ~[T] { + do self.read_owned_vec |len| { + do vec::from_fn(len) |i| { + self.read_vec_elt(i, || f()) + } + } + } +} diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs index 6995155af18cd..8eb37386364f4 100644 --- a/src/libsyntax/ext/auto_encode.rs +++ b/src/libsyntax/ext/auto_encode.rs @@ -818,7 +818,6 @@ fn mk_deser_fields( cx.expr_path(span, ~[ cx.ident_of(~"std"), cx.ident_of(~"serialize"), - cx.ident_of(~"traits"), cx.ident_of(~"Decodable"), cx.ident_of(~"decode"), ]), @@ -1023,7 +1022,6 @@ fn mk_enum_deser_variant_nary( cx.expr_path(span, ~[ cx.ident_of(~"std"), cx.ident_of(~"serialize"), - cx.ident_of(~"traits"), cx.ident_of(~"Decodable"), cx.ident_of(~"decode"), ]), diff --git a/src/test/run-pass/auto-encode.rs b/src/test/run-pass/auto-encode.rs index c5bba615e2857..555171f9d5f30 100644 --- a/src/test/run-pass/auto-encode.rs +++ b/src/test/run-pass/auto-encode.rs @@ -22,7 +22,7 @@ use std::ebml; use EBReader = std::ebml::reader; use EBWriter = std::ebml::writer; use io::Writer; -use std::serialize::traits::{Encodable, Decodable}; +use std::serialize::{Encodable, Decodable}; use std::prettyprint; use std::time; From b865b4b70df27a1e19e7a0cdfedf51d0096da25b Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Wed, 19 Dec 2012 17:28:44 -0800 Subject: [PATCH 15/22] Fix a warning in the workcache test. --- src/libstd/workcache.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/workcache.rs b/src/libstd/workcache.rs index 9b7bbb1660f6a..4d49e98a8b7ec 100644 --- a/src/libstd/workcache.rs +++ b/src/libstd/workcache.rs @@ -335,7 +335,7 @@ fn test() { let pth = Path("foo.c"); { let file = io::file_writer(&pth, [io::Create]).get(); - file.write_str("void main() { }"); + file.write_str("int main() { return 0; }"); } prep.declare_input("file", pth.to_str(), digest_file(&pth)); From 2d313fe5011acfa28b8771c5975be37e1c84fd73 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Wed, 19 Dec 2012 20:38:28 -0700 Subject: [PATCH 16/22] Update docs to mention trait constraints; also fix failing doc tests /cc #4217 --- doc/rust.md | 21 ++++++++++++++++++--- doc/tutorial.md | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/doc/rust.md b/doc/rust.md index c73211acef937..8bff1aa37afc1 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -1195,8 +1195,19 @@ Values with a trait type can have [methods called](#method-call-expressions) on for any method in the trait, and can be used to instantiate type parameters that are bounded by the trait. -Trait methods may be static. Currently implementations of static methods behave like -functions declared in the implentation's module. +Trait methods may be static. +Currently, implementations of static methods behave like functions declared in the implementation's module. + +Traits can have _constraints_ for example, in + +~~~~ +trait Shape { fn area() -> float; } +trait Circle : Shape { fn radius() -> float; } +~~~~ + +the syntax `Circle : Shape` means that types that implement `Circle` must also have an implementation for `Shape`. +In an implementation of `Circle` for a given type `T`, methods can refer to `Shape` methods, +since the typechecker checks that any type with an implementation of `Circle` also has an implementation of `Shape`. ### Implementations @@ -1520,8 +1531,11 @@ To indicate that a field is mutable, the `mut` keyword is written before its nam The following are examples of structure expressions: ~~~~ +# struct Point { x: float, y: float } +# mod game { pub struct User { name: &str, age: uint, mut score: uint } } +# use game; Point {x: 10f, y: 20f}; -game::User {name: "Joe", age: 35u, mut score: 100_000}; +let u = game::User {name: "Joe", age: 35u, mut score: 100_000}; ~~~~ A structure expression forms a new value of the named structure type. @@ -1532,6 +1546,7 @@ A new structure will be created, of the same type as the base expression, with t and the values in the base record for all other fields. ~~~~ +# struct Point3d { x: int, y: int, z: int } let base = Point3d {x: 1, y: 2, z: 3}; Point3d {y: 0, z: 10, .. base}; ~~~~ diff --git a/doc/tutorial.md b/doc/tutorial.md index b7eab9b792163..c7b75993f11e3 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -2076,6 +2076,39 @@ the preferred way to use traits polymorphically. This usage of traits is similar to Haskell type classes. +## Trait constraints + +We can write a trait declaration that is _constrained_ to only be implementable on types that +also implement some other trait. + +For example, we can define a `Circle` trait that only types that also have the `Shape` trait can have: + +~~~~ +trait Shape { fn area() -> float; } +trait Circle : Shape { fn radius() -> float; } +~~~~ + +Now, implementations of `Circle` methods can call `Shape` methods: + +~~~~ +# trait Shape { fn area() -> float; } +# trait Circle : Shape { fn radius() -> float; } +# struct Point { x: float, y: float } +# use float::consts::pi; +# use float::sqrt; +# fn square(x: float) -> float { x * x } +struct CircleStruct { center: Point, radius: float } +impl CircleStruct: Circle { + fn radius() -> float { sqrt(self.area() / pi) } +} +impl CircleStruct: Shape { + fn area() -> float { pi * square(self.radius) } +} +~~~~ + +This is a silly way to compute the radius of a circle +(since we could just return the `circle` field), but you get the idea. + ## Trait objects and dynamic method dispatch The above allows us to define functions that polymorphically act on From b99a2542f38a2d08b863d2e2ab73bfd64647e520 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Wed, 19 Dec 2012 21:32:19 -0700 Subject: [PATCH 17/22] docs: mention static methods /cc #4217 --- doc/rust.md | 19 +++++++++++++++++-- doc/tutorial.md | 26 ++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/doc/rust.md b/doc/rust.md index 8bff1aa37afc1..f1064c395aaa2 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -1195,8 +1195,23 @@ Values with a trait type can have [methods called](#method-call-expressions) on for any method in the trait, and can be used to instantiate type parameters that are bounded by the trait. -Trait methods may be static. -Currently, implementations of static methods behave like functions declared in the implementation's module. +Trait methods may be static, +which means that they lack a `self` argument. +This means that they can only be called with function call syntax (`f(x)`) +and not method call syntax (`obj.f()`). +The way to refer to the name of a static method is to qualify it with the trait name, +treating the trait name like a module. +For example: + +~~~~ +trait Num { + static pure fn from_int(n: int) -> self; +} +impl float: Num { + static pure fn from_int(n: int) -> float { n as float } +} +let x: float = Num::from_int(42); +~~~~ Traits can have _constraints_ for example, in diff --git a/doc/tutorial.md b/doc/tutorial.md index c7b75993f11e3..8c57f2883ad51 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -2076,6 +2076,32 @@ the preferred way to use traits polymorphically. This usage of traits is similar to Haskell type classes. +## Static methods + +Traits can define _static_ methods, which don't have an implicit `self` argument. +The `static` keyword distinguishes static methods from methods that have a `self`: + +~~~~ +trait Shape { + fn area() -> float; + static fn new_shape(area: float) -> Shape; +} +~~~~ + +Constructors are one application for static methods, as in `new_shape` above. +To call a static method, you have to prefix it with the trait name and a double colon: + +~~~~ +# trait Shape { static fn new_shape(area: float) -> self; } +# use float::consts::pi; +# use float::sqrt; +struct Circle { radius: float } +impl Circle: Shape { + static fn new_shape(area: float) -> Circle { Circle { radius: sqrt(area / pi) } } +} +let s: Circle = Shape::new_shape(42.5); +~~~~ + ## Trait constraints We can write a trait declaration that is _constrained_ to only be implementable on types that From 8554d5e7104be30d20ce8e8dc08239ce20b171c2 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Wed, 19 Dec 2012 21:52:03 -0700 Subject: [PATCH 18/22] doc: Mention tuple structs /cc: #4217 --- doc/rust.md | 22 +++++++++++++++++++++- doc/tutorial.md | 16 ++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/doc/rust.md b/doc/rust.md index f1064c395aaa2..b16c56be63361 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -1072,6 +1072,15 @@ let p = Point {x: 10, y: 11}; let px: int = p.x; ~~~~ +A _tuple structure_ is a nominal [tuple type](#tuple-types), also defined with the keyword `struct`. +For example: + +~~~~ +struct Point(int, int); +let p = Point(10, 11); +let px: int = match p { Point(x, _) => x }; +~~~~ + ### Enumerations An _enumeration_ is a simultaneous definition of a nominal [enumerated type](#enumerated-types) as well as a set of *constructors*, @@ -1534,22 +1543,32 @@ values. ~~~~~~~~{.ebnf .gram} struct_expr : expr_path '{' ident ':' expr [ ',' ident ':' expr ] * - [ ".." expr ] '}' + [ ".." expr ] '}' | + expr_path '(' expr + [ ',' expr ] * ')' ~~~~~~~~ +There are several forms of structure expressions. A _structure expression_ consists of the [path](#paths) of a [structure item](#structures), followed by a brace-enclosed list of one or more comma-separated name-value pairs, providing the field values of a new instance of the structure. A field name can be any identifier, and is separated from its value expression by a colon. To indicate that a field is mutable, the `mut` keyword is written before its name. +A _tuple structure expression_ constists of the [path](#paths) of a [structure item](#structures), +followed by a parenthesized list of one or more comma-separated expressions +(in other words, the path of a structured item followed by a tuple expression). +The structure item must be a tuple structure item. + The following are examples of structure expressions: ~~~~ # struct Point { x: float, y: float } +# struct TuplePoint(float, float); # mod game { pub struct User { name: &str, age: uint, mut score: uint } } # use game; Point {x: 10f, y: 20f}; +TuplePoint(10f, 20f); let u = game::User {name: "Joe", age: 35u, mut score: 100_000}; ~~~~ @@ -2597,6 +2616,7 @@ the resulting `struct` value will always be laid out in memory in the order spec The fields of a `struct` may be qualified by [visibility modifiers](#visibility-modifiers), to restrict access to implementation-private data in a structure. +A `tuple struct` type is just like a structure type, except that the fields are anonymous. ### Enumerated types diff --git a/doc/tutorial.md b/doc/tutorial.md index 8c57f2883ad51..6ea0aa67e4e1e 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -902,6 +902,22 @@ match mytup { } ~~~~ +## Tuple structs + +Rust also has _nominal tuples_, which behave like both structs and tuples, +except that nominal tuple types have names +(so `Foo(1, 2)` has a different type from `Bar(1, 2)`), +and nominal tuple types' _fields_ do not have names. + +For example: +~~~~ +struct MyTup(int, int, float); +let mytup: MyTup = MyTup(10, 20, 30.0); +match mytup { + MyTup(a, b, c) => log(info, a + b + (c as int)) +} +~~~~ + # Functions and methods We've already seen several function definitions. Like all other static From d3034e5a2b10d398f2ad576cec538a3fc62742d3 Mon Sep 17 00:00:00 2001 From: ILyoan Date: Thu, 20 Dec 2012 18:26:27 +0900 Subject: [PATCH 19/22] arrange core::os::consts --- src/libcore/os.rs | 68 +++++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/src/libcore/os.rs b/src/libcore/os.rs index b5e0983a420d1..4a2b12bf6a75c 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -355,13 +355,7 @@ fn dup2(src: c_int, dst: c_int) -> c_int { pub fn dll_filename(base: &str) -> ~str { - return pre() + str::from_slice(base) + dll_suffix(); - - #[cfg(unix)] - fn pre() -> ~str { ~"lib" } - - #[cfg(windows)] - fn pre() -> ~str { ~"" } + return dll_prefix() + str::from_slice(base) + dll_suffix(); } @@ -856,33 +850,49 @@ pub fn family() -> ~str { ~"unix" } #[cfg(windows)] pub fn family() -> ~str { ~"windows" } + -#[cfg(target_os = "macos")] mod consts { - pub fn sysname() -> ~str { ~"macos" } - pub fn exe_suffix() -> ~str { ~"" } - pub fn dll_suffix() -> ~str { ~".dylib" } -} -#[cfg(target_os = "freebsd")] -mod consts { - pub fn sysname() -> ~str { ~"freebsd" } - pub fn exe_suffix() -> ~str { ~"" } - pub fn dll_suffix() -> ~str { ~".so" } -} + #[cfg(target_os = "macos")] + use os::consts::macos::*; -#[cfg(target_os = "linux")] -mod consts { - pub fn sysname() -> ~str { ~"linux" } - pub fn exe_suffix() -> ~str { ~"" } - pub fn dll_suffix() -> ~str { ~".so" } -} + #[cfg(target_os = "freebsd")] + use os::consts::freebsd::*; -#[cfg(target_os = "win32")] -mod consts { - pub fn sysname() -> ~str { ~"win32" } - pub fn exe_suffix() -> ~str { ~".exe" } - pub fn dll_suffix() -> ~str { ~".dll" } + #[cfg(target_os = "linux")] + use os::consts::linux::*; + + #[cfg(target_os = "win32")] + use os::consts::win32::*; + + pub mod macos { + pub fn sysname() -> ~str { ~"macos" } + pub fn dll_prefix() -> ~str { ~"lib" } + pub fn dll_suffix() -> ~str { ~".dylib" } + pub fn exe_suffix() -> ~str { ~"" } + } + + pub mod freebsd { + pub fn sysname() -> ~str { ~"freebsd" } + pub fn dll_prefix() -> ~str { ~"lib" } + pub fn dll_suffix() -> ~str { ~".so" } + pub fn exe_suffix() -> ~str { ~"" } + } + + pub mod linux { + pub fn sysname() -> ~str { ~"linux" } + pub fn dll_prefix() -> ~str { ~"lib" } + pub fn dll_suffix() -> ~str { ~".so" } + pub fn exe_suffix() -> ~str { ~"" } + } + + pub mod win32 { + pub fn sysname() -> ~str { ~"win32" } + pub fn dll_prefix() -> ~str { ~"" } + pub fn dll_suffix() -> ~str { ~".dll" } + pub fn exe_suffix() -> ~str { ~".exe" } + } } #[cfg(target_arch = "x86")] From 0a7b730bbe1b0b4853743b46404ffc0145f8ccbf Mon Sep 17 00:00:00 2001 From: ILyoan Date: Thu, 20 Dec 2012 19:15:06 +0900 Subject: [PATCH 20/22] use core::os::consts instead of hard coded contant value --- src/librustc/metadata/loader.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 5901e58aeb190..4bab50a6da470 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -18,6 +18,7 @@ use lib::llvm::{False, llvm, mk_object_file, mk_section_iter}; use metadata::filesearch::FileSearch; use io::WriterUtil; use syntax::parse::token::ident_interner; +use core::os::consts::{macos, freebsd, linux, win32}; export os; export os_macos, os_win32, os_linux, os_freebsd; @@ -67,10 +68,14 @@ fn find_library_crate(cx: ctxt) -> Option<{ident: ~str, data: @~[u8]}> { fn libname(cx: ctxt) -> {prefix: ~str, suffix: ~str} { if cx.static { return {prefix: ~"lib", suffix: ~".rlib"}; } match cx.os { - os_win32 => return {prefix: ~"", suffix: ~".dll"}, - os_macos => return {prefix: ~"lib", suffix: ~".dylib"}, - os_linux => return {prefix: ~"lib", suffix: ~".so"}, - os_freebsd => return {prefix: ~"lib", suffix: ~".so"} + os_win32 => return {prefix: win32::dll_prefix(), + suffix: win32::dll_suffix()}, + os_macos => return {prefix: macos::dll_prefix(), + suffix: macos::dll_suffix()}, + os_linux => return {prefix: linux::dll_prefix(), + suffix: linux::dll_suffix()}, + os_freebsd => return {prefix: freebsd::dll_prefix(), + suffix: freebsd::dll_suffix()} } } From df6345aee420fc2757ed67717662b01e2473b383 Mon Sep 17 00:00:00 2001 From: ILyoan Date: Thu, 20 Dec 2012 19:15:59 +0900 Subject: [PATCH 21/22] generate output dll name based on target os --- src/librustc/back/link.rs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 52b94b76fe614..1073821e58a6a 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -26,6 +26,7 @@ use lib::llvm::{ModuleRef, mk_pass_manager, mk_target_data, True, False, use metadata::filesearch; use syntax::ast_map::{path, path_mod, path_name}; use io::{Writer, WriterUtil}; +use os::consts::{macos, freebsd, linux, win32}; enum output_type { output_type_none, @@ -631,6 +632,21 @@ fn mangle_internal_name_by_seq(ccx: @crate_ctxt, flav: ~str) -> ~str { return fmt!("%s_%u", flav, (ccx.names)(flav).repr); } + +fn output_dll_filename(os: session::os, lm: &link_meta) -> ~str { + let libname = fmt!("%s-%s-%s", lm.name, lm.extras_hash, lm.vers); + match os { + session::os_macos => + macos::dll_prefix() + libname + macos::dll_suffix(), + session::os_freebsd => + freebsd::dll_prefix() + libname + macos::dll_suffix(), + session::os_linux => + freebsd::dll_prefix() + libname + macos::dll_suffix(), + session::os_win32 => + win32::dll_prefix() + libname + win32::dll_suffix(), + } +} + // If the user wants an exe generated we need to invoke // cc to link the object file with some libs fn link_binary(sess: Session, @@ -648,10 +664,9 @@ fn link_binary(sess: Session, } let output = if sess.building_library { - let long_libname = - os::dll_filename(fmt!("%s-%s-%s", - lm.name, lm.extras_hash, lm.vers)); - debug!("link_meta.name: %s", lm.name); + let long_libname = output_dll_filename(sess.targ_cfg.os, &lm); + + debug!("link_meta.name: %s", lm.name); debug!("long_libname: %s", long_libname); debug!("out_filename: %s", out_filename.to_str()); debug!("dirname(out_filename): %s", out_filename.dir_path().to_str()); From 658420aa43bf2898e4cf11d6a4ce076a5fc44877 Mon Sep 17 00:00:00 2001 From: ILyoan Date: Thu, 20 Dec 2012 19:19:41 +0900 Subject: [PATCH 22/22] formatting --- src/libcore/os.rs | 4 ++-- src/librustc/back/link.rs | 9 ++++----- src/librustc/metadata/loader.rs | 6 +++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/libcore/os.rs b/src/libcore/os.rs index 4a2b12bf6a75c..b7f0327ec5da9 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -850,7 +850,7 @@ pub fn family() -> ~str { ~"unix" } #[cfg(windows)] pub fn family() -> ~str { ~"windows" } - + mod consts { @@ -886,7 +886,7 @@ mod consts { pub fn dll_suffix() -> ~str { ~".so" } pub fn exe_suffix() -> ~str { ~"" } } - + pub mod win32 { pub fn sysname() -> ~str { ~"win32" } pub fn dll_prefix() -> ~str { ~"" } diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 1073821e58a6a..60c43e7f526b4 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -639,10 +639,10 @@ fn output_dll_filename(os: session::os, lm: &link_meta) -> ~str { session::os_macos => macos::dll_prefix() + libname + macos::dll_suffix(), session::os_freebsd => - freebsd::dll_prefix() + libname + macos::dll_suffix(), + freebsd::dll_prefix() + libname + freebsd::dll_suffix(), session::os_linux => - freebsd::dll_prefix() + libname + macos::dll_suffix(), - session::os_win32 => + linux::dll_prefix() + libname + linux::dll_suffix(), + session::os_win32 => win32::dll_prefix() + libname + win32::dll_suffix(), } } @@ -665,8 +665,7 @@ fn link_binary(sess: Session, let output = if sess.building_library { let long_libname = output_dll_filename(sess.targ_cfg.os, &lm); - - debug!("link_meta.name: %s", lm.name); + debug!("link_meta.name: %s", lm.name); debug!("long_libname: %s", long_libname); debug!("out_filename: %s", out_filename.to_str()); debug!("dirname(out_filename): %s", out_filename.dir_path().to_str()); diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 4bab50a6da470..5d2af4a37fe7b 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -68,13 +68,13 @@ fn find_library_crate(cx: ctxt) -> Option<{ident: ~str, data: @~[u8]}> { fn libname(cx: ctxt) -> {prefix: ~str, suffix: ~str} { if cx.static { return {prefix: ~"lib", suffix: ~".rlib"}; } match cx.os { - os_win32 => return {prefix: win32::dll_prefix(), + os_win32 => return {prefix: win32::dll_prefix(), suffix: win32::dll_suffix()}, os_macos => return {prefix: macos::dll_prefix(), suffix: macos::dll_suffix()}, - os_linux => return {prefix: linux::dll_prefix(), + os_linux => return {prefix: linux::dll_prefix(), suffix: linux::dll_suffix()}, - os_freebsd => return {prefix: freebsd::dll_prefix(), + os_freebsd => return {prefix: freebsd::dll_prefix(), suffix: freebsd::dll_suffix()} } }