$$(Q)cp $$(TLIB$(2)_T_$(1)_H_$(3))/$(EXTRALIB_GLOB_$(1)) $$@
$$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(EXTRALIB_GLOB_$(4)),$$(notdir $$@))
-$$(HLIB0_H_$(1))/$(CFG_LIBRUSTUV_$(1)):
- touch $$@
-# NOTE: this should get uncommented after a snapshot and the rule above this can
-# get deleted, right now we're not expecting a librustuv in a snapshot.
-# $$(HLIB0_H_$(1))/$(CFG_LIBRUSTUV_$(1)): \
-# $$(TLIB$(2)_T_$(1)_H_$(3))/$(CFG_LIBRUSTUV_$(1)) \
-# | $(HLIB0_H_$(1))/
-# @$$(call E, cp: $$@)
-# $$(call CHECK_FOR_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@))
-# $$(Q)cp $$(TLIB$(2)_T_$(1)_H_$(3))/$(LIBRUSTUV_GLOB_$(1)) $$@
-# $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@))
+$$(HLIB0_H_$(1))/$(CFG_LIBRUSTUV_$(1)): \
+ $$(TLIB$(2)_T_$(1)_H_$(3))/$(CFG_LIBRUSTUV_$(1)) \
+ | $(HLIB0_H_$(1))/
+ @$$(call E, cp: $$@)
+ $$(call CHECK_FOR_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@))
+ $$(Q)cp $$(TLIB$(2)_T_$(1)_H_$(3))/$(LIBRUSTUV_GLOB_$(1)) $$@
+ $$(call LIST_ALL_OLD_GLOB_MATCHES_EXCEPT,$$(dir $$@),$(LIBRUSTUV_GLOB_$(4)),$$(notdir $$@))
$$(HLIB0_H_$(1))/$(CFG_LIBRUSTC_$(1)): \
$$(TLIB$(2)_T_$(1)_H_$(3))/$(CFG_LIBRUSTC_$(1)) \
$(eval $(call DEF_TEST_CRATE_RULES,$(stage),$(target),$(host),$(crate))) \
))))))
+# FIXME (#10104): Raise the stack size to work around rustpkg bypassing
+# the code in rustc that would take care of it.
+define DEF_RUSTPKG_STACK_FIX
+$$(call TEST_OK_FILE,$(1),$(2),$(3),rustpkg): export RUST_MIN_STACK=8000000
+endef
+
+$(foreach host,$(CFG_HOST_TRIPLES), \
+ $(foreach target,$(CFG_TARGET_TRIPLES), \
+ $(foreach stage,$(STAGES), \
+ $(eval $(call DEF_RUSTPKG_STACK_FIX,$(stage),$(target),$(host))))))
+
######################################################################
# Rules for the compiletest tests (rpass, rfail, etc.)
};
let config = &mut config;
let cmds = props.debugger_cmds.connect("\n");
- let check_lines = props.check_lines.clone();
+ let check_lines = &props.check_lines;
// compile test file (it shoud have 'compile-flags:-g' in the header)
let mut ProcRes = compile_test(config, props, testfile);
let num_check_lines = check_lines.len();
if num_check_lines > 0 {
+ // Allow check lines to leave parts unspecified (e.g., uninitialized
+ // bits in the wrong case of an enum) with the notation "[...]".
+ let check_fragments: ~[~[&str]] = check_lines.map(|s| s.split_str_iter("[...]").collect());
// check if each line in props.check_lines appears in the
// output (in order)
let mut i = 0u;
for line in ProcRes.stdout.line_iter() {
- if check_lines[i].trim() == line.trim() {
+ let mut rest = line.trim();
+ let mut first = true;
+ let mut failed = false;
+ for &frag in check_fragments[i].iter() {
+ let found = if first {
+ if rest.starts_with(frag) { Some(0) } else { None }
+ } else {
+ rest.find_str(frag)
+ };
+ match found {
+ None => {
+ failed = true;
+ break;
+ }
+ Some(i) => {
+ rest = rest.slice_from(i + frag.len());
+ }
+ }
+ first = false;
+ }
+ if !failed && rest.len() == 0 {
i += 1u;
}
if i == num_check_lines {
" Vim indent file
" Language: Rust
" Author: Chris Morgan <me@chrismorgan.info>
-" Last Change: 2013 Jul 10
+" Last Change: 2013 Oct 29
" Only load this indent file when no other was loaded.
if exists("b:did_indent")
let prevline = s:get_line_trimmed(prevnonblank(a:lnum - 1))
if prevline[len(prevline) - 1] == ","
\ && s:get_line_trimmed(a:lnum) !~ "^\\s*[\\[\\]{}]"
+ \ && prevline !~ "^\\s*fn\\s"
" Oh ho! The previous line ended in a comma! I bet cindent will try to
- " take this too far... For now, let's use the previous line's indent
+ " take this too far... For now, let's normally use the previous line's
+ " indent.
+
+ " One case where this doesn't work out is where *this* line contains
+ " square or curly brackets; then we normally *do* want to be indenting
+ " further.
+ "
+ " Another case where we don't want to is one like a function
+ " definition with arguments spread over multiple lines:
+ "
+ " fn foo(baz: Baz,
+ " baz: Baz) // <-- cindent gets this right by itself
+ "
+ " There are probably other cases where we don't want to do this as
+ " well. Add them as needed.
return GetRustIndent(a:lnum - 1)
endif
" Maintainer: Patrick Walton <pcwalton@mozilla.com>
" Maintainer: Ben Blum <bblum@cs.cmu.edu>
" Maintainer: Chris Morgan <me@chrismorgan.info>
-" Last Change: 2013 Oct 19
+" Last Change: 2013 Oct 29
if version < 600
syntax clear
"syn keyword rustFunction from_str
" Types and traits {{{3
+syn keyword rustTrait Any AnyOwnExt AnyRefExt AnyMutRefExt
+syn keyword rustTrait Ascii AsciiCast OwnedAsciiCast AsciiStr ToBytesConsume
+syn keyword rustTrait Bool
syn keyword rustTrait ToCStr
+syn keyword rustTrait Char
syn keyword rustTrait Clone DeepClone
syn keyword rustTrait Eq ApproxEq Ord TotalEq TotalOrd Ordering Equiv
syn keyword rustEnumVariant Less Equal Greater
-syn keyword rustTrait Char
syn keyword rustTrait Container Mutable Map MutableMap Set MutableSet
+syn keyword rustTrait Default
syn keyword rustTrait Hash
-syn keyword rustTrait Times
+syn keyword rustTrait FromStr
syn keyword rustTrait FromIterator Extendable
syn keyword rustTrait Iterator DoubleEndedIterator RandomAccessIterator ClonableIterator
syn keyword rustTrait OrdIterator MutableDoubleEndedIterator ExactSize
-syn keyword rustTrait Num NumCast CheckedAdd CheckedSub CheckedMul
-syn keyword rustTrait Orderable Signed Unsigned Round
+syn keyword rustTrait Times
+
syn keyword rustTrait Algebraic Trigonometric Exponential Hyperbolic
-syn keyword rustTrait Integer Fractional Real RealExt
syn keyword rustTrait Bitwise BitCount Bounded
+syn keyword rustTrait Integer Fractional Real RealExt
+syn keyword rustTrait Num NumCast CheckedAdd CheckedSub CheckedMul
+syn keyword rustTrait Orderable Signed Unsigned Round
syn keyword rustTrait Primitive Int Float ToStrRadix ToPrimitive FromPrimitive
-syn keyword rustTrait GenericPath
-syn keyword rustTrait Path
-syn keyword rustTrait PosixPath
-syn keyword rustTrait WindowsPath
+syn keyword rustTrait GenericPath Path PosixPath WindowsPath
syn keyword rustTrait RawPtr
-syn keyword rustTrait Ascii AsciiCast OwnedAsciiCast AsciiStr ToBytesConsume
syn keyword rustTrait SendStr SendStrOwned SendStrStatic IntoSendStr
syn keyword rustTrait Str StrVector StrSlice OwnedStr
-syn keyword rustTrait FromStr
syn keyword rustTrait IterBytes
syn keyword rustTrait ToStr ToStrConsume
syn keyword rustTrait CopyableTuple ImmutableTuple
-syn keyword rustTrait Tuple1 ImmutableTuple1
-syn keyword rustTrait Tuple2 Tuple3 Tuple4 Tuple5
-syn keyword rustTrait Tuple6 Tuple7 Tuple8 Tuple9
-syn keyword rustTrait Tuple10 Tuple11 Tuple12
-syn keyword rustTrait ImmutableTuple2 ImmutableTuple3 ImmutableTuple4 ImmutableTuple5
-syn keyword rustTrait ImmutableTuple6 ImmutableTuple7 ImmutableTuple8 ImmutableTuple9
-syn keyword rustTrait ImmutableTuple10 ImmutableTuple11 ImmutableTuple12
-syn keyword rustTrait Vector VectorVector CopyableVector ImmutableVector
+syn keyword rustTrait Tuple1 Tuple2 Tuple3 Tuple4
+syn keyword rustTrait Tuple5 Tuple6 Tuple7 Tuple8
+syn keyword rustTrait Tuple9 Tuple10 Tuple11 Tuple12
+syn keyword rustTrait ImmutableTuple1 ImmutableTuple2 ImmutableTuple3 ImmutableTuple4
+syn keyword rustTrait ImmutableTuple5 ImmutableTuple6 ImmutableTuple7 ImmutableTuple8
+syn keyword rustTrait ImmutableTuple9 ImmutableTuple10 ImmutableTuple11 ImmutableTuple12
syn keyword rustTrait ImmutableEqVector ImmutableTotalOrdVector ImmutableCopyableVector
syn keyword rustTrait OwnedVector OwnedCopyableVector OwnedEqVector MutableVector
-syn keyword rustTrait Reader ReaderUtil Writer WriterUtil
-syn keyword rustTrait Default
+syn keyword rustTrait Vector VectorVector CopyableVector ImmutableVector
"syn keyword rustFunction stream
syn keyword rustTrait Port Chan GenericChan GenericSmartChan GenericPort Peekable
use enum_set::*;
#[deriving(Eq)]
+ #[repr(uint)]
enum Foo {
A, B, C
}
pub use std::clone;
pub use std::condition;
pub use std::cmp;
+ // NOTE: Remove import after next snapshot
+ #[cfg(stage0)]
pub use std::sys;
pub use std::unstable;
pub use std::str;
pub static Metadata: TypeKind = 14;
pub static X86_MMX: TypeKind = 15;
+#[repr(C)]
pub enum AtomicBinOp {
Xchg = 0,
Add = 1,
UMin = 10,
}
+#[repr(C)]
pub enum AtomicOrdering {
NotAtomic = 0,
Unordered = 1,
}
// Consts for the LLVMCodeGenFileType type (in include/llvm/c/TargetMachine.h)
+#[repr(C)]
pub enum FileType {
AssemblyFile = 0,
ObjectFile = 1
}
#[deriving(Eq)]
+#[repr(C)]
pub enum CodeGenOptLevel {
CodeGenLevelNone = 0,
CodeGenLevelLess = 1,
CodeGenLevelAggressive = 3,
}
+#[repr(C)]
pub enum RelocMode {
RelocDefault = 0,
RelocStatic = 1,
RelocDynamicNoPic = 3,
}
+#[repr(C)]
pub enum CodeGenModel {
CodeModelDefault = 0,
CodeModelJITDefault = 1,
// used to encode crate_ctxt side tables
#[deriving(Eq)]
+#[repr(uint)]
pub enum astencode_tag { // Reserves 0x50 -- 0x6f
tag_ast = 0x50,
pub fn from_uint(value : uint) -> Option<astencode_tag> {
let is_a_tag = first_astencode_tag <= value && value <= last_astencode_tag;
if !is_a_tag { None } else {
- Some(unsafe { cast::transmute(value as int) })
+ Some(unsafe { cast::transmute(value) })
}
}
}
encode_family(ebml_w, 't');
encode_bounds_and_type(ebml_w, ecx, &lookup_item_type(tcx, def_id));
encode_name(ecx, ebml_w, item.ident);
+ encode_attributes(ebml_w, item.attrs);
for v in (*enum_definition).variants.iter() {
encode_variant_id(ebml_w, local_def(v.node.id));
}
//! Context itself, span_lint should be used instead of add_lint.
use driver::session;
+use middle::trans::adt; // for `adt::is_ffi_safe`
use middle::ty;
use middle::pat_util;
use metadata::csearch;
"found rust type `uint` in foreign module, while \
libc::c_uint or libc::c_ulong should be used");
}
+ ast::DefTy(def_id) => {
+ if !adt::is_ffi_safe(cx.tcx, def_id) {
+ cx.span_lint(ctypes, ty.span,
+ "found enum type without foreign-function-safe \
+ representation annotation in foreign module");
+ // NOTE this message could be more helpful
+ }
+ }
_ => ()
}
}
* This module determines how to represent enums, structs, and tuples
* based on their monomorphized types; it is responsible both for
* choosing a representation and translating basic operations on
- * values of those types.
+ * values of those types. (Note: exporting the representations for
+ * debuggers is handled in debuginfo.rs, not here.)
*
* Note that the interface treats everything as a general case of an
* enum, so structs/tuples/etc. have one pseudo-variant with
* that might contain one and adjust GEP indices accordingly. See
* issue #4578.
*
- * - Using smaller integer types for discriminants.
- *
* - Store nested enums' discriminants in the same word. Rather, if
* some variants start with enums, and those enums representations
* have unused alignment padding between discriminant and body, the
use middle::trans::type_of;
use middle::ty;
use middle::ty::Disr;
+use syntax::abi::{X86, X86_64, Arm, Mips};
use syntax::ast;
+use syntax::attr;
+use syntax::attr::IntType;
use util::ppaux::ty_to_str;
use middle::trans::type_::Type;
+type Hint = attr::ReprAttr;
+
/// Representations.
pub enum Repr {
/// C-like enums; basically an int.
- CEnum(Disr, Disr), // discriminant range
+ CEnum(IntType, Disr, Disr), // discriminant range (signedness based on the IntType)
/**
* Single-case variants, and structs/tuples/records.
*
* General-case enums: for each case there is a struct, and they
* all start with a field for the discriminant.
*/
- General(~[Struct]),
+ General(IntType, ~[Struct]),
/**
* Two cases distinguished by a nullable pointer: the case with discriminant
* `nndiscr` is represented by the struct `nonnull`, where the `ptrfield`th
return Univariant(mk_struct(cx, ftys, packed), dtor)
}
ty::ty_enum(def_id, ref substs) => {
- struct Case { discr: Disr, tys: ~[ty::t] };
- impl Case {
- fn is_zerolen(&self, cx: &mut CrateContext) -> bool {
- mk_struct(cx, self.tys, false).size == 0
- }
- fn find_ptr(&self) -> Option<uint> {
- self.tys.iter().position(|&ty| mono_data_classify(ty) == MonoNonNull)
- }
- }
-
- let cases = do ty::enum_variants(cx.tcx, def_id).map |vi| {
- let arg_tys = do vi.args.map |&raw_ty| {
- ty::subst(cx.tcx, substs, raw_ty)
- };
- Case { discr: vi.disr_val, tys: arg_tys }
- };
+ let cases = get_cases(cx.tcx, def_id, substs);
+ let hint = ty::lookup_repr_hint(cx.tcx, def_id);
if cases.len() == 0 {
// Uninhabitable; represent as unit
+ // (Typechecking will reject discriminant-sizing attrs.)
+ assert_eq!(hint, attr::ReprAny);
return Univariant(mk_struct(cx, [], false), false);
}
if cases.iter().all(|c| c.tys.len() == 0) {
// All bodies empty -> intlike
let discrs = cases.map(|c| c.discr);
- return CEnum(*discrs.iter().min().unwrap(), *discrs.iter().max().unwrap());
- }
-
- if cases.len() == 1 {
- // Equivalent to a struct/tuple/newtype.
- assert_eq!(cases[0].discr, 0);
- return Univariant(mk_struct(cx, cases[0].tys, false), false)
+ let bounds = IntBounds {
+ ulo: *discrs.iter().min().unwrap(),
+ uhi: *discrs.iter().max().unwrap(),
+ slo: discrs.iter().map(|n| *n as i64).min().unwrap(),
+ shi: discrs.iter().map(|n| *n as i64).max().unwrap()
+ };
+ return mk_cenum(cx, hint, &bounds);
}
// Since there's at least one
ty::item_path_str(cx.tcx, def_id)))
}
- if cases.len() == 2 {
+ if cases.len() == 1 {
+ // Equivalent to a struct/tuple/newtype.
+ // (Typechecking will reject discriminant-sizing attrs.)
+ assert_eq!(hint, attr::ReprAny);
+ return Univariant(mk_struct(cx, cases[0].tys, false), false)
+ }
+
+ if cases.len() == 2 && hint == attr::ReprAny {
+ // Nullable pointer optimization
let mut discr = 0;
while discr < 2 {
if cases[1 - discr].is_zerolen(cx) {
}
// The general case.
- let discr = ~[ty::mk_uint()];
- return General(cases.map(|c| mk_struct(cx, discr + c.tys, false)))
+ assert!((cases.len() - 1) as i64 >= 0);
+ let bounds = IntBounds { ulo: 0, uhi: (cases.len() - 1) as u64,
+ slo: 0, shi: (cases.len() - 1) as i64 };
+ let ity = range_to_inttype(cx, hint, &bounds);
+ let discr = ~[ty_of_inttype(ity)];
+ return General(ity, cases.map(|c| mk_struct(cx, discr + c.tys, false)))
}
_ => cx.sess.bug("adt::represent_type called on non-ADT type")
}
}
+/// Determine, without doing translation, whether an ADT must be FFI-safe.
+/// For use in lint or similar, where being sound but slightly incomplete is acceptable.
+pub fn is_ffi_safe(tcx: ty::ctxt, def_id: ast::DefId) -> bool {
+ match ty::get(ty::lookup_item_type(tcx, def_id).ty).sty {
+ ty::ty_enum(def_id, _) => {
+ let variants = ty::enum_variants(tcx, def_id);
+ // Univariant => like struct/tuple.
+ if variants.len() <= 1 {
+ return true;
+ }
+ let hint = ty::lookup_repr_hint(tcx, def_id);
+ // Appropriate representation explicitly selected?
+ if hint.is_ffi_safe() {
+ return true;
+ }
+ // Option<~T> and similar are used in FFI. Rather than try to resolve type parameters
+ // and recognize this case exactly, this overapproximates -- assuming that if a
+ // non-C-like enum is being used in FFI then the user knows what they're doing.
+ if variants.iter().any(|vi| !vi.args.is_empty()) {
+ return true;
+ }
+ false
+ }
+ // struct, tuple, etc.
+ // (is this right in the present of typedefs?)
+ _ => true
+ }
+}
+
+// NOTE this should probably all be in ty
+struct Case { discr: Disr, tys: ~[ty::t] }
+impl Case {
+ fn is_zerolen(&self, cx: &mut CrateContext) -> bool {
+ mk_struct(cx, self.tys, false).size == 0
+ }
+ fn find_ptr(&self) -> Option<uint> {
+ self.tys.iter().position(|&ty| mono_data_classify(ty) == MonoNonNull)
+ }
+}
+
+fn get_cases(tcx: ty::ctxt, def_id: ast::DefId, substs: &ty::substs) -> ~[Case] {
+ do ty::enum_variants(tcx, def_id).map |vi| {
+ let arg_tys = do vi.args.map |&raw_ty| {
+ ty::subst(tcx, substs, raw_ty)
+ };
+ Case { discr: vi.disr_val, tys: arg_tys }
+ }
+}
+
+
fn mk_struct(cx: &mut CrateContext, tys: &[ty::t], packed: bool) -> Struct {
let lltys = tys.map(|&ty| type_of::sizing_type_of(cx, ty));
let llty_rec = Type::struct_(lltys, packed);
}
}
+struct IntBounds {
+ slo: i64,
+ shi: i64,
+ ulo: u64,
+ uhi: u64
+}
+
+fn mk_cenum(cx: &mut CrateContext, hint: Hint, bounds: &IntBounds) -> Repr {
+ let it = range_to_inttype(cx, hint, bounds);
+ match it {
+ attr::SignedInt(_) => CEnum(it, bounds.slo as Disr, bounds.shi as Disr),
+ attr::UnsignedInt(_) => CEnum(it, bounds.ulo, bounds.uhi)
+ }
+}
+
+fn range_to_inttype(cx: &mut CrateContext, hint: Hint, bounds: &IntBounds) -> IntType {
+ debug!("range_to_inttype: {:?} {:?}", hint, bounds);
+ // Lists of sizes to try. u64 is always allowed as a fallback.
+ static choose_shortest: &'static[IntType] = &[
+ attr::UnsignedInt(ast::ty_u8), attr::SignedInt(ast::ty_i8),
+ attr::UnsignedInt(ast::ty_u16), attr::SignedInt(ast::ty_i16),
+ attr::UnsignedInt(ast::ty_u32), attr::SignedInt(ast::ty_i32)];
+ static at_least_32: &'static[IntType] = &[
+ attr::UnsignedInt(ast::ty_u32), attr::SignedInt(ast::ty_i32)];
+
+ let attempts;
+ match hint {
+ attr::ReprInt(span, ity) => {
+ if !bounds_usable(cx, ity, bounds) {
+ cx.sess.span_bug(span, "representation hint insufficient for discriminant range")
+ }
+ return ity;
+ }
+ attr::ReprExtern => {
+ attempts = match cx.sess.targ_cfg.arch {
+ X86 | X86_64 => at_least_32,
+ // WARNING: the ARM EABI has two variants; the one corresponding to `at_least_32`
+ // appears to be used on Linux and NetBSD, but some systems may use the variant
+ // corresponding to `choose_shortest`. However, we don't run on those yet...?
+ Arm => at_least_32,
+ Mips => at_least_32,
+ }
+ }
+ attr::ReprAny => {
+ attempts = choose_shortest;
+ }
+ }
+ for &ity in attempts.iter() {
+ if bounds_usable(cx, ity, bounds) {
+ return ity;
+ }
+ }
+ return attr::UnsignedInt(ast::ty_u64);
+}
+
+pub fn ll_inttype(cx: &mut CrateContext, ity: IntType) -> Type {
+ match ity {
+ attr::SignedInt(t) => Type::int_from_ty(cx, t),
+ attr::UnsignedInt(t) => Type::uint_from_ty(cx, t)
+ }
+}
+
+fn bounds_usable(cx: &mut CrateContext, ity: IntType, bounds: &IntBounds) -> bool {
+ debug!("bounds_usable: {:?} {:?}", ity, bounds);
+ match ity {
+ attr::SignedInt(_) => {
+ let lllo = C_integral(ll_inttype(cx, ity), bounds.slo as u64, true);
+ let llhi = C_integral(ll_inttype(cx, ity), bounds.shi as u64, true);
+ bounds.slo == const_to_int(lllo) as i64 && bounds.shi == const_to_int(llhi) as i64
+ }
+ attr::UnsignedInt(_) => {
+ let lllo = C_integral(ll_inttype(cx, ity), bounds.ulo, false);
+ let llhi = C_integral(ll_inttype(cx, ity), bounds.uhi, false);
+ bounds.ulo == const_to_uint(lllo) as u64 && bounds.uhi == const_to_uint(llhi) as u64
+ }
+ }
+}
+
+pub fn ty_of_inttype(ity: IntType) -> ty::t {
+ match ity {
+ attr::SignedInt(t) => ty::mk_mach_int(t),
+ attr::UnsignedInt(t) => ty::mk_mach_uint(t)
+ }
+}
+
+
/**
* Returns the fields of a struct for the given representation.
* All nominal types are LLVM structs, in order to be able to use
}
fn generic_fields_of(cx: &mut CrateContext, r: &Repr, sizing: bool) -> ~[Type] {
match *r {
- CEnum(*) => ~[Type::enum_discrim(cx)],
+ CEnum(ity, _, _) => ~[ll_inttype(cx, ity)],
Univariant(ref st, _dtor) => struct_llfields(cx, st, sizing),
NullablePointer{ nonnull: ref st, _ } => struct_llfields(cx, st, sizing),
- General(ref sts) => {
- // To get "the" type of a general enum, we pick the case
- // with the largest alignment (so it will always align
- // correctly in containing structures) and pad it out.
- assert!(sts.len() >= 1);
- let mut most_aligned = None;
- let mut largest_align = 0;
- let mut largest_size = 0;
- for st in sts.iter() {
- if largest_size < st.size {
- largest_size = st.size;
- }
- if largest_align < st.align {
- // Clang breaks ties by size; it is unclear if
- // that accomplishes anything important.
- largest_align = st.align;
- most_aligned = Some(st);
- }
- }
- let most_aligned = most_aligned.unwrap();
- let padding = largest_size - most_aligned.size;
-
- struct_llfields(cx, most_aligned, sizing)
- + &[Type::array(&Type::i8(), padding)]
+ General(ity, ref sts) => {
+ // We need a representation that has:
+ // * The alignment of the most-aligned field
+ // * The size of the largest variant (rounded up to that alignment)
+ // * No alignment padding anywhere any variant has actual data
+ // (currently matters only for enums small enough to be immediate)
+ // * The discriminant in an obvious place.
+ //
+ // So we start with the discriminant, pad it up to the alignment with
+ // more of its own type, then use alignment-sized ints to get the rest
+ // of the size.
+ //
+ // Note: if/when we start exposing SIMD vector types (or f80, on some
+ // platforms that have it), this will need some adjustment.
+ let size = sts.iter().map(|st| st.size).max().unwrap();
+ let most_aligned = sts.iter().max_by(|st| st.align).unwrap();
+ let align = most_aligned.align;
+ let discr_ty = ll_inttype(cx, ity);
+ let discr_size = machine::llsize_of_alloc(cx, discr_ty) as u64;
+ let pad_ty = match align {
+ 1 => Type::i8(),
+ 2 => Type::i16(),
+ 4 => Type::i32(),
+ 8 if machine::llalign_of_min(cx, Type::i64()) == 8 => Type::i64(),
+ _ => fail!("Unsupported enum alignment: {:?}", align)
+ };
+ assert_eq!(machine::llalign_of_min(cx, pad_ty) as u64, align);
+ let align_units = (size + align - 1) / align;
+ assert_eq!(align % discr_size, 0);
+ ~[discr_ty,
+ Type::array(&discr_ty, align / discr_size - 1),
+ Type::array(&pad_ty, align_units - 1)]
}
}
}
-> (_match::branch_kind, Option<ValueRef>) {
match *r {
CEnum(*) | General(*) => {
- (_match::switch, Some(trans_get_discr(bcx, r, scrutinee)))
+ (_match::switch, Some(trans_get_discr(bcx, r, scrutinee, None)))
}
NullablePointer{ nonnull: ref nonnull, nndiscr, ptrfield, _ } => {
(_match::switch, Some(nullable_bitdiscr(bcx, nonnull, nndiscr, ptrfield, scrutinee)))
/// Obtain the actual discriminant of a value.
-pub fn trans_get_discr(bcx: @mut Block, r: &Repr, scrutinee: ValueRef)
+pub fn trans_get_discr(bcx: @mut Block, r: &Repr, scrutinee: ValueRef, cast_to: Option<Type>)
-> ValueRef {
+ let signed;
+ let val;
match *r {
- CEnum(min, max) => load_discr(bcx, scrutinee, min, max),
- Univariant(*) => C_disr(bcx.ccx(), 0),
- General(ref cases) => load_discr(bcx, scrutinee, 0, (cases.len() - 1) as Disr),
+ CEnum(ity, min, max) => {
+ val = load_discr(bcx, ity, scrutinee, min, max);
+ signed = ity.is_signed();
+ }
+ General(ity, ref cases) => {
+ val = load_discr(bcx, ity, scrutinee, 0, (cases.len() - 1) as Disr);
+ signed = ity.is_signed();
+ }
+ Univariant(*) => {
+ val = C_u8(0);
+ signed = false;
+ }
NullablePointer{ nonnull: ref nonnull, nndiscr, ptrfield, _ } => {
- ZExt(bcx, nullable_bitdiscr(bcx, nonnull, nndiscr, ptrfield, scrutinee),
- Type::enum_discrim(bcx.ccx()))
+ val = nullable_bitdiscr(bcx, nonnull, nndiscr, ptrfield, scrutinee);
+ signed = false;
}
}
+ match cast_to {
+ None => val,
+ Some(llty) => if signed { SExt(bcx, val, llty) } else { ZExt(bcx, val, llty) }
+ }
}
fn nullable_bitdiscr(bcx: @mut Block, nonnull: &Struct, nndiscr: Disr, ptrfield: uint,
}
/// Helper for cases where the discriminant is simply loaded.
-fn load_discr(bcx: @mut Block, scrutinee: ValueRef, min: Disr, max: Disr)
+fn load_discr(bcx: @mut Block, ity: IntType, scrutinee: ValueRef, min: Disr, max: Disr)
-> ValueRef {
let ptr = GEPi(bcx, scrutinee, [0, 0]);
- if max + 1 == min {
+ let llty = ll_inttype(bcx.ccx(), ity);
+ assert_eq!(val_ty(ptr), llty.ptr_to());
+ let bits = machine::llbitsize_of_real(bcx.ccx(), llty);
+ assert!(bits <= 64);
+ let mask = (-1u64 >> (64 - bits)) as Disr;
+ if (max + 1) & mask == min & mask {
// i.e., if the range is everything. The lo==hi case would be
// rejected by the LLVM verifier (it would mean either an
// empty set, which is impossible, or the entire range of the
*/
pub fn trans_case(bcx: @mut Block, r: &Repr, discr: Disr) -> _match::opt_result {
match *r {
- CEnum(*) => {
- _match::single_result(rslt(bcx, C_disr(bcx.ccx(), discr)))
+ CEnum(ity, _, _) => {
+ _match::single_result(rslt(bcx, C_integral(ll_inttype(bcx.ccx(), ity),
+ discr as u64, true)))
+ }
+ General(ity, _) => {
+ _match::single_result(rslt(bcx, C_integral(ll_inttype(bcx.ccx(), ity),
+ discr as u64, true)))
}
Univariant(*) => {
bcx.ccx().sess.bug("no cases for univariants or structs")
}
- General(*) => {
- _match::single_result(rslt(bcx, C_disr(bcx.ccx(), discr)))
- }
NullablePointer{ _ } => {
assert!(discr == 0 || discr == 1);
_match::single_result(rslt(bcx, C_i1(discr != 0)))
*/
pub fn trans_start_init(bcx: @mut Block, r: &Repr, val: ValueRef, discr: Disr) {
match *r {
- CEnum(min, max) => {
- assert!(min <= discr && discr <= max);
- Store(bcx, C_disr(bcx.ccx(), discr), GEPi(bcx, val, [0, 0]))
+ CEnum(ity, min, max) => {
+ assert_discr_in_range(ity, min, max, discr);
+ Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true),
+ GEPi(bcx, val, [0, 0]))
+ }
+ General(ity, _) => {
+ Store(bcx, C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true),
+ GEPi(bcx, val, [0, 0]))
}
Univariant(ref st, true) => {
assert_eq!(discr, 0);
Univariant(*) => {
assert_eq!(discr, 0);
}
- General(*) => {
- Store(bcx, C_disr(bcx.ccx(), discr), GEPi(bcx, val, [0, 0]))
- }
NullablePointer{ nonnull: ref nonnull, nndiscr, ptrfield, _ } => {
if discr != nndiscr {
let llptrptr = GEPi(bcx, val, [0, ptrfield]);
}
}
+fn assert_discr_in_range(ity: IntType, min: Disr, max: Disr, discr: Disr) {
+ match ity {
+ attr::UnsignedInt(_) => assert!(min <= discr && discr <= max),
+ attr::SignedInt(_) => assert!(min as i64 <= discr as i64 && discr as i64 <= max as i64)
+ }
+}
+
/**
* The number of fields in a given case; for use when obtaining this
* information from the type or definition is less convenient.
assert_eq!(discr, 0);
st.fields.len() - (if dtor { 1 } else { 0 })
}
- General(ref cases) => cases[discr].fields.len() - 1,
+ General(_, ref cases) => cases[discr].fields.len() - 1,
NullablePointer{ nonnull: ref nonnull, nndiscr, nullfields: ref nullfields, _ } => {
if discr == nndiscr { nonnull.fields.len() } else { nullfields.len() }
}
assert_eq!(discr, 0);
struct_field_ptr(bcx, st, val, ix, false)
}
- General(ref cases) => {
+ General(_, ref cases) => {
struct_field_ptr(bcx, &cases[discr], val, ix + 1, true)
}
NullablePointer{ nonnull: ref nonnull, nullfields: ref nullfields, nndiscr, _ } => {
pub fn trans_const(ccx: &mut CrateContext, r: &Repr, discr: Disr,
vals: &[ValueRef]) -> ValueRef {
match *r {
- CEnum(min, max) => {
+ CEnum(ity, min, max) => {
assert_eq!(vals.len(), 0);
- assert!(min <= discr && discr <= max);
- C_disr(ccx, discr)
+ assert_discr_in_range(ity, min, max, discr);
+ C_integral(ll_inttype(ccx, ity), discr as u64, true)
}
- Univariant(ref st, _dro) => {
- assert_eq!(discr, 0);
- let contents = build_const_struct(ccx, st, vals);
- C_struct(contents, st.packed)
- }
- General(ref cases) => {
+ General(ity, ref cases) => {
let case = &cases[discr];
let max_sz = cases.iter().map(|x| x.size).max().unwrap();
- let discr_ty = C_disr(ccx, discr);
- let contents = build_const_struct(ccx, case,
- ~[discr_ty] + vals);
+ let lldiscr = C_integral(ll_inttype(ccx, ity), discr as u64, true);
+ let contents = build_const_struct(ccx, case, ~[lldiscr] + vals);
C_struct(contents + &[padding(max_sz - case.size)], false)
}
+ Univariant(ref st, _dro) => {
+ assert!(discr == 0);
+ let contents = build_const_struct(ccx, st, vals);
+ C_struct(contents, st.packed)
+ }
NullablePointer{ nonnull: ref nonnull, nndiscr, ptrfield, _ } => {
if discr == nndiscr {
C_struct(build_const_struct(ccx, nonnull, vals), false)
pub fn const_get_discrim(ccx: &mut CrateContext, r: &Repr, val: ValueRef)
-> Disr {
match *r {
- CEnum(*) => const_to_uint(val) as Disr,
+ CEnum(ity, _, _) => {
+ match ity {
+ attr::SignedInt(*) => const_to_int(val) as Disr,
+ attr::UnsignedInt(*) => const_to_uint(val) as Disr
+ }
+ }
+ General(ity, _) => {
+ match ity {
+ attr::SignedInt(*) => const_to_int(const_get_elt(ccx, val, [0])) as Disr,
+ attr::UnsignedInt(*) => const_to_uint(const_get_elt(ccx, val, [0])) as Disr
+ }
+ }
Univariant(*) => 0,
- General(*) => const_to_uint(const_get_elt(ccx, val, [0])) as Disr,
NullablePointer{ nndiscr, ptrfield, _ } => {
if is_null(const_struct_field(ccx, val, ptrfield)) {
/* subtraction as uint is ok because nndiscr is either 0 or 1 */
_ => false
}
}
-
-fn C_disr(cx: &CrateContext, i: Disr) -> ValueRef {
- return C_integral(cx.int_type, i, false);
-}
return C_integral(Type::i64(), i as u64, true);
}
+pub fn C_u64(i: u64) -> ValueRef {
+ return C_integral(Type::i64(), i, false);
+}
+
pub fn C_int(cx: &CrateContext, i: int) -> ValueRef {
return C_integral(cx.int_type, i as u64, true);
}
-> ~[MemberDescription] {
// Capture type_rep, so we don't have to copy the struct_defs array
let struct_defs = match *self.type_rep {
- adt::General(ref struct_defs) => struct_defs,
+ adt::General(_, ref struct_defs) => struct_defs,
_ => cx.sess.bug("unreachable")
};
return FinalMetadata(empty_type_metadata);
}
- // Prepare some data (llvm type, size, align, etc) about the discriminant. This data will be
- // needed in all of the following cases.
- let discriminant_llvm_type = Type::enum_discrim(cx);
- let (discriminant_size, discriminant_align) = size_and_align_of(cx, discriminant_llvm_type);
-
- assert!(Type::enum_discrim(cx) == cx.int_type);
- let discriminant_base_type_metadata = type_metadata(cx, ty::mk_int(), codemap::dummy_sp());
-
let variants = ty::enum_variants(cx.tcx, enum_def_id);
let enumerators_metadata: ~[DIDescriptor] = variants
})
.collect();
- let discriminant_type_metadata = do enum_name.with_c_str |enum_name| {
- unsafe {
- llvm::LLVMDIBuilderCreateEnumerationType(
- DIB(cx),
- containing_scope,
- enum_name,
- file_metadata,
- loc.line as c_uint,
- bytes_to_bits(discriminant_size),
- bytes_to_bits(discriminant_align),
- create_DIArray(DIB(cx), enumerators_metadata),
- discriminant_base_type_metadata)
+ let discriminant_type_metadata = |inttype| {
+ let discriminant_llvm_type = adt::ll_inttype(cx, inttype);
+ let (discriminant_size, discriminant_align) = size_and_align_of(cx, discriminant_llvm_type);
+ let discriminant_base_type_metadata = type_metadata(cx, adt::ty_of_inttype(inttype),
+ codemap::dummy_sp());
+ do enum_name.with_c_str |enum_name| {
+ unsafe {
+ llvm::LLVMDIBuilderCreateEnumerationType(
+ DIB(cx),
+ containing_scope,
+ enum_name,
+ file_metadata,
+ loc.line as c_uint,
+ bytes_to_bits(discriminant_size),
+ bytes_to_bits(discriminant_align),
+ create_DIArray(DIB(cx), enumerators_metadata),
+ discriminant_base_type_metadata)
+ }
}
};
let type_rep = adt::represent_type(cx, enum_type);
return match *type_rep {
- adt::CEnum(*) => {
- FinalMetadata(discriminant_type_metadata)
+ adt::CEnum(inttype, _, _) => {
+ FinalMetadata(discriminant_type_metadata(inttype))
}
adt::Univariant(ref struct_def, _) => {
assert!(variants.len() == 1);
member_description_factory: member_description_factory
}
}
- adt::General(_) => {
+ adt::General(inttype, _) => {
+ let discriminant_type_metadata = discriminant_type_metadata(inttype);
let enum_llvm_type = type_of::type_of(cx, enum_type);
let (enum_type_size, enum_type_align) = size_and_align_of(cx, enum_llvm_type);
(cast_enum, cast_float) => {
let bcx = bcx;
let repr = adt::represent_type(ccx, t_in);
- let slot = Alloca(bcx, ll_t_in, "");
- Store(bcx, llexpr, slot);
- let lldiscrim_a = adt::trans_get_discr(bcx, repr, slot);
+ let llexpr_ptr;
+ if type_is_immediate(ccx, t_in) {
+ llexpr_ptr = Alloca(bcx, ll_t_in, "");
+ Store(bcx, llexpr, llexpr_ptr);
+ } else {
+ llexpr_ptr = llexpr;
+ }
+ let lldiscrim_a = adt::trans_get_discr(bcx, repr, llexpr_ptr, Some(Type::i64()));
match k_out {
cast_integral => int_cast(bcx, ll_t_out,
val_ty(lldiscrim_a),
use util::ppaux::ty_to_str;
use std::libc::c_uint;
-use std::option::None;
+use std::option::{Some,None};
use std::vec;
use syntax::ast::DefId;
use syntax::ast;
sub_path,
"get_disr");
- let llfdecl = decl_internal_rust_fn(ccx, [opaqueptrty], ty::mk_int(), sym);
+ let llfdecl = decl_internal_rust_fn(ccx, [opaqueptrty], ty::mk_u64(), sym);
let fcx = new_fn_ctxt(ccx,
~[],
llfdecl,
- ty::mk_uint(),
+ ty::mk_u64(),
None);
let arg = unsafe {
//
};
let mut bcx = fcx.entry_bcx.unwrap();
let arg = BitCast(bcx, arg, llptrty);
- let ret = adt::trans_get_discr(bcx, repr, arg);
+ let ret = adt::trans_get_discr(bcx, repr, arg, Some(Type::i64()));
Store(bcx, ret, fcx.llretptr.unwrap());
match fcx.llreturn {
Some(llreturn) => cleanup_and_Br(bcx, bcx, llreturn),
for (i, v) in variants.iter().enumerate() {
let name = ccx.sess.str_of(v.name);
let variant_args = ~[this.c_uint(i),
- C_integral(self.bcx.ccx().int_type, v.disr_val, false),
+ C_u64(v.disr_val),
this.c_uint(v.args.len()),
this.c_slice(name)];
do this.bracketed("enum_variant", variant_args) |this| {
use middle::trans::expr::{Dest, Ignore, SaveIn};
use middle::trans::expr;
use middle::trans::glue;
-use middle::trans::machine::{llsize_of, nonzero_llsize_of};
+use middle::trans::machine::{llsize_of, nonzero_llsize_of, llsize_of_alloc};
use middle::trans::type_of;
use middle::ty;
use util::common::indenter;
vec_ty: ty::t,
unit_ty: ty::t,
llunit_ty: Type,
- llunit_size: ValueRef
+ llunit_size: ValueRef,
+ llunit_alloc_size: uint
}
impl VecTypes {
pub fn to_str(&self, ccx: &CrateContext) -> ~str {
- format!("VecTypes \\{vec_ty={}, unit_ty={}, llunit_ty={}, llunit_size={}\\}",
+ format!("VecTypes \\{vec_ty={}, unit_ty={}, llunit_ty={}, llunit_size={}, \
+ llunit_alloc_size={}\\}",
ty_to_str(ccx.tcx, self.vec_ty),
ty_to_str(ccx.tcx, self.unit_ty),
ccx.tn.type_to_str(self.llunit_ty),
- ccx.tn.val_to_str(self.llunit_size))
+ ccx.tn.val_to_str(self.llunit_size),
+ self.llunit_alloc_size)
}
}
expr::trans_to_datum(bcx, element)
});
- let next_bcx = sub_block(bcx, "expr_repeat: while next");
- let loop_bcx = loop_scope_block(bcx, next_bcx, None, "expr_repeat", None);
- let cond_bcx = scope_block(loop_bcx, None, "expr_repeat: loop cond");
- let set_bcx = scope_block(loop_bcx, None, "expr_repeat: body: set");
- let inc_bcx = scope_block(loop_bcx, None, "expr_repeat: body: inc");
- Br(bcx, loop_bcx.llbb);
-
- let loop_counter = {
- // i = 0
- let i = alloca(loop_bcx, bcx.ccx().int_type, "__i");
- Store(loop_bcx, C_uint(bcx.ccx(), 0), i);
-
- Br(loop_bcx, cond_bcx.llbb);
- i
- };
-
- { // i < count
- let lhs = Load(cond_bcx, loop_counter);
- let rhs = C_uint(bcx.ccx(), count);
- let cond_val = ICmp(cond_bcx, lib::llvm::IntULT, lhs, rhs);
-
- CondBr(cond_bcx, cond_val, set_bcx.llbb, next_bcx.llbb);
- }
-
- { // v[i] = elem
- let i = Load(set_bcx, loop_counter);
- let lleltptr = InBoundsGEP(set_bcx, lldest, [i]);
- let set_bcx = elem.copy_to(set_bcx, INIT, lleltptr);
-
- Br(set_bcx, inc_bcx.llbb);
- }
-
- { // i += 1
- let i = Load(inc_bcx, loop_counter);
- let plusone = Add(inc_bcx, i, C_uint(bcx.ccx(), 1));
- Store(inc_bcx, plusone, loop_counter);
-
- Br(inc_bcx, cond_bcx.llbb);
- }
-
- return next_bcx;
-
+ iter_vec_loop(bcx, lldest, vt,
+ C_uint(bcx.ccx(), count), |set_bcx, lleltptr, _| {
+ elem.copy_to(set_bcx, INIT, lleltptr)
+ })
}
}
}
let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
let llunit_ty = type_of::type_of(ccx, unit_ty);
let llunit_size = nonzero_llsize_of(ccx, llunit_ty);
+ let llunit_alloc_size = llsize_of_alloc(ccx, llunit_ty);
VecTypes {vec_ty: vec_ty,
unit_ty: unit_ty,
llunit_ty: llunit_ty,
- llunit_size: llunit_size}
+ llunit_size: llunit_size,
+ llunit_alloc_size: llunit_alloc_size}
}
pub fn elements_required(bcx: @mut Block, content_expr: &ast::Expr) -> uint {
pub type iter_vec_block<'self> = &'self fn(@mut Block, ValueRef, ty::t) -> @mut Block;
+pub fn iter_vec_loop(bcx: @mut Block,
+ data_ptr: ValueRef,
+ vt: &VecTypes,
+ count: ValueRef,
+ f: iter_vec_block
+ ) -> @mut Block {
+ let _icx = push_ctxt("tvec::iter_vec_loop");
+
+ let next_bcx = sub_block(bcx, "iter_vec_loop: while next");
+ let loop_bcx = loop_scope_block(bcx, next_bcx, None, "iter_vec_loop", None);
+ let cond_bcx = scope_block(loop_bcx, None, "iter_vec_loop: loop cond");
+ let body_bcx = scope_block(loop_bcx, None, "iter_vec_loop: body: main");
+ let inc_bcx = scope_block(loop_bcx, None, "iter_vec_loop: loop inc");
+ Br(bcx, loop_bcx.llbb);
+
+ let loop_counter = {
+ // i = 0
+ let i = alloca(loop_bcx, bcx.ccx().int_type, "__i");
+ Store(loop_bcx, C_uint(bcx.ccx(), 0), i);
+
+ Br(loop_bcx, cond_bcx.llbb);
+ i
+ };
+
+ { // i < count
+ let lhs = Load(cond_bcx, loop_counter);
+ let rhs = count;
+ let cond_val = ICmp(cond_bcx, lib::llvm::IntULT, lhs, rhs);
+
+ CondBr(cond_bcx, cond_val, body_bcx.llbb, next_bcx.llbb);
+ }
+
+ { // loop body
+ let i = Load(body_bcx, loop_counter);
+ let lleltptr = if vt.llunit_alloc_size == 0 {
+ data_ptr
+ } else {
+ InBoundsGEP(body_bcx, data_ptr, [i])
+ };
+ let body_bcx = f(body_bcx, lleltptr, vt.unit_ty);
+
+ Br(body_bcx, inc_bcx.llbb);
+ }
+
+ { // i += 1
+ let i = Load(inc_bcx, loop_counter);
+ let plusone = Add(inc_bcx, i, C_uint(bcx.ccx(), 1));
+ Store(inc_bcx, plusone, loop_counter);
+
+ Br(inc_bcx, cond_bcx.llbb);
+ }
+
+ next_bcx
+}
+
pub fn iter_vec_raw(bcx: @mut Block, data_ptr: ValueRef, vec_ty: ty::t,
fill: ValueRef, f: iter_vec_block) -> @mut Block {
let _icx = push_ctxt("tvec::iter_vec_raw");
- let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
-
- // Calculate the last pointer address we want to handle.
- // FIXME (#3729): Optimize this when the size of the unit type is
- // statically known to not use pointer casts, which tend to confuse
- // LLVM.
- let data_end_ptr = pointer_add_byte(bcx, data_ptr, fill);
-
- // Now perform the iteration.
- let header_bcx = base::sub_block(bcx, "iter_vec_loop_header");
- Br(bcx, header_bcx.llbb);
- let data_ptr =
- Phi(header_bcx, val_ty(data_ptr), [data_ptr], [bcx.llbb]);
- let not_yet_at_end =
- ICmp(header_bcx, lib::llvm::IntULT, data_ptr, data_end_ptr);
- let body_bcx = base::sub_block(header_bcx, "iter_vec_loop_body");
- let next_bcx = base::sub_block(header_bcx, "iter_vec_next");
- CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb);
- let body_bcx = f(body_bcx, data_ptr, unit_ty);
- AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr,
- [C_int(bcx.ccx(), 1)]),
- body_bcx.llbb);
- Br(body_bcx, header_bcx.llbb);
- return next_bcx;
+ let vt = vec_types(bcx, vec_ty);
+ if (vt.llunit_alloc_size == 0) {
+ // Special-case vectors with elements of size 0 so they don't go out of bounds (#9890)
+ iter_vec_loop(bcx, data_ptr, &vt, fill, f)
+ } else {
+ // Calculate the last pointer address we want to handle.
+ // FIXME (#3729): Optimize this when the size of the unit type is
+ // statically known to not use pointer casts, which tend to confuse
+ // LLVM.
+ let data_end_ptr = pointer_add_byte(bcx, data_ptr, fill);
+
+ // Now perform the iteration.
+ let header_bcx = base::sub_block(bcx, "iter_vec_loop_header");
+ Br(bcx, header_bcx.llbb);
+ let data_ptr =
+ Phi(header_bcx, val_ty(data_ptr), [data_ptr], [bcx.llbb]);
+ let not_yet_at_end =
+ ICmp(header_bcx, lib::llvm::IntULT, data_ptr, data_end_ptr);
+ let body_bcx = base::sub_block(header_bcx, "iter_vec_loop_body");
+ let next_bcx = base::sub_block(header_bcx, "iter_vec_next");
+ CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb);
+ let body_bcx = f(body_bcx, data_ptr, vt.unit_ty);
+ AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr,
+ [C_int(bcx.ccx(), 1)]),
+ body_bcx.llbb);
+ Br(body_bcx, header_bcx.llbb);
+ next_bcx
+ }
}
pub fn iter_vec_uniq(bcx: @mut Block, vptr: ValueRef, vec_ty: ty::t,
use syntax::ast_util::is_local;
use syntax::ast_util;
use syntax::attr;
+use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
use syntax::codemap;
use syntax::parse::token;
pub type BuiltinBounds = EnumSet<BuiltinBound>;
#[deriving(Clone, Eq, IterBytes, ToStr)]
+#[repr(uint)]
pub enum BuiltinBound {
BoundStatic,
BoundSend,
}
}
-/// Determine whether an item is annotated with an attribute
-pub fn has_attr(tcx: ctxt, did: DefId, attr: &str) -> bool {
+/// Iterate over meta_items of a definition.
+// (This should really be an iterator, but that would require csearch and
+// decoder to use iterators instead of higher-order functions.)
+pub fn each_attr(tcx: ctxt, did: DefId, f: &fn(@MetaItem) -> bool) -> bool {
if is_local(did) {
match tcx.items.find(&did.node) {
- Some(
- &ast_map::node_item(@ast::item {
- attrs: ref attrs,
- _
- }, _)) => attr::contains_name(*attrs, attr),
+ Some(&ast_map::node_item(@ast::item {attrs: ref attrs, _}, _)) =>
+ attrs.iter().advance(|attr| f(attr.node.value)),
_ => tcx.sess.bug(format!("has_attr: {:?} is not an item",
- did))
+ did))
}
} else {
- let mut ret = false;
+ let mut cont = true;
do csearch::get_item_attrs(tcx.cstore, did) |meta_items| {
- ret = ret || attr::contains_name(meta_items, attr);
+ if cont {
+ cont = meta_items.iter().advance(|ptrptr| f(*ptrptr));
+ }
}
- ret
+ return cont;
}
}
+/// Determine whether an item is annotated with an attribute
+pub fn has_attr(tcx: ctxt, did: DefId, attr: &str) -> bool {
+ let mut found = false;
+ each_attr(tcx, did, |item| {
+ if attr == item.name() {
+ found = true;
+ false
+ } else {
+ true
+ }
+ });
+ return found;
+}
+
/// Determine whether an item is annotated with `#[packed]`
pub fn lookup_packed(tcx: ctxt, did: DefId) -> bool {
has_attr(tcx, did, "packed")
has_attr(tcx, did, "simd")
}
+// Obtain the the representation annotation for a definition.
+pub fn lookup_repr_hint(tcx: ctxt, did: DefId) -> attr::ReprAttr {
+ let mut acc = attr::ReprAny;
+ ty::each_attr(tcx, did, |meta| {
+ acc = attr::find_repr_attr(tcx.sess.diagnostic(), meta, acc);
+ true
+ });
+ return acc;
+}
+
// Look up a field ID, whether or not it's local
// Takes a list of type substs in case the struct is generic
pub fn lookup_field_type(tcx: ctxt,
use syntax::ast_map;
use syntax::ast_util::local_def;
use syntax::ast_util;
+use syntax::attr;
use syntax::codemap::Span;
use syntax::codemap;
use syntax::opt_vec::OptVec;
let result_t = fcx.expr_ty(expr);
demand::suptype(fcx, expr.span, result_t, lhs_t);
+ let tcx = fcx.tcx();
+ if !ty::expr_is_lval(tcx, fcx.ccx.method_map, lhs) {
+ tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
+ }
+
// Overwrite result of check_binop...this preserves existing behavior
// but seems quite dubious with regard to user-defined methods
// and so forth. - Niko
}
ast::ExprAssign(lhs, rhs) => {
check_assignment(fcx, lhs, rhs, id);
+
+ let tcx = fcx.tcx();
+ if !ty::expr_is_lval(tcx, fcx.ccx.method_map, lhs) {
+ tcx.sess.span_err(lhs.span, "illegal left-hand side expression");
+ }
+
let lhs_ty = fcx.expr_ty(lhs);
let rhs_ty = fcx.expr_ty(rhs);
if ty::type_is_error(lhs_ty) || ty::type_is_error(rhs_ty) {
sp: Span,
vs: &[ast::variant],
id: ast::NodeId) {
+
+ fn disr_in_range(ccx: @mut CrateCtxt,
+ ty: attr::IntType,
+ disr: ty::Disr) -> bool {
+ fn uint_in_range(ccx: @mut CrateCtxt, ty: ast::uint_ty, disr: ty::Disr) -> bool {
+ match ty {
+ ast::ty_u8 => disr as u8 as Disr == disr,
+ ast::ty_u16 => disr as u16 as Disr == disr,
+ ast::ty_u32 => disr as u32 as Disr == disr,
+ ast::ty_u64 => disr as u64 as Disr == disr,
+ ast::ty_u => uint_in_range(ccx, ccx.tcx.sess.targ_cfg.uint_type, disr)
+ }
+ }
+ fn int_in_range(ccx: @mut CrateCtxt, ty: ast::int_ty, disr: ty::Disr) -> bool {
+ match ty {
+ ast::ty_i8 => disr as i8 as Disr == disr,
+ ast::ty_i16 => disr as i16 as Disr == disr,
+ ast::ty_i32 => disr as i32 as Disr == disr,
+ ast::ty_i64 => disr as i64 as Disr == disr,
+ ast::ty_i => int_in_range(ccx, ccx.tcx.sess.targ_cfg.int_type, disr)
+ }
+ }
+ match ty {
+ attr::UnsignedInt(ty) => uint_in_range(ccx, ty, disr),
+ attr::SignedInt(ty) => int_in_range(ccx, ty, disr)
+ }
+ }
+
fn do_check(ccx: @mut CrateCtxt,
vs: &[ast::variant],
- id: ast::NodeId)
+ id: ast::NodeId,
+ hint: attr::ReprAttr)
-> ~[@ty::VariantInfo] {
let rty = ty::node_id_to_type(ccx.tcx, id);
None => ()
};
- // Check for duplicate discriminator values
+ // Check for duplicate discriminant values
if disr_vals.contains(¤t_disr_val) {
- ccx.tcx.sess.span_err(v.span, "discriminator value already exists");
+ ccx.tcx.sess.span_err(v.span, "discriminant value already exists");
+ }
+ // Check for unrepresentable discriminant values
+ match hint {
+ attr::ReprAny | attr::ReprExtern => (),
+ attr::ReprInt(sp, ity) => {
+ if !disr_in_range(ccx, ity, current_disr_val) {
+ ccx.tcx.sess.span_err(v.span,
+ "discriminant value outside specified type");
+ ccx.tcx.sess.span_note(sp, "discriminant type specified here");
+ }
+ }
}
disr_vals.push(current_disr_val);
}
let rty = ty::node_id_to_type(ccx.tcx, id);
+ let hint = ty::lookup_repr_hint(ccx.tcx, ast::DefId { crate: ast::LOCAL_CRATE, node: id });
+ if hint != attr::ReprAny && vs.len() <= 1 {
+ ccx.tcx.sess.span_err(sp, format!("unsupported representation for {}variant enum",
+ if vs.len() == 1 { "uni" } else { "zero-" }))
+ }
- let variants = do_check(ccx, vs, id);
+ let variants = do_check(ccx, vs, id, hint);
// cache so that ty::enum_variants won't repeat this work
ccx.tcx.enum_var_cache.insert(local_def(id), @variants);
}
}
- fn close(self, cb: NullCallback) {
- let mut this = self;
+ fn close(mut self, cb: NullCallback) {
{
- let data = this.get_watcher_data();
+ let data = self.get_watcher_data();
assert!(data.close_cb.is_none());
data.close_cb = Some(cb);
}
- unsafe { uvll::close(this.native_handle(), close_cb); }
+ unsafe { uvll::close(self.native_handle(), close_cb); }
extern fn close_cb(handle: *uvll::uv_handle_t) {
let mut h: Handle = NativeHandle::from_native_handle(handle);
a // return the result of the IO
}
- fn home_for_io_consume<A>(self, io: &fn(Self) -> A) -> A {
- let mut this = self;
- let home = this.go_to_IO_home();
- let a = io(this); // do IO
+ fn home_for_io_consume<A>(mut self, io: &fn(Self) -> A) -> A {
+ let home = self.go_to_IO_home();
+ let a = io(self); // do IO
HomingIO::restore_original_home(None::<Self>, home);
a // return the result of the IO
}
}
}
-#[cfg(not(stage0), not(test))]
+#[cfg(not(test))]
#[lang = "event_loop_factory"]
pub extern "C" fn new_loop() -> ~EventLoop {
~UvEventLoop::new() as ~EventLoop
}
}
-impl<T> Clone for SharedChan<T> {
+impl<T: Send> Clone for SharedChan<T> {
fn clone(&self) -> SharedChan<T> {
let &SharedChan { x: ref c } = self;
SharedChan { x: c.clone() }
}
}
-impl<T> Clone for SharedPort<T> {
+impl<T: Send> Clone for SharedPort<T> {
fn clone(&self) -> SharedPort<T> {
let &SharedPort { x: ref p } = self;
SharedPort { x: p.clone() }
pub static bytes : uint = ($bits / 8);
pub static min_value: $T = (-1 as $T) << (bits - 1);
-pub static max_value: $T = min_value - 1 as $T;
+// FIXME(#9837): Compute min_value like this so the high bits that shouldn't exist are 0.
+pub static max_value: $T = !min_value;
impl CheckedDiv for $T {
#[inline]
#[allow(missing_doc)];
-use unstable::intrinsics::{Opaque, TyDesc, TyVisitor};
+use unstable::intrinsics::{Disr, Opaque, TyDesc, TyVisitor};
use libc::c_void;
use mem;
use unstable::raw;
}
fn visit_enter_enum(&mut self, n_variants: uint,
- get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+ get_disr: extern unsafe fn(ptr: *Opaque) -> Disr,
sz: uint, align: uint)
-> bool {
self.align(align);
}
fn visit_enter_enum_variant(&mut self, variant: uint,
- disr_val: int,
+ disr_val: Disr,
n_fields: uint,
name: &str) -> bool {
if ! self.inner.visit_enter_enum_variant(variant, disr_val,
}
fn visit_leave_enum_variant(&mut self, variant: uint,
- disr_val: int,
+ disr_val: Disr,
n_fields: uint,
name: &str) -> bool {
if ! self.inner.visit_leave_enum_variant(variant, disr_val,
}
fn visit_leave_enum(&mut self, n_variants: uint,
- get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+ get_disr: extern unsafe fn(ptr: *Opaque) -> Disr,
sz: uint, align: uint) -> bool {
if ! self.inner.visit_leave_enum(n_variants, get_disr, sz, align) {
return false;
use str::StrSlice;
use to_str::ToStr;
use vec::OwnedVector;
-use unstable::intrinsics::{Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc};
+use unstable::intrinsics::{Disr, Opaque, TyDesc, TyVisitor, get_tydesc, visit_tydesc};
use unstable::raw;
/// Representations
// New implementation using reflect::MovePtr
enum VariantState {
- SearchingFor(int),
+ SearchingFor(Disr),
Matched,
AlreadyFound
}
fn visit_enter_enum(&mut self,
_n_variants: uint,
- get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+ get_disr: extern unsafe fn(ptr: *Opaque) -> Disr,
_sz: uint,
_align: uint) -> bool {
let disr = unsafe {
}
fn visit_enter_enum_variant(&mut self, _variant: uint,
- disr_val: int,
+ disr_val: Disr,
n_fields: uint,
name: &str) -> bool {
let mut write = false;
}
fn visit_leave_enum_variant(&mut self, _variant: uint,
- _disr_val: int,
+ _disr_val: Disr,
n_fields: uint,
_name: &str) -> bool {
match self.var_stk[self.var_stk.len() - 1] {
fn visit_leave_enum(&mut self,
_n_variants: uint,
- _get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+ _get_disr: extern unsafe fn(ptr: *Opaque) -> Disr,
_sz: uint,
_align: uint)
-> bool {
None => { // not recording borrows
let msg = "borrowed";
do msg.with_c_str |msg_p| {
- task::begin_unwind(msg_p, file, line);
+ task::begin_unwind_raw(msg_p, file, line);
}
}
Some(borrow_list) => { // recording borrows
}
}
do msg.with_c_str |msg_p| {
- task::begin_unwind(msg_p, file, line)
+ task::begin_unwind_raw(msg_p, file, line)
}
}
}
if br.box != a || br.file != file || br.line != line {
let err = format!("wrong borrow found, br={:?}", br);
do err.with_c_str |msg_p| {
- task::begin_unwind(msg_p, file, line)
+ task::begin_unwind_raw(msg_p, file, line)
}
}
borrow_list
}
}
-impl<T> ChanOne<T> {
+impl<T: Send> ChanOne<T> {
#[inline]
fn packet(&self) -> *mut Packet<T> {
unsafe {
}
}
-impl<T> PortOne<T> {
+impl<T: Send> PortOne<T> {
fn packet(&self) -> *mut Packet<T> {
unsafe {
let p: *mut ~Packet<T> = cast::transmute(&self.void_packet);
}
}
-impl<T> SelectInner for PortOne<T> {
+impl<T: Send> SelectInner for PortOne<T> {
#[inline] #[cfg(not(test))]
fn optimistic_check(&mut self) -> bool {
unsafe { (*self.packet()).state.load(Acquire) == STATE_ONE }
}
}
-impl<T> Select for PortOne<T> { }
+impl<T: Send> Select for PortOne<T> { }
-impl<T> SelectPortInner<T> for PortOne<T> {
+impl<T: Send> SelectPortInner<T> for PortOne<T> {
fn recv_ready(mut self) -> Option<T> {
let packet = self.packet();
}
}
-impl<T> SelectPort<T> for PortOne<T> { }
+impl<T: Send> SelectPort<T> for PortOne<T> { }
-impl<T> Peekable<T> for PortOne<T> {
+impl<T: Send> Peekable<T> for PortOne<T> {
fn peek(&self) -> bool {
unsafe {
let packet: *mut Packet<T> = self.packet();
}
#[unsafe_destructor]
-impl<T> Drop for ChanOne<T> {
+impl<T: Send> Drop for ChanOne<T> {
fn drop(&mut self) {
if self.suppress_finalize { return }
}
#[unsafe_destructor]
-impl<T> Drop for PortOne<T> {
+impl<T: Send> Drop for PortOne<T> {
fn drop(&mut self) {
if self.suppress_finalize { return }
}
}
-impl<T> GenericPort<T> for Port<T> {
+impl<T: Send> GenericPort<T> for Port<T> {
fn recv(&self) -> T {
match self.try_recv() {
Some(val) => val,
}
}
-impl<T> Peekable<T> for Port<T> {
+impl<T: Send> Peekable<T> for Port<T> {
fn peek(&self) -> bool {
self.next.with_mut_ref(|p| p.peek())
}
// of them, but a &Port<T> should also be selectable so you can select2 on it
// alongside a PortOne<U> without passing the port by value in recv_ready.
-impl<'self, T> SelectInner for &'self Port<T> {
+impl<'self, T: Send> SelectInner for &'self Port<T> {
#[inline]
fn optimistic_check(&mut self) -> bool {
do self.next.with_mut_ref |pone| { pone.optimistic_check() }
}
}
-impl<'self, T> Select for &'self Port<T> { }
+impl<'self, T: Send> Select for &'self Port<T> { }
-impl<T> SelectInner for Port<T> {
+impl<T: Send> SelectInner for Port<T> {
#[inline]
fn optimistic_check(&mut self) -> bool {
(&*self).optimistic_check()
}
}
-impl<T> Select for Port<T> { }
+impl<T: Send> Select for Port<T> { }
-impl<'self, T> SelectPortInner<T> for &'self Port<T> {
+impl<'self, T: Send> SelectPortInner<T> for &'self Port<T> {
fn recv_ready(self) -> Option<T> {
match self.next.take().recv_ready() {
Some(StreamPayload { val, next }) => {
}
}
-impl<'self, T> SelectPort<T> for &'self Port<T> { }
+impl<'self, T: Send> SelectPort<T> for &'self Port<T> { }
pub struct SharedChan<T> {
// Just like Chan, but a shared AtomicOption instead of Cell
priv next: UnsafeArc<AtomicOption<StreamChanOne<T>>>
}
-impl<T> SharedChan<T> {
+impl<T: Send> SharedChan<T> {
pub fn new(chan: Chan<T>) -> SharedChan<T> {
let next = chan.next.take();
let next = AtomicOption::new(~next);
}
}
-impl<T> Clone for SharedChan<T> {
+impl<T: Send> Clone for SharedChan<T> {
fn clone(&self) -> SharedChan<T> {
SharedChan {
next: self.next.clone()
priv next_link: UnsafeArc<AtomicOption<PortOne<StreamPortOne<T>>>>
}
-impl<T> SharedPort<T> {
+impl<T: Send> SharedPort<T> {
pub fn new(port: Port<T>) -> SharedPort<T> {
// Put the data port into a new link pipe
let next_data_port = port.next.take();
}
}
-impl<T> Clone for SharedPort<T> {
+impl<T: Send> Clone for SharedPort<T> {
fn clone(&self) -> SharedPort<T> {
SharedPort {
next_link: self.next_link.clone()
use hashmap::HashSet;
use option::{Some, None, Option};
use vec::ImmutableVector;
-#[cfg(not(stage0))]
use rt::rtio::EventLoop;
// Need to tell the linker on OS X to not barf on undefined symbols
log_level: *mut u32
}
-#[cfg(stage0)]
-pub struct CrateMap<'self> {
- version: i32,
- entries: &'self [ModEntry<'self>],
- children: &'self [&'self CrateMap<'self>]
-}
-
-#[cfg(not(stage0))]
pub struct CrateMap<'self> {
version: i32,
entries: &'self [ModEntry<'self>],
#[cfg(not(windows))]
pub fn get_crate_map() -> Option<&'static CrateMap<'static>> {
extern {
- #[cfg(stage0)]
- #[weak_linkage]
- #[link_name = "_rust_crate_map_toplevel"]
- static CRATE_MAP: CrateMap<'static>;
-
- #[cfg(not(stage0))]
#[crate_map]
static CRATE_MAP: CrateMap<'static>;
}
use rt::io::io_error;
use rt::rtio::{IoFactory, RtioSignal, with_local_io};
+#[repr(int)]
#[deriving(Eq, IterBytes)]
pub enum Signum {
/// Equivalent to SIGBREAK, delivered when the user presses Ctrl-Break.
use option::{Option, Some, None};
use prelude::*;
use rt::task::Task;
-use rt::task::UnwindReasonLinked;
+use rt::task::UnwindMessageLinked;
use rt::task::{UnwindResult, Failure};
use task::spawn::Taskgroup;
use to_bytes::IterBytes;
}
if !success {
- result = Cell::new(Failure(UnwindReasonLinked));
+ result = Cell::new(Failure(UnwindMessageLinked));
}
}
on_exit(result.take());
/// The EventLoop and internal synchronous I/O interface.
pub mod rtio;
-/// libuv and default rtio implementation.
-#[cfg(stage0)]
-pub mod uv;
-
/// The Local trait for types that are accessible via thread-local
/// or task-local storage.
pub mod local;
}
}
-#[cfg(stage0)]
-pub fn new_event_loop() -> ~rtio::EventLoop {
- use rt::uv::uvio::UvEventLoop;
- ~UvEventLoop::new() as ~rtio::EventLoop
-}
-
-#[cfg(not(stage0))]
pub fn new_event_loop() -> ~rtio::EventLoop {
#[fixed_stack_segment]; #[allow(cstack)];
/// The task is ending successfully
Success,
- /// The Task is failing with reason `UnwindReason`
- Failure(UnwindReason),
+ /// The Task is failing with reason `UnwindMessage`
+ Failure(UnwindMessage),
}
impl UnwindResult {
/// Represents the cause of a task failure
#[deriving(ToStr)]
-pub enum UnwindReason {
- /// Failed with a string message
- UnwindReasonStr(SendStr),
+pub enum UnwindMessage {
+ // FIXME: #9913 - This variant is not neccessary once Any works properly
+ /// Failed with a static string message
+ UnwindMessageStrStatic(&'static str),
+
+ // FIXME: #9913 - This variant is not neccessary once Any works properly
+ /// Failed with a owned string message
+ UnwindMessageStrOwned(~str),
/// Failed with an `~Any`
- UnwindReasonAny(~Any),
+ UnwindMessageAny(~Any),
/// Failed because of linked failure
- UnwindReasonLinked
+ UnwindMessageLinked
}
pub struct Unwinder {
unwinding: bool,
- cause: Option<UnwindReason>
+ cause: Option<UnwindMessage>
}
impl Unwinder {
}
}
- pub fn begin_unwind(&mut self, cause: UnwindReason) -> ! {
+ pub fn begin_unwind(&mut self, cause: UnwindMessage) -> ! {
#[fixed_stack_segment]; #[inline(never)];
self.unwinding = true;
/// This is the entry point of unwinding for things like lang items and such.
/// The arguments are normally generated by the compiler, and need to
/// have static lifetimes.
-pub fn begin_unwind(msg: *c_char, file: *c_char, line: size_t) -> ! {
+pub fn begin_unwind_raw(msg: *c_char, file: *c_char, line: size_t) -> ! {
use c_str::CString;
use cast::transmute;
let msg = static_char_ptr(msg);
let file = static_char_ptr(file);
- begin_unwind_reason(UnwindReasonStr(msg.into_send_str()), file, line as uint)
+ begin_unwind(msg, file, line as uint)
}
/// This is the entry point of unwinding for fail!() and assert!().
-pub fn begin_unwind_reason(reason: UnwindReason, file: &'static str, line: uint) -> ! {
+pub fn begin_unwind<M: Any + Send>(msg: M, file: &'static str, line: uint) -> ! {
+ // Wrap the fail message in a `Any` box for uniform representation.
+ let any = ~msg as ~Any;
+
+ // FIXME: #9913 - This can be changed to be internal to begin_unwind_internal
+ // once Any works properly.
+ // As a workaround, string types need to be special cased right now
+ // because `Any` does not support dynamically querying whether the
+ // type implements a trait yet, so without requiring that every `Any`
+ // also implements `ToStr` there is no way to get a failure message
+ // out of it again during unwinding.
+ let msg = if any.is::<&'static str>() {
+ UnwindMessageStrStatic(*any.move::<&'static str>().unwrap())
+ } else if any.is::<~str>() {
+ UnwindMessageStrOwned(*any.move::<~str>().unwrap())
+ } else {
+ UnwindMessageAny(any)
+ };
+
+ begin_unwind_internal(msg, file, line)
+}
+
+fn begin_unwind_internal(msg: UnwindMessage, file: &'static str, line: uint) -> ! {
use rt::in_green_task_context;
use rt::task::Task;
use rt::local::Local;
let task: *mut Task;
{
- let msg = match reason {
- UnwindReasonStr(ref s) => s.as_slice(),
- UnwindReasonAny(_) => "~Any",
- UnwindReasonLinked => "linked failure",
+ let msg_s = match msg {
+ UnwindMessageAny(_) => "~Any",
+ UnwindMessageLinked => "linked failure",
+ UnwindMessageStrOwned(ref s) => s.as_slice(),
+ UnwindMessageStrStatic(ref s) => s.as_slice(),
};
if !in_green_task_context() {
rterrln!("failed in non-task context at '{}', {}:{}",
- msg, file, line);
+ msg_s, file, line);
intrinsics::abort();
}
// due to mismanagment of its own kill flag, so calling our own
// logger in its current state is a bit of a problem.
- rterrln!("task '{}' failed at '{}', {}:{}", n, msg, file, line);
+ rterrln!("task '{}' failed at '{}', {}:{}", n, msg_s, file, line);
if (*task).unwinder.unwinding {
rtabort!("unwinding again");
}
}
- (*task).unwinder.begin_unwind(reason);
+ (*task).unwinder.begin_unwind(msg);
}
}
#[cfg(test)]
mod test {
+ use super::*;
use rt::test::*;
#[test]
a.next = Some(b);
}
}
+
+ #[test]
+ #[should_fail]
+ fn test_begin_unwind() { begin_unwind("cause", file!(), line!()) }
}
+++ /dev/null
-// Copyright 2013 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use cast::transmute;
-use cell::Cell;
-use c_str::ToCStr;
-use libc::{c_int, c_void};
-use option::{Option, Some, None};
-use ptr::null;
-use rt::uv::uvll;
-use rt::uv::uvll::UV_GETADDRINFO;
-use rt::uv::{Loop, UvError, NativeHandle};
-use rt::uv::status_to_maybe_uv_error;
-use rt::uv::net;
-use ai = rt::io::net::addrinfo;
-
-type GetAddrInfoCallback = ~fn(GetAddrInfoRequest, &net::UvAddrInfo, Option<UvError>);
-
-pub struct GetAddrInfoRequest(*uvll::uv_getaddrinfo_t);
-
-pub struct RequestData {
- priv getaddrinfo_cb: Option<GetAddrInfoCallback>,
-}
-
-impl GetAddrInfoRequest {
- pub fn new() -> GetAddrInfoRequest {
- let req = unsafe { uvll::malloc_req(UV_GETADDRINFO) };
- assert!(req.is_not_null());
- let mut req: GetAddrInfoRequest = NativeHandle::from_native_handle(req);
- req.install_req_data();
- return req;
- }
-
- pub fn getaddrinfo(&mut self, loop_: &Loop, node: Option<&str>,
- service: Option<&str>, hints: Option<ai::Hint>,
- cb: GetAddrInfoCallback) {
-
- assert!(node.is_some() || service.is_some());
-
- let (c_node, c_node_ptr) = match node {
- Some(n) => {
- let c_node = n.to_c_str();
- let c_node_ptr = c_node.with_ref(|r| r);
- (Some(c_node), c_node_ptr)
- }
- None => (None, null())
- };
-
- let (c_service, c_service_ptr) = match service {
- Some(s) => {
- let c_service = s.to_c_str();
- let c_service_ptr = c_service.with_ref(|r| r);
- (Some(c_service), c_service_ptr)
- }
- None => (None, null())
- };
-
- let cb = Cell::new(cb);
- let wrapper_cb: GetAddrInfoCallback = |req, addrinfo, err| {
- // Capture some heap values that need to stay alive for the
- // getaddrinfo call
- let _ = &c_node;
- let _ = &c_service;
-
- let cb = cb.take();
- cb(req, addrinfo, err)
- };
-
- let hint = hints.map(|hint| {
- let mut flags = 0;
- do each_ai_flag |cval, aival| {
- if hint.flags & (aival as uint) != 0 {
- flags |= cval as i32;
- }
- }
- /* XXX: do we really want to support these?
- let socktype = match hint.socktype {
- Some(ai::Stream) => uvll::rust_SOCK_STREAM(),
- Some(ai::Datagram) => uvll::rust_SOCK_DGRAM(),
- Some(ai::Raw) => uvll::rust_SOCK_RAW(),
- None => 0,
- };
- let protocol = match hint.protocol {
- Some(ai::UDP) => uvll::rust_IPPROTO_UDP(),
- Some(ai::TCP) => uvll::rust_IPPROTO_TCP(),
- _ => 0,
- };
- */
- let socktype = 0;
- let protocol = 0;
-
- uvll::addrinfo {
- ai_flags: flags,
- ai_family: hint.family as c_int,
- ai_socktype: socktype,
- ai_protocol: protocol,
- ai_addrlen: 0,
- ai_canonname: null(),
- ai_addr: null(),
- ai_next: null(),
- }
- });
- let hint_ptr = hint.as_ref().map_default(null(), |x| x as *uvll::addrinfo);
-
- self.get_req_data().getaddrinfo_cb = Some(wrapper_cb);
-
- unsafe {
- assert!(0 == uvll::getaddrinfo(loop_.native_handle(),
- self.native_handle(),
- getaddrinfo_cb,
- c_node_ptr,
- c_service_ptr,
- hint_ptr));
- }
-
- extern "C" fn getaddrinfo_cb(req: *uvll::uv_getaddrinfo_t,
- status: c_int,
- res: *uvll::addrinfo) {
- let mut req: GetAddrInfoRequest = NativeHandle::from_native_handle(req);
- let err = status_to_maybe_uv_error(status);
- let addrinfo = net::UvAddrInfo(res);
- let data = req.get_req_data();
- (*data.getaddrinfo_cb.get_ref())(req, &addrinfo, err);
- unsafe {
- uvll::freeaddrinfo(res);
- }
- }
- }
-
- fn get_loop(&self) -> Loop {
- unsafe {
- Loop {
- handle: uvll::get_loop_from_fs_req(self.native_handle())
- }
- }
- }
-
- fn install_req_data(&mut self) {
- let req = self.native_handle() as *uvll::uv_getaddrinfo_t;
- let data = ~RequestData {
- getaddrinfo_cb: None
- };
- unsafe {
- let data = transmute::<~RequestData, *c_void>(data);
- uvll::set_data_for_req(req, data);
- }
- }
-
- fn get_req_data<'r>(&'r mut self) -> &'r mut RequestData {
- unsafe {
- let data = uvll::get_data_for_req(self.native_handle());
- let data = transmute::<&*c_void, &mut ~RequestData>(&data);
- return &mut **data;
- }
- }
-
- fn delete(self) {
- unsafe {
- let data = uvll::get_data_for_req(self.native_handle());
- let _data = transmute::<*c_void, ~RequestData>(data);
- uvll::set_data_for_req(self.native_handle(), null::<()>());
- uvll::free_req(self.native_handle());
- }
- }
-}
-
-fn each_ai_flag(_f: &fn(c_int, ai::Flag)) {
- /* XXX: do we really want to support these?
- unsafe {
- f(uvll::rust_AI_ADDRCONFIG(), ai::AddrConfig);
- f(uvll::rust_AI_ALL(), ai::All);
- f(uvll::rust_AI_CANONNAME(), ai::CanonName);
- f(uvll::rust_AI_NUMERICHOST(), ai::NumericHost);
- f(uvll::rust_AI_NUMERICSERV(), ai::NumericServ);
- f(uvll::rust_AI_PASSIVE(), ai::Passive);
- f(uvll::rust_AI_V4MAPPED(), ai::V4Mapped);
- }
- */
-}
-
-// Traverse the addrinfo linked list, producing a vector of Rust socket addresses
-pub fn accum_addrinfo(addr: &net::UvAddrInfo) -> ~[ai::Info] {
- unsafe {
- let &net::UvAddrInfo(addr) = addr;
- let mut addr = addr;
-
- let mut addrs = ~[];
- loop {
- let uvaddr = net::sockaddr_to_UvSocketAddr((*addr).ai_addr);
- let rustaddr = net::uv_socket_addr_to_socket_addr(uvaddr);
-
- let mut flags = 0;
- do each_ai_flag |cval, aival| {
- if (*addr).ai_flags & cval != 0 {
- flags |= aival as uint;
- }
- }
-
- /* XXX: do we really want to support these
- let protocol = match (*addr).ai_protocol {
- p if p == uvll::rust_IPPROTO_UDP() => Some(ai::UDP),
- p if p == uvll::rust_IPPROTO_TCP() => Some(ai::TCP),
- _ => None,
- };
- let socktype = match (*addr).ai_socktype {
- p if p == uvll::rust_SOCK_STREAM() => Some(ai::Stream),
- p if p == uvll::rust_SOCK_DGRAM() => Some(ai::Datagram),
- p if p == uvll::rust_SOCK_RAW() => Some(ai::Raw),
- _ => None,
- };
- */
- let protocol = None;
- let socktype = None;
-
- addrs.push(ai::Info {
- address: rustaddr,
- family: (*addr).ai_family as uint,
- socktype: socktype,
- protocol: protocol,
- flags: flags,
- });
- if (*addr).ai_next.is_not_null() {
- addr = (*addr).ai_next;
- } else {
- break;
- }
- }
-
- return addrs;
- }
-}
-
-impl NativeHandle<*uvll::uv_getaddrinfo_t> for GetAddrInfoRequest {
- fn from_native_handle(handle: *uvll::uv_getaddrinfo_t) -> GetAddrInfoRequest {
- GetAddrInfoRequest(handle)
- }
- fn native_handle(&self) -> *uvll::uv_getaddrinfo_t {
- match self { &GetAddrInfoRequest(ptr) => ptr }
- }
-}
-
-#[cfg(test)]
-mod test {
- use option::{Some, None};
- use rt::uv::Loop;
- use rt::io::net::ip::{SocketAddr, Ipv4Addr};
- use super::*;
-
- #[test]
- fn getaddrinfo_test() {
- let mut loop_ = Loop::new();
- let mut req = GetAddrInfoRequest::new();
- do req.getaddrinfo(&loop_, Some("localhost"), None, None) |_, addrinfo, _| {
- let sockaddrs = accum_addrinfo(addrinfo);
- let mut found_local = false;
- let local_addr = &SocketAddr {
- ip: Ipv4Addr(127, 0, 0, 1),
- port: 0
- };
- for addr in sockaddrs.iter() {
- found_local = found_local || addr.address == *local_addr;
- }
- assert!(found_local);
- }
- loop_.run();
- loop_.close();
- req.delete();
- }
-}
+++ /dev/null
-// Copyright 2013 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use libc::c_int;
-use option::Some;
-use rt::uv::uvll;
-use rt::uv::uvll::UV_ASYNC;
-use rt::uv::{Watcher, Loop, NativeHandle, AsyncCallback};
-use rt::uv::WatcherInterop;
-use rt::uv::status_to_maybe_uv_error;
-
-pub struct AsyncWatcher(*uvll::uv_async_t);
-impl Watcher for AsyncWatcher { }
-
-impl AsyncWatcher {
- pub fn new(loop_: &mut Loop, cb: AsyncCallback) -> AsyncWatcher {
- unsafe {
- let handle = uvll::malloc_handle(UV_ASYNC);
- assert!(handle.is_not_null());
- let mut watcher: AsyncWatcher = NativeHandle::from_native_handle(handle);
- watcher.install_watcher_data();
- let data = watcher.get_watcher_data();
- data.async_cb = Some(cb);
- assert_eq!(0, uvll::async_init(loop_.native_handle(), handle, async_cb));
- return watcher;
- }
-
- extern fn async_cb(handle: *uvll::uv_async_t, status: c_int) {
- let mut watcher: AsyncWatcher = NativeHandle::from_native_handle(handle);
- let status = status_to_maybe_uv_error(status);
- let data = watcher.get_watcher_data();
- let cb = data.async_cb.get_ref();
- (*cb)(watcher, status);
- }
- }
-
- pub fn send(&mut self) {
- unsafe {
- let handle = self.native_handle();
- uvll::async_send(handle);
- }
- }
-}
-
-impl NativeHandle<*uvll::uv_async_t> for AsyncWatcher {
- fn from_native_handle(handle: *uvll::uv_async_t) -> AsyncWatcher {
- AsyncWatcher(handle)
- }
- fn native_handle(&self) -> *uvll::uv_async_t {
- match self { &AsyncWatcher(ptr) => ptr }
- }
-}
-
-#[cfg(test)]
-mod test {
-
- use super::*;
- use rt::uv::Loop;
- use unstable::run_in_bare_thread;
- use rt::thread::Thread;
- use cell::Cell;
-
- #[test]
- fn smoke_test() {
- do run_in_bare_thread {
- let mut loop_ = Loop::new();
- let watcher = AsyncWatcher::new(&mut loop_, |w, _| w.close(||()) );
- let watcher_cell = Cell::new(watcher);
- let thread = do Thread::start {
- let mut watcher = watcher_cell.take();
- watcher.send();
- };
- loop_.run();
- loop_.close();
- thread.join();
- }
- }
-}
+++ /dev/null
-// Copyright 2013 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use prelude::*;
-use ptr::null;
-use c_str;
-use c_str::CString;
-use libc::c_void;
-use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf,
- status_to_maybe_uv_error, UvError};
-use rt::uv::uvll;
-use rt::uv::uvll::*;
-use cast::transmute;
-use libc;
-use libc::{c_int};
-use option::{None, Some, Option};
-
-pub struct FsRequest(*uvll::uv_fs_t);
-impl Request for FsRequest {}
-
-pub struct RequestData {
- priv complete_cb: Option<FsCallback>
-}
-
-impl FsRequest {
- pub fn new() -> FsRequest {
- let fs_req = unsafe { malloc_req(UV_FS) };
- assert!(fs_req.is_not_null());
- let fs_req: FsRequest = NativeHandle::from_native_handle(fs_req);
- fs_req
- }
-
- pub fn open(self, loop_: &Loop, path: &CString, flags: int, mode: int,
- cb: FsCallback) {
- let complete_cb_ptr = {
- let mut me = self;
- me.req_boilerplate(Some(cb))
- };
- let ret = path.with_ref(|p| unsafe {
- uvll::fs_open(loop_.native_handle(),
- self.native_handle(), p, flags, mode, complete_cb_ptr)
- });
- assert_eq!(ret, 0);
- }
-
- pub fn open_sync(self, loop_: &Loop, path: &CString,
- flags: int, mode: int) -> Result<c_int, UvError> {
- let complete_cb_ptr = {
- let mut me = self;
- me.req_boilerplate(None)
- };
- let result = path.with_ref(|p| unsafe {
- uvll::fs_open(loop_.native_handle(),
- self.native_handle(), p, flags, mode, complete_cb_ptr)
- });
- self.sync_cleanup(result)
- }
-
- pub fn unlink(self, loop_: &Loop, path: &CString, cb: FsCallback) {
- let complete_cb_ptr = {
- let mut me = self;
- me.req_boilerplate(Some(cb))
- };
- let ret = path.with_ref(|p| unsafe {
- uvll::fs_unlink(loop_.native_handle(),
- self.native_handle(), p, complete_cb_ptr)
- });
- assert_eq!(ret, 0);
- }
-
- pub fn unlink_sync(self, loop_: &Loop, path: &CString)
- -> Result<c_int, UvError> {
- let complete_cb_ptr = {
- let mut me = self;
- me.req_boilerplate(None)
- };
- let result = path.with_ref(|p| unsafe {
- uvll::fs_unlink(loop_.native_handle(),
- self.native_handle(), p, complete_cb_ptr)
- });
- self.sync_cleanup(result)
- }
-
- pub fn stat(self, loop_: &Loop, path: &CString, cb: FsCallback) {
- let complete_cb_ptr = {
- let mut me = self;
- me.req_boilerplate(Some(cb))
- };
- let ret = path.with_ref(|p| unsafe {
- uvll::fs_stat(loop_.native_handle(),
- self.native_handle(), p, complete_cb_ptr)
- });
- assert_eq!(ret, 0);
- }
-
- pub fn write(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64, cb: FsCallback) {
- let complete_cb_ptr = {
- let mut me = self;
- me.req_boilerplate(Some(cb))
- };
- let base_ptr = buf.base as *c_void;
- let len = buf.len as uint;
- let ret = unsafe {
- uvll::fs_write(loop_.native_handle(), self.native_handle(),
- fd, base_ptr,
- len, offset, complete_cb_ptr)
- };
- assert_eq!(ret, 0);
- }
- pub fn write_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64)
- -> Result<c_int, UvError> {
- let complete_cb_ptr = {
- let mut me = self;
- me.req_boilerplate(None)
- };
- let base_ptr = buf.base as *c_void;
- let len = buf.len as uint;
- let result = unsafe {
- uvll::fs_write(loop_.native_handle(), self.native_handle(),
- fd, base_ptr,
- len, offset, complete_cb_ptr)
- };
- self.sync_cleanup(result)
- }
-
- pub fn read(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64, cb: FsCallback) {
- let complete_cb_ptr = {
- let mut me = self;
- me.req_boilerplate(Some(cb))
- };
- let buf_ptr = buf.base as *c_void;
- let len = buf.len as uint;
- let ret = unsafe {
- uvll::fs_read(loop_.native_handle(), self.native_handle(),
- fd, buf_ptr,
- len, offset, complete_cb_ptr)
- };
- assert_eq!(ret, 0);
- }
- pub fn read_sync(self, loop_: &Loop, fd: c_int, buf: Buf, offset: i64)
- -> Result<c_int, UvError> {
- let complete_cb_ptr = {
- let mut me = self;
- me.req_boilerplate(None)
- };
- let buf_ptr = buf.base as *c_void;
- let len = buf.len as uint;
- let result = unsafe {
- uvll::fs_read(loop_.native_handle(), self.native_handle(),
- fd, buf_ptr,
- len, offset, complete_cb_ptr)
- };
- self.sync_cleanup(result)
- }
-
- pub fn close(self, loop_: &Loop, fd: c_int, cb: FsCallback) {
- let complete_cb_ptr = {
- let mut me = self;
- me.req_boilerplate(Some(cb))
- };
- let ret = unsafe {
- uvll::fs_close(loop_.native_handle(), self.native_handle(),
- fd, complete_cb_ptr)
- };
- assert_eq!(ret, 0);
- }
- pub fn close_sync(self, loop_: &Loop, fd: c_int) -> Result<c_int, UvError> {
- let complete_cb_ptr = {
- let mut me = self;
- me.req_boilerplate(None)
- };
- let result = unsafe {
- uvll::fs_close(loop_.native_handle(), self.native_handle(),
- fd, complete_cb_ptr)
- };
- self.sync_cleanup(result)
- }
-
- pub fn mkdir(self, loop_: &Loop, path: &CString, mode: int, cb: FsCallback) {
- let complete_cb_ptr = {
- let mut me = self;
- me.req_boilerplate(Some(cb))
- };
- let ret = path.with_ref(|p| unsafe {
- uvll::fs_mkdir(loop_.native_handle(),
- self.native_handle(), p, mode, complete_cb_ptr)
- });
- assert_eq!(ret, 0);
- }
-
- pub fn rmdir(self, loop_: &Loop, path: &CString, cb: FsCallback) {
- let complete_cb_ptr = {
- let mut me = self;
- me.req_boilerplate(Some(cb))
- };
- let ret = path.with_ref(|p| unsafe {
- uvll::fs_rmdir(loop_.native_handle(),
- self.native_handle(), p, complete_cb_ptr)
- });
- assert_eq!(ret, 0);
- }
-
- pub fn readdir(self, loop_: &Loop, path: &CString,
- flags: c_int, cb: FsCallback) {
- let complete_cb_ptr = {
- let mut me = self;
- me.req_boilerplate(Some(cb))
- };
- let ret = path.with_ref(|p| unsafe {
- uvll::fs_readdir(loop_.native_handle(),
- self.native_handle(), p, flags, complete_cb_ptr)
- });
- assert_eq!(ret, 0);
- }
-
- // accessors/utility funcs
- fn sync_cleanup(self, result: c_int)
- -> Result<c_int, UvError> {
- self.cleanup_and_delete();
- match status_to_maybe_uv_error(result as i32) {
- Some(err) => Err(err),
- None => Ok(result)
- }
- }
- fn req_boilerplate(&mut self, cb: Option<FsCallback>) -> *u8 {
- let result = match cb {
- Some(_) => {
- compl_cb as *u8
- },
- None => 0 as *u8
- };
- self.install_req_data(cb);
- result
- }
- pub fn install_req_data(&mut self, cb: Option<FsCallback>) {
- let fs_req = (self.native_handle()) as *uvll::uv_write_t;
- let data = ~RequestData {
- complete_cb: cb
- };
- unsafe {
- let data = transmute::<~RequestData, *c_void>(data);
- uvll::set_data_for_req(fs_req, data);
- }
- }
-
- fn get_req_data<'r>(&'r mut self) -> &'r mut RequestData {
- unsafe {
- let data = uvll::get_data_for_req((self.native_handle()));
- let data = transmute::<&*c_void, &mut ~RequestData>(&data);
- &mut **data
- }
- }
-
- pub fn get_result(&mut self) -> c_int {
- unsafe {
- uvll::get_result_from_fs_req(self.native_handle())
- }
- }
-
- pub fn get_loop(&self) -> Loop {
- unsafe { Loop{handle:uvll::get_loop_from_fs_req(self.native_handle())} }
- }
-
- pub fn get_stat(&self) -> uv_stat_t {
- let stat = uv_stat_t::new();
- unsafe { uvll::populate_stat(self.native_handle(), &stat); }
- stat
- }
-
- pub fn get_ptr(&self) -> *libc::c_void {
- unsafe {
- uvll::get_ptr_from_fs_req(self.native_handle())
- }
- }
-
- pub fn each_path(&mut self, f: &fn(&CString)) {
- let ptr = self.get_ptr();
- match self.get_result() {
- n if (n <= 0) => {}
- n => {
- let n_len = n as uint;
- // we pass in the len that uv tells us is there
- // for the entries and we don't continue past that..
- // it appears that sometimes the multistring isn't
- // correctly delimited and we stray into garbage memory?
- // in any case, passing Some(n_len) fixes it and ensures
- // good results
- unsafe {
- c_str::from_c_multistring(ptr as *libc::c_char,
- Some(n_len), f);
- }
- }
- }
- }
-
- fn cleanup_and_delete(self) {
- unsafe {
- let data = uvll::get_data_for_req(self.native_handle());
- let _data = transmute::<*c_void, ~RequestData>(data);
- uvll::set_data_for_req(self.native_handle(), null::<()>());
- uvll::fs_req_cleanup(self.native_handle());
- free_req(self.native_handle() as *c_void)
- }
- }
-}
-
-impl NativeHandle<*uvll::uv_fs_t> for FsRequest {
- fn from_native_handle(handle: *uvll:: uv_fs_t) -> FsRequest {
- FsRequest(handle)
- }
- fn native_handle(&self) -> *uvll::uv_fs_t {
- match self { &FsRequest(ptr) => ptr }
- }
-}
-
-fn sync_cleanup(result: int)
- -> Result<int, UvError> {
- match status_to_maybe_uv_error(result as i32) {
- Some(err) => Err(err),
- None => Ok(result)
- }
-}
-
-extern fn compl_cb(req: *uv_fs_t) {
- let mut req: FsRequest = NativeHandle::from_native_handle(req);
- // pull the user cb out of the req data
- let cb = {
- let data = req.get_req_data();
- assert!(data.complete_cb.is_some());
- // option dance, option dance. oooooh yeah.
- data.complete_cb.take_unwrap()
- };
- // in uv_fs_open calls, the result will be the fd in the
- // case of success, otherwise it's -1 indicating an error
- let result = req.get_result();
- let status = status_to_maybe_uv_error(result);
- // we have a req and status, call the user cb..
- // only giving the user a ref to the FsRequest, as we
- // have to clean it up, afterwards (and they aren't really
- // reusable, anyways
- cb(&mut req, status);
- // clean up the req (and its data!) after calling the user cb
- req.cleanup_and_delete();
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
- //use rt::test::*;
- use libc::{STDOUT_FILENO};
- use vec;
- use str;
- use unstable::run_in_bare_thread;
- use rt::uv::{Loop, Buf, slice_to_uv_buf};
- use libc::{O_CREAT, O_RDWR, O_RDONLY, S_IWUSR, S_IRUSR};
-
- #[test]
- fn file_test_full_simple() {
- do run_in_bare_thread {
- let mut loop_ = Loop::new();
- let create_flags = O_RDWR | O_CREAT;
- let read_flags = O_RDONLY;
- // 0644 BZZT! WRONG! 0600! See below.
- let mode = S_IWUSR |S_IRUSR;
- // these aren't defined in std::libc :(
- //map_mode(S_IRGRP) |
- //map_mode(S_IROTH);
- let path_str = "./tmp/file_full_simple.txt";
- let write_val = "hello".as_bytes().to_owned();
- let write_buf = slice_to_uv_buf(write_val);
- let write_buf_ptr: *Buf = &write_buf;
- let read_buf_len = 1028;
- let read_mem = vec::from_elem(read_buf_len, 0u8);
- let read_buf = slice_to_uv_buf(read_mem);
- let read_buf_ptr: *Buf = &read_buf;
- let open_req = FsRequest::new();
- do open_req.open(&loop_, &path_str.to_c_str(), create_flags as int,
- mode as int) |req, uverr| {
- assert!(uverr.is_none());
- let fd = req.get_result();
- let buf = unsafe { *write_buf_ptr };
- let write_req = FsRequest::new();
- do write_req.write(&req.get_loop(), fd, buf, -1) |req, uverr| {
- let close_req = FsRequest::new();
- do close_req.close(&req.get_loop(), fd) |req, _| {
- assert!(uverr.is_none());
- let loop_ = req.get_loop();
- let open_req = FsRequest::new();
- do open_req.open(&loop_, &path_str.to_c_str(),
- read_flags as int,0) |req, uverr| {
- assert!(uverr.is_none());
- let loop_ = req.get_loop();
- let fd = req.get_result();
- let read_buf = unsafe { *read_buf_ptr };
- let read_req = FsRequest::new();
- do read_req.read(&loop_, fd, read_buf, 0) |req, uverr| {
- assert!(uverr.is_none());
- let loop_ = req.get_loop();
- // we know nread >=0 because uverr is none..
- let nread = req.get_result() as uint;
- // nread == 0 would be EOF
- if nread > 0 {
- let read_str = unsafe {
- let read_buf = *read_buf_ptr;
- str::from_utf8(
- vec::from_buf(
- read_buf.base, nread))
- };
- assert!(read_str == ~"hello");
- let close_req = FsRequest::new();
- do close_req.close(&loop_, fd) |req,uverr| {
- assert!(uverr.is_none());
- let loop_ = &req.get_loop();
- let unlink_req = FsRequest::new();
- do unlink_req.unlink(loop_,
- &path_str.to_c_str())
- |_,uverr| {
- assert!(uverr.is_none());
- };
- };
- };
- };
- };
- };
- };
- };
- loop_.run();
- loop_.close();
- }
- }
-
- #[test]
- fn file_test_full_simple_sync() {
- do run_in_bare_thread {
- // setup
- let mut loop_ = Loop::new();
- let create_flags = O_RDWR |
- O_CREAT;
- let read_flags = O_RDONLY;
- // 0644
- let mode = S_IWUSR |
- S_IRUSR;
- //S_IRGRP |
- //S_IROTH;
- let path_str = "./tmp/file_full_simple_sync.txt";
- let write_val = "hello".as_bytes().to_owned();
- let write_buf = slice_to_uv_buf(write_val);
- // open/create
- let open_req = FsRequest::new();
- let result = open_req.open_sync(&loop_, &path_str.to_c_str(),
- create_flags as int, mode as int);
- assert!(result.is_ok());
- let fd = result.unwrap();
- // write
- let write_req = FsRequest::new();
- let result = write_req.write_sync(&loop_, fd, write_buf, -1);
- assert!(result.is_ok());
- // close
- let close_req = FsRequest::new();
- let result = close_req.close_sync(&loop_, fd);
- assert!(result.is_ok());
- // re-open
- let open_req = FsRequest::new();
- let result = open_req.open_sync(&loop_, &path_str.to_c_str(),
- read_flags as int,0);
- assert!(result.is_ok());
- let len = 1028;
- let fd = result.unwrap();
- // read
- let read_mem: ~[u8] = vec::from_elem(len, 0u8);
- let buf = slice_to_uv_buf(read_mem);
- let read_req = FsRequest::new();
- let result = read_req.read_sync(&loop_, fd, buf, 0);
- assert!(result.is_ok());
- let nread = result.unwrap();
- // nread == 0 would be EOF.. we know it's >= zero because otherwise
- // the above assert would fail
- if nread > 0 {
- let read_str = str::from_utf8(
- read_mem.slice(0, nread as uint));
- assert!(read_str == ~"hello");
- // close
- let close_req = FsRequest::new();
- let result = close_req.close_sync(&loop_, fd);
- assert!(result.is_ok());
- // unlink
- let unlink_req = FsRequest::new();
- let result = unlink_req.unlink_sync(&loop_, &path_str.to_c_str());
- assert!(result.is_ok());
- } else { fail!("nread was 0.. wudn't expectin' that."); }
- loop_.close();
- }
- }
-
- fn naive_print(loop_: &Loop, input: &str) {
- let write_val = input.as_bytes();
- let write_buf = slice_to_uv_buf(write_val);
- let write_req = FsRequest::new();
- write_req.write_sync(loop_, STDOUT_FILENO, write_buf, -1);
- }
-
- #[test]
- fn file_test_write_to_stdout() {
- do run_in_bare_thread {
- let mut loop_ = Loop::new();
- naive_print(&loop_, "zanzibar!\n");
- loop_.run();
- loop_.close();
- };
- }
- #[test]
- fn file_test_stat_simple() {
- do run_in_bare_thread {
- let mut loop_ = Loop::new();
- let path = "./tmp/file_test_stat_simple.txt";
- let create_flags = O_RDWR |
- O_CREAT;
- let mode = S_IWUSR |
- S_IRUSR;
- let write_val = "hello".as_bytes().to_owned();
- let write_buf = slice_to_uv_buf(write_val);
- let write_buf_ptr: *Buf = &write_buf;
- let open_req = FsRequest::new();
- do open_req.open(&loop_, &path.to_c_str(), create_flags as int,
- mode as int) |req, uverr| {
- assert!(uverr.is_none());
- let fd = req.get_result();
- let buf = unsafe { *write_buf_ptr };
- let write_req = FsRequest::new();
- do write_req.write(&req.get_loop(), fd, buf, 0) |req, uverr| {
- assert!(uverr.is_none());
- let loop_ = req.get_loop();
- let stat_req = FsRequest::new();
- do stat_req.stat(&loop_, &path.to_c_str()) |req, uverr| {
- assert!(uverr.is_none());
- let loop_ = req.get_loop();
- let stat = req.get_stat();
- let sz: uint = stat.st_size as uint;
- assert!(sz > 0);
- let close_req = FsRequest::new();
- do close_req.close(&loop_, fd) |req, uverr| {
- assert!(uverr.is_none());
- let loop_ = req.get_loop();
- let unlink_req = FsRequest::new();
- do unlink_req.unlink(&loop_,
- &path.to_c_str()) |req,uverr| {
- assert!(uverr.is_none());
- let loop_ = req.get_loop();
- let stat_req = FsRequest::new();
- do stat_req.stat(&loop_,
- &path.to_c_str()) |_, uverr| {
- // should cause an error because the
- // file doesn't exist anymore
- assert!(uverr.is_some());
- };
- };
- };
- };
- };
- };
- loop_.run();
- loop_.close();
- }
- }
-
- #[test]
- fn file_test_mk_rm_dir() {
- do run_in_bare_thread {
- let mut loop_ = Loop::new();
- let path = "./tmp/mk_rm_dir";
- let mode = S_IWUSR |
- S_IRUSR;
- let mkdir_req = FsRequest::new();
- do mkdir_req.mkdir(&loop_, &path.to_c_str(),
- mode as int) |req,uverr| {
- assert!(uverr.is_none());
- let loop_ = req.get_loop();
- let stat_req = FsRequest::new();
- do stat_req.stat(&loop_, &path.to_c_str()) |req, uverr| {
- assert!(uverr.is_none());
- let loop_ = req.get_loop();
- let stat = req.get_stat();
- naive_print(&loop_, format!("{:?}", stat));
- assert!(stat.is_dir());
- let rmdir_req = FsRequest::new();
- do rmdir_req.rmdir(&loop_, &path.to_c_str()) |req,uverr| {
- assert!(uverr.is_none());
- let loop_ = req.get_loop();
- let stat_req = FsRequest::new();
- do stat_req.stat(&loop_, &path.to_c_str()) |_req, uverr| {
- assert!(uverr.is_some());
- }
- }
- }
- }
- loop_.run();
- loop_.close();
- }
- }
- #[test]
- fn file_test_mkdir_chokes_on_double_create() {
- do run_in_bare_thread {
- let mut loop_ = Loop::new();
- let path = "./tmp/double_create_dir";
- let mode = S_IWUSR |
- S_IRUSR;
- let mkdir_req = FsRequest::new();
- do mkdir_req.mkdir(&loop_, &path.to_c_str(), mode as int) |req,uverr| {
- assert!(uverr.is_none());
- let loop_ = req.get_loop();
- let mkdir_req = FsRequest::new();
- do mkdir_req.mkdir(&loop_, &path.to_c_str(),
- mode as int) |req,uverr| {
- assert!(uverr.is_some());
- let loop_ = req.get_loop();
- let _stat = req.get_stat();
- let rmdir_req = FsRequest::new();
- do rmdir_req.rmdir(&loop_, &path.to_c_str()) |req,uverr| {
- assert!(uverr.is_none());
- let _loop = req.get_loop();
- }
- }
- }
- loop_.run();
- loop_.close();
- }
- }
- #[test]
- fn file_test_rmdir_chokes_on_nonexistant_path() {
- do run_in_bare_thread {
- let mut loop_ = Loop::new();
- let path = "./tmp/never_existed_dir";
- let rmdir_req = FsRequest::new();
- do rmdir_req.rmdir(&loop_, &path.to_c_str()) |_req, uverr| {
- assert!(uverr.is_some());
- }
- loop_.run();
- loop_.close();
- }
- }
-}
+++ /dev/null
-// Copyright 2013 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use libc::c_int;
-use option::Some;
-use rt::uv::uvll;
-use rt::uv::{Watcher, Loop, NativeHandle, IdleCallback};
-use rt::uv::status_to_maybe_uv_error;
-
-pub struct IdleWatcher(*uvll::uv_idle_t);
-impl Watcher for IdleWatcher { }
-
-impl IdleWatcher {
- pub fn new(loop_: &mut Loop) -> IdleWatcher {
- unsafe {
- let handle = uvll::malloc_handle(uvll::UV_IDLE);
- assert!(handle.is_not_null());
- assert_eq!(uvll::idle_init(loop_.native_handle(), handle), 0);
- let mut watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
- watcher.install_watcher_data();
- return watcher
- }
- }
-
- pub fn start(&mut self, cb: IdleCallback) {
- {
- let data = self.get_watcher_data();
- data.idle_cb = Some(cb);
- }
-
- unsafe {
- assert_eq!(uvll::idle_start(self.native_handle(), idle_cb), 0)
- }
- }
-
- pub fn restart(&mut self) {
- unsafe {
- assert!(self.get_watcher_data().idle_cb.is_some());
- assert_eq!(uvll::idle_start(self.native_handle(), idle_cb), 0)
- }
- }
-
- pub fn stop(&mut self) {
- // NB: Not resetting the Rust idle_cb to None here because `stop` is
- // likely called from *within* the idle callback, causing a use after
- // free
-
- unsafe {
- assert_eq!(uvll::idle_stop(self.native_handle()), 0);
- }
- }
-}
-
-impl NativeHandle<*uvll::uv_idle_t> for IdleWatcher {
- fn from_native_handle(handle: *uvll::uv_idle_t) -> IdleWatcher {
- IdleWatcher(handle)
- }
- fn native_handle(&self) -> *uvll::uv_idle_t {
- match self { &IdleWatcher(ptr) => ptr }
- }
-}
-
-extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) {
- let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
- let data = idle_watcher.get_watcher_data();
- let cb: &IdleCallback = data.idle_cb.get_ref();
- let status = status_to_maybe_uv_error(status);
- (*cb)(idle_watcher, status);
-}
-
-#[cfg(test)]
-mod test {
-
- use rt::uv::Loop;
- use super::*;
- use unstable::run_in_bare_thread;
-
- #[test]
- #[ignore(reason = "valgrind - loop destroyed before watcher?")]
- fn idle_new_then_close() {
- do run_in_bare_thread {
- let mut loop_ = Loop::new();
- let idle_watcher = { IdleWatcher::new(&mut loop_) };
- idle_watcher.close(||());
- }
- }
-
- #[test]
- fn idle_smoke_test() {
- do run_in_bare_thread {
- let mut loop_ = Loop::new();
- let mut idle_watcher = { IdleWatcher::new(&mut loop_) };
- let mut count = 10;
- let count_ptr: *mut int = &mut count;
- do idle_watcher.start |idle_watcher, status| {
- let mut idle_watcher = idle_watcher;
- assert!(status.is_none());
- if unsafe { *count_ptr == 10 } {
- idle_watcher.stop();
- idle_watcher.close(||());
- } else {
- unsafe { *count_ptr = *count_ptr + 1; }
- }
- }
- loop_.run();
- loop_.close();
- assert_eq!(count, 10);
- }
- }
-
- #[test]
- fn idle_start_stop_start() {
- do run_in_bare_thread {
- let mut loop_ = Loop::new();
- let mut idle_watcher = { IdleWatcher::new(&mut loop_) };
- do idle_watcher.start |idle_watcher, status| {
- let mut idle_watcher = idle_watcher;
- assert!(status.is_none());
- idle_watcher.stop();
- do idle_watcher.start |idle_watcher, status| {
- assert!(status.is_none());
- let mut idle_watcher = idle_watcher;
- idle_watcher.stop();
- idle_watcher.close(||());
- }
- }
- loop_.run();
- loop_.close();
- }
- }
-}
+++ /dev/null
-// Copyright 2013 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
-
-Bindings to libuv, along with the default implementation of `std::rt::rtio`.
-
-UV types consist of the event loop (Loop), Watchers, Requests and
-Callbacks.
-
-Watchers and Requests encapsulate pointers to uv *handles*, which have
-subtyping relationships with each other. This subtyping is reflected
-in the bindings with explicit or implicit coercions. For example, an
-upcast from TcpWatcher to StreamWatcher is done with
-`tcp_watcher.as_stream()`. In other cases a callback on a specific
-type of watcher will be passed a watcher of a supertype.
-
-Currently all use of Request types (connect/write requests) are
-encapsulated in the bindings and don't need to be dealt with by the
-caller.
-
-# Safety note
-
-Due to the complex lifecycle of uv handles, as well as compiler bugs,
-this module is not memory safe and requires explicit memory management,
-via `close` and `delete` methods.
-
-*/
-
-use container::Container;
-use option::*;
-use str::raw::from_c_str;
-use to_str::ToStr;
-use ptr::RawPtr;
-use vec;
-use vec::ImmutableVector;
-use ptr;
-use str;
-use libc::{c_void, c_int, size_t, malloc, free};
-use cast::transmute;
-use ptr::null;
-use unstable::finally::Finally;
-use rt::io::net::ip::SocketAddr;
-use rt::io::signal::Signum;
-
-use rt::io::IoError;
-
-//#[cfg(test)] use unstable::run_in_bare_thread;
-
-pub use self::file::{FsRequest};
-pub use self::net::{StreamWatcher, TcpWatcher, UdpWatcher};
-pub use self::idle::IdleWatcher;
-pub use self::timer::TimerWatcher;
-pub use self::async::AsyncWatcher;
-pub use self::process::Process;
-pub use self::pipe::Pipe;
-pub use self::signal::SignalWatcher;
-
-/// The implementation of `rtio` for libuv
-pub mod uvio;
-
-/// C bindings to libuv
-pub mod uvll;
-
-pub mod file;
-pub mod net;
-pub mod idle;
-pub mod timer;
-pub mod async;
-pub mod addrinfo;
-pub mod process;
-pub mod pipe;
-pub mod tty;
-pub mod signal;
-
-/// XXX: Loop(*handle) is buggy with destructors. Normal structs
-/// with dtors may not be destructured, but tuple structs can,
-/// but the results are not correct.
-pub struct Loop {
- priv handle: *uvll::uv_loop_t
-}
-
-pub struct Handle(*uvll::uv_handle_t);
-
-impl Watcher for Handle {}
-impl NativeHandle<*uvll::uv_handle_t> for Handle {
- fn from_native_handle(h: *uvll::uv_handle_t) -> Handle { Handle(h) }
- fn native_handle(&self) -> *uvll::uv_handle_t { **self }
-}
-
-/// The trait implemented by uv 'watchers' (handles). Watchers are
-/// non-owning wrappers around the uv handles and are not completely
-/// safe - there may be multiple instances for a single underlying
-/// handle. Watchers are generally created, then `start`ed, `stop`ed
-/// and `close`ed, but due to their complex life cycle may not be
-/// entirely memory safe if used in unanticipated patterns.
-pub trait Watcher { }
-
-pub trait Request { }
-
-/// A type that wraps a native handle
-pub trait NativeHandle<T> {
- fn from_native_handle(T) -> Self;
- fn native_handle(&self) -> T;
-}
-
-impl Loop {
- pub fn new() -> Loop {
- let handle = unsafe { uvll::loop_new() };
- assert!(handle.is_not_null());
- NativeHandle::from_native_handle(handle)
- }
-
- pub fn run(&mut self) {
- unsafe { uvll::run(self.native_handle()) };
- }
-
- pub fn close(&mut self) {
- unsafe { uvll::loop_delete(self.native_handle()) };
- }
-}
-
-impl NativeHandle<*uvll::uv_loop_t> for Loop {
- fn from_native_handle(handle: *uvll::uv_loop_t) -> Loop {
- Loop { handle: handle }
- }
- fn native_handle(&self) -> *uvll::uv_loop_t {
- self.handle
- }
-}
-
-// XXX: The uv alloc callback also has a *uv_handle_t arg
-pub type AllocCallback = ~fn(uint) -> Buf;
-pub type ReadCallback = ~fn(StreamWatcher, int, Buf, Option<UvError>);
-pub type NullCallback = ~fn();
-pub type IdleCallback = ~fn(IdleWatcher, Option<UvError>);
-pub type ConnectionCallback = ~fn(StreamWatcher, Option<UvError>);
-pub type FsCallback = ~fn(&mut FsRequest, Option<UvError>);
-// first int is exit_status, second is term_signal
-pub type ExitCallback = ~fn(Process, int, int, Option<UvError>);
-pub type TimerCallback = ~fn(TimerWatcher, Option<UvError>);
-pub type AsyncCallback = ~fn(AsyncWatcher, Option<UvError>);
-pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, SocketAddr, uint, Option<UvError>);
-pub type UdpSendCallback = ~fn(UdpWatcher, Option<UvError>);
-pub type SignalCallback = ~fn(SignalWatcher, Signum);
-
-
-/// Callbacks used by StreamWatchers, set as custom data on the foreign handle.
-/// XXX: Would be better not to have all watchers allocate room for all callback types.
-struct WatcherData {
- read_cb: Option<ReadCallback>,
- write_cb: Option<ConnectionCallback>,
- connect_cb: Option<ConnectionCallback>,
- close_cb: Option<NullCallback>,
- alloc_cb: Option<AllocCallback>,
- idle_cb: Option<IdleCallback>,
- timer_cb: Option<TimerCallback>,
- async_cb: Option<AsyncCallback>,
- udp_recv_cb: Option<UdpReceiveCallback>,
- udp_send_cb: Option<UdpSendCallback>,
- exit_cb: Option<ExitCallback>,
- signal_cb: Option<SignalCallback>,
-}
-
-pub trait WatcherInterop {
- fn event_loop(&self) -> Loop;
- fn install_watcher_data(&mut self);
- fn get_watcher_data<'r>(&'r mut self) -> &'r mut WatcherData;
- fn drop_watcher_data(&mut self);
- fn close(self, cb: NullCallback);
- fn close_async(self);
-}
-
-impl<H, W: Watcher + NativeHandle<*H>> WatcherInterop for W {
- /// Get the uv event loop from a Watcher
- fn event_loop(&self) -> Loop {
- unsafe {
- let handle = self.native_handle();
- let loop_ = uvll::get_loop_for_uv_handle(handle);
- NativeHandle::from_native_handle(loop_)
- }
- }
-
- fn install_watcher_data(&mut self) {
- unsafe {
- let data = ~WatcherData {
- read_cb: None,
- write_cb: None,
- connect_cb: None,
- close_cb: None,
- alloc_cb: None,
- idle_cb: None,
- timer_cb: None,
- async_cb: None,
- udp_recv_cb: None,
- udp_send_cb: None,
- exit_cb: None,
- signal_cb: None,
- };
- let data = transmute::<~WatcherData, *c_void>(data);
- uvll::set_data_for_uv_handle(self.native_handle(), data);
- }
- }
-
- fn get_watcher_data<'r>(&'r mut self) -> &'r mut WatcherData {
- unsafe {
- let data = uvll::get_data_for_uv_handle(self.native_handle());
- let data = transmute::<&*c_void, &mut ~WatcherData>(&data);
- return &mut **data;
- }
- }
-
- fn drop_watcher_data(&mut self) {
- unsafe {
- let data = uvll::get_data_for_uv_handle(self.native_handle());
- let _data = transmute::<*c_void, ~WatcherData>(data);
- uvll::set_data_for_uv_handle(self.native_handle(), null::<()>());
- }
- }
-
- fn close(mut self, cb: NullCallback) {
- {
- let data = self.get_watcher_data();
- assert!(data.close_cb.is_none());
- data.close_cb = Some(cb);
- }
-
- unsafe { uvll::close(self.native_handle(), close_cb); }
-
- extern fn close_cb(handle: *uvll::uv_handle_t) {
- let mut h: Handle = NativeHandle::from_native_handle(handle);
- h.get_watcher_data().close_cb.take_unwrap()();
- h.drop_watcher_data();
- unsafe { uvll::free_handle(handle as *c_void) }
- }
- }
-
- fn close_async(self) {
- unsafe { uvll::close(self.native_handle(), close_cb); }
-
- extern fn close_cb(handle: *uvll::uv_handle_t) {
- let mut h: Handle = NativeHandle::from_native_handle(handle);
- h.drop_watcher_data();
- unsafe { uvll::free_handle(handle as *c_void) }
- }
- }
-}
-
-// XXX: Need to define the error constants like EOF so they can be
-// compared to the UvError type
-
-pub struct UvError(c_int);
-
-impl UvError {
- pub fn name(&self) -> ~str {
- unsafe {
- let inner = match self { &UvError(a) => a };
- let name_str = uvll::err_name(inner);
- assert!(name_str.is_not_null());
- from_c_str(name_str)
- }
- }
-
- pub fn desc(&self) -> ~str {
- unsafe {
- let inner = match self { &UvError(a) => a };
- let desc_str = uvll::strerror(inner);
- assert!(desc_str.is_not_null());
- from_c_str(desc_str)
- }
- }
-
- pub fn is_eof(&self) -> bool {
- **self == uvll::EOF
- }
-}
-
-impl ToStr for UvError {
- fn to_str(&self) -> ~str {
- format!("{}: {}", self.name(), self.desc())
- }
-}
-
-#[test]
-fn error_smoke_test() {
- let err: UvError = UvError(uvll::EOF);
- assert_eq!(err.to_str(), ~"EOF: end of file");
-}
-
-pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
- unsafe {
- // Importing error constants
- use rt::uv::uvll::*;
- use rt::io::*;
-
- // uv error descriptions are static
- let c_desc = uvll::strerror(*uverr);
- let desc = str::raw::c_str_to_static_slice(c_desc);
-
- let kind = match *uverr {
- UNKNOWN => OtherIoError,
- OK => OtherIoError,
- EOF => EndOfFile,
- EACCES => PermissionDenied,
- ECONNREFUSED => ConnectionRefused,
- ECONNRESET => ConnectionReset,
- ENOTCONN => NotConnected,
- EPIPE => BrokenPipe,
- ECONNABORTED => ConnectionAborted,
- err => {
- rtdebug!("uverr.code {}", err as int);
- // XXX: Need to map remaining uv error types
- OtherIoError
- }
- };
-
- IoError {
- kind: kind,
- desc: desc,
- detail: None
- }
- }
-}
-
-/// Given a uv handle, convert a callback status to a UvError
-pub fn status_to_maybe_uv_error(status: c_int) -> Option<UvError>
-{
- if status >= 0 {
- None
- } else {
- Some(UvError(status))
- }
-}
-
-/// The uv buffer type
-pub type Buf = uvll::uv_buf_t;
-
-pub fn empty_buf() -> Buf {
- uvll::uv_buf_t {
- base: null(),
- len: 0,
- }
-}
-
-/// Borrow a slice to a Buf
-pub fn slice_to_uv_buf(v: &[u8]) -> Buf {
- let data = vec::raw::to_ptr(v);
- unsafe { uvll::buf_init(data, v.len()) }
-}
-
-// XXX: Do these conversions without copying
-
-/// Transmute an owned vector to a Buf
-pub fn vec_to_uv_buf(v: ~[u8]) -> Buf {
- #[fixed_stack_segment]; #[inline(never)];
-
- unsafe {
- let data = malloc(v.len() as size_t) as *u8;
- assert!(data.is_not_null());
- do v.as_imm_buf |b, l| {
- let data = data as *mut u8;
- ptr::copy_memory(data, b, l)
- }
- uvll::buf_init(data, v.len())
- }
-}
-
-/// Transmute a Buf that was once a ~[u8] back to ~[u8]
-pub fn vec_from_uv_buf(buf: Buf) -> Option<~[u8]> {
- #[fixed_stack_segment]; #[inline(never)];
-
- if !(buf.len == 0 && buf.base.is_null()) {
- let v = unsafe { vec::from_buf(buf.base, buf.len as uint) };
- unsafe { free(buf.base as *c_void) };
- return Some(v);
- } else {
- // No buffer
- rtdebug!("No buffer!");
- return None;
- }
-}
-/*
-#[test]
-fn test_slice_to_uv_buf() {
- let slice = [0, .. 20];
- let buf = slice_to_uv_buf(slice);
-
- assert!(buf.len == 20);
-
- unsafe {
- let base = transmute::<*u8, *mut u8>(buf.base);
- (*base) = 1;
- (*ptr::mut_offset(base, 1)) = 2;
- }
-
- assert!(slice[0] == 1);
- assert!(slice[1] == 2);
-}
-
-
-#[test]
-fn loop_smoke_test() {
- do run_in_bare_thread {
- let mut loop_ = Loop::new();
- loop_.run();
- loop_.close();
- }
-}
-*/
+++ /dev/null
-// Copyright 2013 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use prelude::*;
-use libc::{size_t, ssize_t, c_int, c_void, c_uint};
-use rt::uv::uvll;
-use rt::uv::uvll::*;
-use rt::uv::{AllocCallback, ConnectionCallback, ReadCallback, UdpReceiveCallback, UdpSendCallback};
-use rt::uv::{Loop, Watcher, Request, UvError, Buf, NativeHandle,
- status_to_maybe_uv_error, empty_buf};
-use rt::io::net::ip::{SocketAddr, Ipv4Addr, Ipv6Addr};
-use vec;
-use str;
-use from_str::{FromStr};
-
-pub struct UvAddrInfo(*uvll::addrinfo);
-
-pub enum UvSocketAddr {
- UvIpv4SocketAddr(*sockaddr_in),
- UvIpv6SocketAddr(*sockaddr_in6),
-}
-
-pub fn sockaddr_to_UvSocketAddr(addr: *uvll::sockaddr) -> UvSocketAddr {
- unsafe {
- assert!((is_ip4_addr(addr) || is_ip6_addr(addr)));
- assert!(!(is_ip4_addr(addr) && is_ip6_addr(addr)));
- match addr {
- _ if is_ip4_addr(addr) => UvIpv4SocketAddr(addr as *uvll::sockaddr_in),
- _ if is_ip6_addr(addr) => UvIpv6SocketAddr(addr as *uvll::sockaddr_in6),
- _ => fail!(),
- }
- }
-}
-
-fn socket_addr_as_uv_socket_addr<T>(addr: SocketAddr, f: &fn(UvSocketAddr) -> T) -> T {
- let malloc = match addr.ip {
- Ipv4Addr(*) => malloc_ip4_addr,
- Ipv6Addr(*) => malloc_ip6_addr,
- };
- let wrap = match addr.ip {
- Ipv4Addr(*) => UvIpv4SocketAddr,
- Ipv6Addr(*) => UvIpv6SocketAddr,
- };
- let free = match addr.ip {
- Ipv4Addr(*) => free_ip4_addr,
- Ipv6Addr(*) => free_ip6_addr,
- };
-
- let addr = unsafe { malloc(addr.ip.to_str(), addr.port as int) };
- do (|| {
- f(wrap(addr))
- }).finally {
- unsafe { free(addr) };
- }
-}
-
-fn uv_socket_addr_as_socket_addr<T>(addr: UvSocketAddr, f: &fn(SocketAddr) -> T) -> T {
- let ip_size = match addr {
- UvIpv4SocketAddr(*) => 4/*groups of*/ * 3/*digits separated by*/ + 3/*periods*/,
- UvIpv6SocketAddr(*) => 8/*groups of*/ * 4/*hex digits separated by*/ + 7 /*colons*/,
- };
- let ip_name = {
- let buf = vec::from_elem(ip_size + 1 /*null terminated*/, 0u8);
- unsafe {
- let buf_ptr = vec::raw::to_ptr(buf);
- match addr {
- UvIpv4SocketAddr(addr) => uvll::ip4_name(addr, buf_ptr, ip_size as size_t),
- UvIpv6SocketAddr(addr) => uvll::ip6_name(addr, buf_ptr, ip_size as size_t),
- }
- };
- buf
- };
- let ip_port = unsafe {
- let port = match addr {
- UvIpv4SocketAddr(addr) => uvll::ip4_port(addr),
- UvIpv6SocketAddr(addr) => uvll::ip6_port(addr),
- };
- port as u16
- };
- let ip_str = str::from_utf8_slice(ip_name).trim_right_chars(&'\x00');
- let ip_addr = FromStr::from_str(ip_str).unwrap();
-
- // finally run the closure
- f(SocketAddr { ip: ip_addr, port: ip_port })
-}
-
-pub fn uv_socket_addr_to_socket_addr(addr: UvSocketAddr) -> SocketAddr {
- use util;
- uv_socket_addr_as_socket_addr(addr, util::id)
-}
-
-#[cfg(test)]
-#[test]
-fn test_ip4_conversion() {
- use rt;
- let ip4 = rt::test::next_test_ip4();
- assert_eq!(ip4, socket_addr_as_uv_socket_addr(ip4, uv_socket_addr_to_socket_addr));
-}
-
-#[cfg(test)]
-#[test]
-fn test_ip6_conversion() {
- use rt;
- let ip6 = rt::test::next_test_ip6();
- assert_eq!(ip6, socket_addr_as_uv_socket_addr(ip6, uv_socket_addr_to_socket_addr));
-}
-
-// uv_stream_t is the parent class of uv_tcp_t, uv_pipe_t, uv_tty_t
-// and uv_file_t
-pub struct StreamWatcher(*uvll::uv_stream_t);
-impl Watcher for StreamWatcher { }
-
-impl StreamWatcher {
- pub fn read_start(&mut self, alloc: AllocCallback, cb: ReadCallback) {
- unsafe {
- match uvll::read_start(self.native_handle(), alloc_cb, read_cb) {
- 0 => {
- let data = self.get_watcher_data();
- data.alloc_cb = Some(alloc);
- data.read_cb = Some(cb);
- }
- n => {
- cb(*self, 0, empty_buf(), Some(UvError(n)))
- }
- }
- }
-
- extern fn alloc_cb(stream: *uvll::uv_stream_t, suggested_size: size_t) -> Buf {
- let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(stream);
- let alloc_cb = stream_watcher.get_watcher_data().alloc_cb.get_ref();
- return (*alloc_cb)(suggested_size as uint);
- }
-
- extern fn read_cb(stream: *uvll::uv_stream_t, nread: ssize_t, buf: Buf) {
- rtdebug!("buf addr: {}", buf.base);
- rtdebug!("buf len: {}", buf.len);
- let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(stream);
- let cb = stream_watcher.get_watcher_data().read_cb.get_ref();
- let status = status_to_maybe_uv_error(nread as c_int);
- (*cb)(stream_watcher, nread as int, buf, status);
- }
- }
-
- pub fn read_stop(&mut self) {
- // It would be nice to drop the alloc and read callbacks here,
- // but read_stop may be called from inside one of them and we
- // would end up freeing the in-use environment
- let handle = self.native_handle();
- unsafe { assert_eq!(uvll::read_stop(handle), 0); }
- }
-
- pub fn write(&mut self, buf: Buf, cb: ConnectionCallback) {
- let req = WriteRequest::new();
- return unsafe {
- match uvll::write(req.native_handle(), self.native_handle(),
- [buf], write_cb) {
- 0 => {
- let data = self.get_watcher_data();
- assert!(data.write_cb.is_none());
- data.write_cb = Some(cb);
- }
- n => {
- req.delete();
- cb(*self, Some(UvError(n)))
- }
- }
- };
-
- extern fn write_cb(req: *uvll::uv_write_t, status: c_int) {
- let write_request: WriteRequest = NativeHandle::from_native_handle(req);
- let mut stream_watcher = write_request.stream();
- write_request.delete();
- let cb = stream_watcher.get_watcher_data().write_cb.take_unwrap();
- let status = status_to_maybe_uv_error(status);
- cb(stream_watcher, status);
- }
- }
-
-
- pub fn listen(&mut self, cb: ConnectionCallback) -> Result<(), UvError> {
- {
- let data = self.get_watcher_data();
- assert!(data.connect_cb.is_none());
- data.connect_cb = Some(cb);
- }
-
- return unsafe {
- static BACKLOG: c_int = 128; // XXX should be configurable
- match uvll::listen(self.native_handle(), BACKLOG, connection_cb) {
- 0 => Ok(()),
- n => Err(UvError(n))
- }
- };
-
- extern fn connection_cb(handle: *uvll::uv_stream_t, status: c_int) {
- rtdebug!("connection_cb");
- let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle);
- let cb = stream_watcher.get_watcher_data().connect_cb.get_ref();
- let status = status_to_maybe_uv_error(status);
- (*cb)(stream_watcher, status);
- }
- }
-
- pub fn accept(&mut self, stream: StreamWatcher) {
- let self_handle = self.native_handle() as *c_void;
- let stream_handle = stream.native_handle() as *c_void;
- assert_eq!(0, unsafe { uvll::accept(self_handle, stream_handle) } );
- }
-}
-
-impl NativeHandle<*uvll::uv_stream_t> for StreamWatcher {
- fn from_native_handle(handle: *uvll::uv_stream_t) -> StreamWatcher {
- StreamWatcher(handle)
- }
- fn native_handle(&self) -> *uvll::uv_stream_t {
- match self { &StreamWatcher(ptr) => ptr }
- }
-}
-
-pub struct TcpWatcher(*uvll::uv_tcp_t);
-impl Watcher for TcpWatcher { }
-
-impl TcpWatcher {
- pub fn new(loop_: &Loop) -> TcpWatcher {
- unsafe {
- let handle = malloc_handle(UV_TCP);
- assert!(handle.is_not_null());
- assert_eq!(0, uvll::tcp_init(loop_.native_handle(), handle));
- let mut watcher: TcpWatcher = NativeHandle::from_native_handle(handle);
- watcher.install_watcher_data();
- return watcher;
- }
- }
-
- pub fn bind(&mut self, address: SocketAddr) -> Result<(), UvError> {
- do socket_addr_as_uv_socket_addr(address) |addr| {
- let result = unsafe {
- match addr {
- UvIpv4SocketAddr(addr) => uvll::tcp_bind(self.native_handle(), addr),
- UvIpv6SocketAddr(addr) => uvll::tcp_bind6(self.native_handle(), addr),
- }
- };
- match result {
- 0 => Ok(()),
- _ => Err(UvError(result)),
- }
- }
- }
-
- pub fn connect(&mut self, address: SocketAddr, cb: ConnectionCallback) {
- unsafe {
- assert!(self.get_watcher_data().connect_cb.is_none());
- self.get_watcher_data().connect_cb = Some(cb);
-
- let connect_handle = ConnectRequest::new().native_handle();
- rtdebug!("connect_t: {}", connect_handle);
- do socket_addr_as_uv_socket_addr(address) |addr| {
- let result = match addr {
- UvIpv4SocketAddr(addr) => uvll::tcp_connect(connect_handle,
- self.native_handle(), addr, connect_cb),
- UvIpv6SocketAddr(addr) => uvll::tcp_connect6(connect_handle,
- self.native_handle(), addr, connect_cb),
- };
- assert_eq!(0, result);
- }
-
- extern fn connect_cb(req: *uvll::uv_connect_t, status: c_int) {
- rtdebug!("connect_t: {}", req);
- let connect_request: ConnectRequest = NativeHandle::from_native_handle(req);
- let mut stream_watcher = connect_request.stream();
- connect_request.delete();
- let cb = stream_watcher.get_watcher_data().connect_cb.take_unwrap();
- let status = status_to_maybe_uv_error(status);
- cb(stream_watcher, status);
- }
- }
- }
-
- pub fn as_stream(&self) -> StreamWatcher {
- NativeHandle::from_native_handle(self.native_handle() as *uvll::uv_stream_t)
- }
-}
-
-impl NativeHandle<*uvll::uv_tcp_t> for TcpWatcher {
- fn from_native_handle(handle: *uvll::uv_tcp_t) -> TcpWatcher {
- TcpWatcher(handle)
- }
- fn native_handle(&self) -> *uvll::uv_tcp_t {
- match self { &TcpWatcher(ptr) => ptr }
- }
-}
-
-pub struct UdpWatcher(*uvll::uv_udp_t);
-impl Watcher for UdpWatcher { }
-
-impl UdpWatcher {
- pub fn new(loop_: &Loop) -> UdpWatcher {
- unsafe {
- let handle = malloc_handle(UV_UDP);
- assert!(handle.is_not_null());
- assert_eq!(0, uvll::udp_init(loop_.native_handle(), handle));
- let mut watcher: UdpWatcher = NativeHandle::from_native_handle(handle);
- watcher.install_watcher_data();
- return watcher;
- }
- }
-
- pub fn bind(&mut self, address: SocketAddr) -> Result<(), UvError> {
- do socket_addr_as_uv_socket_addr(address) |addr| {
- let result = unsafe {
- match addr {
- UvIpv4SocketAddr(addr) => uvll::udp_bind(self.native_handle(), addr, 0u32),
- UvIpv6SocketAddr(addr) => uvll::udp_bind6(self.native_handle(), addr, 0u32),
- }
- };
- match result {
- 0 => Ok(()),
- _ => Err(UvError(result)),
- }
- }
- }
-
- pub fn recv_start(&mut self, alloc: AllocCallback, cb: UdpReceiveCallback) {
- {
- let data = self.get_watcher_data();
- data.alloc_cb = Some(alloc);
- data.udp_recv_cb = Some(cb);
- }
-
- unsafe { uvll::udp_recv_start(self.native_handle(), alloc_cb, recv_cb); }
-
- extern fn alloc_cb(handle: *uvll::uv_udp_t, suggested_size: size_t) -> Buf {
- let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle);
- let alloc_cb = udp_watcher.get_watcher_data().alloc_cb.get_ref();
- return (*alloc_cb)(suggested_size as uint);
- }
-
- extern fn recv_cb(handle: *uvll::uv_udp_t, nread: ssize_t, buf: Buf,
- addr: *uvll::sockaddr, flags: c_uint) {
- // When there's no data to read the recv callback can be a no-op.
- // This can happen if read returns EAGAIN/EWOULDBLOCK. By ignoring
- // this we just drop back to kqueue and wait for the next callback.
- if nread == 0 {
- return;
- }
-
- rtdebug!("buf addr: {}", buf.base);
- rtdebug!("buf len: {}", buf.len);
- let mut udp_watcher: UdpWatcher = NativeHandle::from_native_handle(handle);
- let cb = udp_watcher.get_watcher_data().udp_recv_cb.get_ref();
- let status = status_to_maybe_uv_error(nread as c_int);
- let addr = uv_socket_addr_to_socket_addr(sockaddr_to_UvSocketAddr(addr));
- (*cb)(udp_watcher, nread as int, buf, addr, flags as uint, status);
- }
- }
-
- pub fn recv_stop(&mut self) {
- unsafe { uvll::udp_recv_stop(self.native_handle()); }
- }
-
- pub fn send(&mut self, buf: Buf, address: SocketAddr, cb: UdpSendCallback) {
- {
- let data = self.get_watcher_data();
- assert!(data.udp_send_cb.is_none());
- data.udp_send_cb = Some(cb);
- }
-
- let req = UdpSendRequest::new();
- do socket_addr_as_uv_socket_addr(address) |addr| {
- let result = unsafe {
- match addr {
- UvIpv4SocketAddr(addr) => uvll::udp_send(req.native_handle(),
- self.native_handle(), [buf], addr, send_cb),
- UvIpv6SocketAddr(addr) => uvll::udp_send6(req.native_handle(),
- self.native_handle(), [buf], addr, send_cb),
- }
- };
- assert_eq!(0, result);
- }
-
- extern fn send_cb(req: *uvll::uv_udp_send_t, status: c_int) {
- let send_request: UdpSendRequest = NativeHandle::from_native_handle(req);
- let mut udp_watcher = send_request.handle();
- send_request.delete();
- let cb = udp_watcher.get_watcher_data().udp_send_cb.take_unwrap();
- let status = status_to_maybe_uv_error(status);
- cb(udp_watcher, status);
- }
- }
-}
-
-impl NativeHandle<*uvll::uv_udp_t> for UdpWatcher {
- fn from_native_handle(handle: *uvll::uv_udp_t) -> UdpWatcher {
- UdpWatcher(handle)
- }
- fn native_handle(&self) -> *uvll::uv_udp_t {
- match self { &UdpWatcher(ptr) => ptr }
- }
-}
-
-// uv_connect_t is a subclass of uv_req_t
-pub struct ConnectRequest(*uvll::uv_connect_t);
-impl Request for ConnectRequest { }
-
-impl ConnectRequest {
-
- pub fn new() -> ConnectRequest {
- let connect_handle = unsafe { malloc_req(UV_CONNECT) };
- assert!(connect_handle.is_not_null());
- ConnectRequest(connect_handle as *uvll::uv_connect_t)
- }
-
- fn stream(&self) -> StreamWatcher {
- unsafe {
- let stream_handle = uvll::get_stream_handle_from_connect_req(self.native_handle());
- NativeHandle::from_native_handle(stream_handle)
- }
- }
-
- fn delete(self) {
- unsafe { free_req(self.native_handle() as *c_void) }
- }
-}
-
-impl NativeHandle<*uvll::uv_connect_t> for ConnectRequest {
- fn from_native_handle(handle: *uvll:: uv_connect_t) -> ConnectRequest {
- ConnectRequest(handle)
- }
- fn native_handle(&self) -> *uvll::uv_connect_t {
- match self { &ConnectRequest(ptr) => ptr }
- }
-}
-
-pub struct WriteRequest(*uvll::uv_write_t);
-
-impl Request for WriteRequest { }
-
-impl WriteRequest {
- pub fn new() -> WriteRequest {
- let write_handle = unsafe { malloc_req(UV_WRITE) };
- assert!(write_handle.is_not_null());
- WriteRequest(write_handle as *uvll::uv_write_t)
- }
-
- pub fn stream(&self) -> StreamWatcher {
- unsafe {
- let stream_handle = uvll::get_stream_handle_from_write_req(self.native_handle());
- NativeHandle::from_native_handle(stream_handle)
- }
- }
-
- pub fn delete(self) {
- unsafe { free_req(self.native_handle() as *c_void) }
- }
-}
-
-impl NativeHandle<*uvll::uv_write_t> for WriteRequest {
- fn from_native_handle(handle: *uvll:: uv_write_t) -> WriteRequest {
- WriteRequest(handle)
- }
- fn native_handle(&self) -> *uvll::uv_write_t {
- match self { &WriteRequest(ptr) => ptr }
- }
-}
-
-pub struct UdpSendRequest(*uvll::uv_udp_send_t);
-impl Request for UdpSendRequest { }
-
-impl UdpSendRequest {
- pub fn new() -> UdpSendRequest {
- let send_handle = unsafe { malloc_req(UV_UDP_SEND) };
- assert!(send_handle.is_not_null());
- UdpSendRequest(send_handle as *uvll::uv_udp_send_t)
- }
-
- pub fn handle(&self) -> UdpWatcher {
- let send_request_handle = unsafe {
- uvll::get_udp_handle_from_send_req(self.native_handle())
- };
- NativeHandle::from_native_handle(send_request_handle)
- }
-
- pub fn delete(self) {
- unsafe { free_req(self.native_handle() as *c_void) }
- }
-}
-
-impl NativeHandle<*uvll::uv_udp_send_t> for UdpSendRequest {
- fn from_native_handle(handle: *uvll::uv_udp_send_t) -> UdpSendRequest {
- UdpSendRequest(handle)
- }
- fn native_handle(&self) -> *uvll::uv_udp_send_t {
- match self { &UdpSendRequest(ptr) => ptr }
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
- use util::ignore;
- use cell::Cell;
- use vec;
- use unstable::run_in_bare_thread;
- use rt::thread::Thread;
- use rt::test::*;
- use rt::uv::{Loop, AllocCallback};
- use rt::uv::{vec_from_uv_buf, vec_to_uv_buf, slice_to_uv_buf};
- use prelude::*;
-
- #[test]
- fn connect_close_ip4() {
- do run_in_bare_thread() {
- let mut loop_ = Loop::new();
- let mut tcp_watcher = { TcpWatcher::new(&mut loop_) };
- // Connect to a port where nobody is listening
- let addr = next_test_ip4();
- do tcp_watcher.connect(addr) |stream_watcher, status| {
- rtdebug!("tcp_watcher.connect!");
- assert!(status.is_some());
- assert_eq!(status.unwrap().name(), ~"ECONNREFUSED");
- stream_watcher.close(||());
- }
- loop_.run();
- loop_.close();
- }
- }
-
- #[test]
- fn connect_close_ip6() {
- do run_in_bare_thread() {
- let mut loop_ = Loop::new();
- let mut tcp_watcher = { TcpWatcher::new(&mut loop_) };
- // Connect to a port where nobody is listening
- let addr = next_test_ip6();
- do tcp_watcher.connect(addr) |stream_watcher, status| {
- rtdebug!("tcp_watcher.connect!");
- assert!(status.is_some());
- assert_eq!(status.unwrap().name(), ~"ECONNREFUSED");
- stream_watcher.close(||());
- }
- loop_.run();
- loop_.close();
- }
- }
-
- #[test]
- fn udp_bind_close_ip4() {
- do run_in_bare_thread() {
- let mut loop_ = Loop::new();
- let mut udp_watcher = { UdpWatcher::new(&mut loop_) };
- let addr = next_test_ip4();
- udp_watcher.bind(addr);
- udp_watcher.close(||());
- loop_.run();
- loop_.close();
- }
- }
-
- #[test]
- fn udp_bind_close_ip6() {
- do run_in_bare_thread() {
- let mut loop_ = Loop::new();
- let mut udp_watcher = { UdpWatcher::new(&mut loop_) };
- let addr = next_test_ip6();
- udp_watcher.bind(addr);
- udp_watcher.close(||());
- loop_.run();
- loop_.close();
- }
- }
-
- #[test]
- fn listen_ip4() {
- do run_in_bare_thread() {
- static MAX: int = 10;
- let mut loop_ = Loop::new();
- let mut server_tcp_watcher = { TcpWatcher::new(&mut loop_) };
- let addr = next_test_ip4();
- server_tcp_watcher.bind(addr);
- let loop_ = loop_;
- rtdebug!("listening");
- let mut stream = server_tcp_watcher.as_stream();
- let res = do stream.listen |mut server_stream_watcher, status| {
- rtdebug!("listened!");
- assert!(status.is_none());
- let mut loop_ = loop_;
- let client_tcp_watcher = TcpWatcher::new(&mut loop_);
- let mut client_tcp_watcher = client_tcp_watcher.as_stream();
- server_stream_watcher.accept(client_tcp_watcher);
- let count_cell = Cell::new(0);
- let server_stream_watcher = server_stream_watcher;
- rtdebug!("starting read");
- let alloc: AllocCallback = |size| {
- vec_to_uv_buf(vec::from_elem(size, 0u8))
- };
- do client_tcp_watcher.read_start(alloc) |stream_watcher, nread, buf, status| {
-
- rtdebug!("i'm reading!");
- let buf = vec_from_uv_buf(buf);
- let mut count = count_cell.take();
- if status.is_none() {
- rtdebug!("got {} bytes", nread);
- let buf = buf.unwrap();
- for byte in buf.slice(0, nread as uint).iter() {
- assert!(*byte == count as u8);
- rtdebug!("{}", *byte as uint);
- count += 1;
- }
- } else {
- assert_eq!(count, MAX);
- do stream_watcher.close {
- server_stream_watcher.close(||());
- }
- }
- count_cell.put_back(count);
- }
- };
-
- assert!(res.is_ok());
-
- let client_thread = do Thread::start {
- rtdebug!("starting client thread");
- let mut loop_ = Loop::new();
- let mut tcp_watcher = { TcpWatcher::new(&mut loop_) };
- do tcp_watcher.connect(addr) |mut stream_watcher, status| {
- rtdebug!("connecting");
- assert!(status.is_none());
- let msg = ~[0, 1, 2, 3, 4, 5, 6 ,7 ,8, 9];
- let buf = slice_to_uv_buf(msg);
- let msg_cell = Cell::new(msg);
- do stream_watcher.write(buf) |stream_watcher, status| {
- rtdebug!("writing");
- assert!(status.is_none());
- let msg_cell = Cell::new(msg_cell.take());
- stream_watcher.close(||ignore(msg_cell.take()));
- }
- }
- loop_.run();
- loop_.close();
- };
-
- let mut loop_ = loop_;
- loop_.run();
- loop_.close();
- client_thread.join();
- };
- }
-
- #[test]
- fn listen_ip6() {
- do run_in_bare_thread() {
- static MAX: int = 10;
- let mut loop_ = Loop::new();
- let mut server_tcp_watcher = { TcpWatcher::new(&mut loop_) };
- let addr = next_test_ip6();
- server_tcp_watcher.bind(addr);
- let loop_ = loop_;
- rtdebug!("listening");
- let mut stream = server_tcp_watcher.as_stream();
- let res = do stream.listen |mut server_stream_watcher, status| {
- rtdebug!("listened!");
- assert!(status.is_none());
- let mut loop_ = loop_;
- let client_tcp_watcher = TcpWatcher::new(&mut loop_);
- let mut client_tcp_watcher = client_tcp_watcher.as_stream();
- server_stream_watcher.accept(client_tcp_watcher);
- let count_cell = Cell::new(0);
- let server_stream_watcher = server_stream_watcher;
- rtdebug!("starting read");
- let alloc: AllocCallback = |size| {
- vec_to_uv_buf(vec::from_elem(size, 0u8))
- };
- do client_tcp_watcher.read_start(alloc)
- |stream_watcher, nread, buf, status| {
-
- rtdebug!("i'm reading!");
- let buf = vec_from_uv_buf(buf);
- let mut count = count_cell.take();
- if status.is_none() {
- rtdebug!("got {} bytes", nread);
- let buf = buf.unwrap();
- let r = buf.slice(0, nread as uint);
- for byte in r.iter() {
- assert!(*byte == count as u8);
- rtdebug!("{}", *byte as uint);
- count += 1;
- }
- } else {
- assert_eq!(count, MAX);
- do stream_watcher.close {
- server_stream_watcher.close(||());
- }
- }
- count_cell.put_back(count);
- }
- };
- assert!(res.is_ok());
-
- let client_thread = do Thread::start {
- rtdebug!("starting client thread");
- let mut loop_ = Loop::new();
- let mut tcp_watcher = { TcpWatcher::new(&mut loop_) };
- do tcp_watcher.connect(addr) |mut stream_watcher, status| {
- rtdebug!("connecting");
- assert!(status.is_none());
- let msg = ~[0, 1, 2, 3, 4, 5, 6 ,7 ,8, 9];
- let buf = slice_to_uv_buf(msg);
- let msg_cell = Cell::new(msg);
- do stream_watcher.write(buf) |stream_watcher, status| {
- rtdebug!("writing");
- assert!(status.is_none());
- let msg_cell = Cell::new(msg_cell.take());
- stream_watcher.close(||ignore(msg_cell.take()));
- }
- }
- loop_.run();
- loop_.close();
- };
-
- let mut loop_ = loop_;
- loop_.run();
- loop_.close();
- client_thread.join();
- }
- }
-
- #[test]
- fn udp_recv_ip4() {
- do run_in_bare_thread() {
- static MAX: int = 10;
- let mut loop_ = Loop::new();
- let server_addr = next_test_ip4();
- let client_addr = next_test_ip4();
-
- let mut server = UdpWatcher::new(&loop_);
- assert!(server.bind(server_addr).is_ok());
-
- rtdebug!("starting read");
- let alloc: AllocCallback = |size| {
- vec_to_uv_buf(vec::from_elem(size, 0u8))
- };
-
- do server.recv_start(alloc) |mut server, nread, buf, src, flags, status| {
- server.recv_stop();
- rtdebug!("i'm reading!");
- assert!(status.is_none());
- assert_eq!(flags, 0);
- assert_eq!(src, client_addr);
-
- let buf = vec_from_uv_buf(buf);
- let mut count = 0;
- rtdebug!("got {} bytes", nread);
-
- let buf = buf.unwrap();
- for &byte in buf.slice(0, nread as uint).iter() {
- assert!(byte == count as u8);
- rtdebug!("{}", byte as uint);
- count += 1;
- }
- assert_eq!(count, MAX);
-
- server.close(||{});
- }
-
- let thread = do Thread::start {
- let mut loop_ = Loop::new();
- let mut client = UdpWatcher::new(&loop_);
- assert!(client.bind(client_addr).is_ok());
- let msg = ~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
- let buf = slice_to_uv_buf(msg);
- do client.send(buf, server_addr) |client, status| {
- rtdebug!("writing");
- assert!(status.is_none());
- client.close(||{});
- }
-
- loop_.run();
- loop_.close();
- };
-
- loop_.run();
- loop_.close();
- thread.join();
- }
- }
-
- #[test]
- fn udp_recv_ip6() {
- do run_in_bare_thread() {
- static MAX: int = 10;
- let mut loop_ = Loop::new();
- let server_addr = next_test_ip6();
- let client_addr = next_test_ip6();
-
- let mut server = UdpWatcher::new(&loop_);
- assert!(server.bind(server_addr).is_ok());
-
- rtdebug!("starting read");
- let alloc: AllocCallback = |size| {
- vec_to_uv_buf(vec::from_elem(size, 0u8))
- };
-
- do server.recv_start(alloc) |mut server, nread, buf, src, flags, status| {
- server.recv_stop();
- rtdebug!("i'm reading!");
- assert!(status.is_none());
- assert_eq!(flags, 0);
- assert_eq!(src, client_addr);
-
- let buf = vec_from_uv_buf(buf);
- let mut count = 0;
- rtdebug!("got {} bytes", nread);
-
- let buf = buf.unwrap();
- for &byte in buf.slice(0, nread as uint).iter() {
- assert!(byte == count as u8);
- rtdebug!("{}", byte as uint);
- count += 1;
- }
- assert_eq!(count, MAX);
-
- server.close(||{});
- }
-
- let thread = do Thread::start {
- let mut loop_ = Loop::new();
- let mut client = UdpWatcher::new(&loop_);
- assert!(client.bind(client_addr).is_ok());
- let msg = ~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
- let buf = slice_to_uv_buf(msg);
- do client.send(buf, server_addr) |client, status| {
- rtdebug!("writing");
- assert!(status.is_none());
- client.close(||{});
- }
-
- loop_.run();
- loop_.close();
- };
-
- loop_.run();
- loop_.close();
- thread.join();
- }
- }
-}
+++ /dev/null
-// Copyright 2013 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use prelude::*;
-use libc;
-use c_str::CString;
-
-use rt::uv;
-use rt::uv::net;
-use rt::uv::uvll;
-
-pub struct Pipe(*uvll::uv_pipe_t);
-
-impl uv::Watcher for Pipe {}
-
-impl Pipe {
- pub fn new(loop_: &uv::Loop, ipc: bool) -> Pipe {
- unsafe {
- let handle = uvll::malloc_handle(uvll::UV_NAMED_PIPE);
- assert!(handle.is_not_null());
- let ipc = ipc as libc::c_int;
- assert_eq!(uvll::pipe_init(loop_.native_handle(), handle, ipc), 0);
- let mut ret: Pipe =
- uv::NativeHandle::from_native_handle(handle);
- ret.install_watcher_data();
- ret
- }
- }
-
- pub fn as_stream(&self) -> net::StreamWatcher {
- net::StreamWatcher(**self as *uvll::uv_stream_t)
- }
-
- #[fixed_stack_segment] #[inline(never)]
- pub fn open(&mut self, file: libc::c_int) -> Result<(), uv::UvError> {
- match unsafe { uvll::pipe_open(self.native_handle(), file) } {
- 0 => Ok(()),
- n => Err(uv::UvError(n))
- }
- }
-
- #[fixed_stack_segment] #[inline(never)]
- pub fn bind(&mut self, name: &CString) -> Result<(), uv::UvError> {
- do name.with_ref |name| {
- match unsafe { uvll::pipe_bind(self.native_handle(), name) } {
- 0 => Ok(()),
- n => Err(uv::UvError(n))
- }
- }
- }
-
- #[fixed_stack_segment] #[inline(never)]
- pub fn connect(&mut self, name: &CString, cb: uv::ConnectionCallback) {
- {
- let data = self.get_watcher_data();
- assert!(data.connect_cb.is_none());
- data.connect_cb = Some(cb);
- }
-
- let connect = net::ConnectRequest::new();
- let name = do name.with_ref |p| { p };
-
- unsafe {
- uvll::pipe_connect(connect.native_handle(),
- self.native_handle(),
- name,
- connect_cb)
- }
-
- extern "C" fn connect_cb(req: *uvll::uv_connect_t, status: libc::c_int) {
- let connect_request: net::ConnectRequest =
- uv::NativeHandle::from_native_handle(req);
- let mut stream_watcher = connect_request.stream();
- connect_request.delete();
-
- let cb = stream_watcher.get_watcher_data().connect_cb.take_unwrap();
- let status = uv::status_to_maybe_uv_error(status);
- cb(stream_watcher, status);
- }
- }
-
-}
-
-impl uv::NativeHandle<*uvll::uv_pipe_t> for Pipe {
- fn from_native_handle(handle: *uvll::uv_pipe_t) -> Pipe {
- Pipe(handle)
- }
- fn native_handle(&self) -> *uvll::uv_pipe_t {
- match self { &Pipe(ptr) => ptr }
- }
-}
+++ /dev/null
-// Copyright 2013 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use prelude::*;
-use cell::Cell;
-use libc;
-use ptr;
-use vec;
-
-use rt::io::process::*;
-use rt::uv;
-use rt::uv::uvio::{UvPipeStream, UvUnboundPipe};
-use rt::uv::uvll;
-
-/// A process wraps the handle of the underlying uv_process_t.
-pub struct Process(*uvll::uv_process_t);
-
-impl uv::Watcher for Process {}
-
-impl Process {
- /// Creates a new process, ready to spawn inside an event loop
- pub fn new() -> Process {
- let handle = unsafe { uvll::malloc_handle(uvll::UV_PROCESS) };
- assert!(handle.is_not_null());
- let mut ret: Process = uv::NativeHandle::from_native_handle(handle);
- ret.install_watcher_data();
- return ret;
- }
-
- /// Spawn a new process inside the specified event loop.
- ///
- /// The `config` variable will be passed down to libuv, and the `exit_cb`
- /// will be run only once, when the process exits.
- ///
- /// Returns either the corresponding process object or an error which
- /// occurred.
- pub fn spawn(&mut self, loop_: &uv::Loop, config: ProcessConfig,
- exit_cb: uv::ExitCallback)
- -> Result<~[Option<~UvPipeStream>], uv::UvError>
- {
- let cwd = config.cwd.map(|s| s.to_c_str());
-
- extern fn on_exit(p: *uvll::uv_process_t,
- exit_status: libc::c_int,
- term_signal: libc::c_int) {
- let mut p: Process = uv::NativeHandle::from_native_handle(p);
- let err = match exit_status {
- 0 => None,
- _ => uv::status_to_maybe_uv_error(-1)
- };
- p.get_watcher_data().exit_cb.take_unwrap()(p,
- exit_status as int,
- term_signal as int,
- err);
- }
-
- let io = config.io;
- let mut stdio = vec::with_capacity::<uvll::uv_stdio_container_t>(io.len());
- let mut ret_io = vec::with_capacity(io.len());
- unsafe {
- vec::raw::set_len(&mut stdio, io.len());
- for (slot, other) in stdio.iter().zip(io.iter()) {
- let io = set_stdio(slot as *uvll::uv_stdio_container_t, other,
- loop_);
- ret_io.push(io);
- }
- }
-
- let exit_cb = Cell::new(exit_cb);
- let ret_io = Cell::new(ret_io);
- do with_argv(config.program, config.args) |argv| {
- do with_env(config.env) |envp| {
- let options = uvll::uv_process_options_t {
- exit_cb: on_exit,
- file: unsafe { *argv },
- args: argv,
- env: envp,
- cwd: match cwd {
- Some(ref cwd) => cwd.with_ref(|p| p),
- None => ptr::null(),
- },
- flags: 0,
- stdio_count: stdio.len() as libc::c_int,
- stdio: stdio.as_imm_buf(|p, _| p),
- uid: 0,
- gid: 0,
- };
-
- match unsafe {
- uvll::spawn(loop_.native_handle(), **self, options)
- } {
- 0 => {
- (*self).get_watcher_data().exit_cb = Some(exit_cb.take());
- Ok(ret_io.take())
- }
- err => Err(uv::UvError(err))
- }
- }
- }
- }
-
- /// Sends a signal to this process.
- ///
- /// This is a wrapper around `uv_process_kill`
- pub fn kill(&self, signum: int) -> Result<(), uv::UvError> {
- match unsafe {
- uvll::process_kill(self.native_handle(), signum as libc::c_int)
- } {
- 0 => Ok(()),
- err => Err(uv::UvError(err))
- }
- }
-
- /// Returns the process id of a spawned process
- pub fn pid(&self) -> libc::pid_t {
- unsafe { uvll::process_pid(**self) as libc::pid_t }
- }
-}
-
-unsafe fn set_stdio(dst: *uvll::uv_stdio_container_t,
- io: &StdioContainer,
- loop_: &uv::Loop) -> Option<~UvPipeStream> {
- match *io {
- Ignored => {
- uvll::set_stdio_container_flags(dst, uvll::STDIO_IGNORE);
- None
- }
- InheritFd(fd) => {
- uvll::set_stdio_container_flags(dst, uvll::STDIO_INHERIT_FD);
- uvll::set_stdio_container_fd(dst, fd);
- None
- }
- CreatePipe(readable, writable) => {
- let mut flags = uvll::STDIO_CREATE_PIPE as libc::c_int;
- if readable {
- flags |= uvll::STDIO_READABLE_PIPE as libc::c_int;
- }
- if writable {
- flags |= uvll::STDIO_WRITABLE_PIPE as libc::c_int;
- }
- let pipe = UvUnboundPipe::new(loop_);
- let handle = pipe.pipe.as_stream().native_handle();
- uvll::set_stdio_container_flags(dst, flags);
- uvll::set_stdio_container_stream(dst, handle);
- Some(~UvPipeStream::new(pipe))
- }
- }
-}
-
-/// Converts the program and arguments to the argv array expected by libuv
-fn with_argv<T>(prog: &str, args: &[~str], f: &fn(**libc::c_char) -> T) -> T {
- // First, allocation space to put all the C-strings (we need to have
- // ownership of them somewhere
- let mut c_strs = vec::with_capacity(args.len() + 1);
- c_strs.push(prog.to_c_str());
- for arg in args.iter() {
- c_strs.push(arg.to_c_str());
- }
-
- // Next, create the char** array
- let mut c_args = vec::with_capacity(c_strs.len() + 1);
- for s in c_strs.iter() {
- c_args.push(s.with_ref(|p| p));
- }
- c_args.push(ptr::null());
- c_args.as_imm_buf(|buf, _| f(buf))
-}
-
-/// Converts the environment to the env array expected by libuv
-fn with_env<T>(env: Option<&[(~str, ~str)]>, f: &fn(**libc::c_char) -> T) -> T {
- let env = match env {
- Some(s) => s,
- None => { return f(ptr::null()); }
- };
- // As with argv, create some temporary storage and then the actual array
- let mut envp = vec::with_capacity(env.len());
- for &(ref key, ref value) in env.iter() {
- envp.push(format!("{}={}", *key, *value).to_c_str());
- }
- let mut c_envp = vec::with_capacity(envp.len() + 1);
- for s in envp.iter() {
- c_envp.push(s.with_ref(|p| p));
- }
- c_envp.push(ptr::null());
- c_envp.as_imm_buf(|buf, _| f(buf))
-}
-
-impl uv::NativeHandle<*uvll::uv_process_t> for Process {
- fn from_native_handle(handle: *uvll::uv_process_t) -> Process {
- Process(handle)
- }
- fn native_handle(&self) -> *uvll::uv_process_t {
- match self { &Process(ptr) => ptr }
- }
-}
+++ /dev/null
-// Copyright 2013 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use cast;
-use option::Some;
-use libc::c_int;
-use result::{Err, Ok, Result};
-use rt::io::signal::Signum;
-use rt::uv::{Loop, NativeHandle, SignalCallback, UvError, Watcher};
-use rt::uv::uvll;
-
-pub struct SignalWatcher(*uvll::uv_signal_t);
-
-impl Watcher for SignalWatcher { }
-
-impl SignalWatcher {
- pub fn new(loop_: &mut Loop) -> SignalWatcher {
- unsafe {
- let handle = uvll::malloc_handle(uvll::UV_SIGNAL);
- assert!(handle.is_not_null());
- assert!(0 == uvll::signal_init(loop_.native_handle(), handle));
- let mut watcher: SignalWatcher = NativeHandle::from_native_handle(handle);
- watcher.install_watcher_data();
- return watcher;
- }
- }
-
- pub fn start(&mut self, signum: Signum, callback: SignalCallback)
- -> Result<(), UvError>
- {
- return unsafe {
- match uvll::signal_start(self.native_handle(), signal_cb,
- signum as c_int) {
- 0 => {
- let data = self.get_watcher_data();
- data.signal_cb = Some(callback);
- Ok(())
- }
- n => Err(UvError(n)),
- }
- };
-
- extern fn signal_cb(handle: *uvll::uv_signal_t, signum: c_int) {
- let mut watcher: SignalWatcher = NativeHandle::from_native_handle(handle);
- let data = watcher.get_watcher_data();
- let cb = data.signal_cb.get_ref();
- (*cb)(watcher, unsafe { cast::transmute(signum as int) });
- }
- }
-
- pub fn stop(&mut self) {
- unsafe {
- uvll::signal_stop(self.native_handle());
- }
- }
-}
-
-impl NativeHandle<*uvll::uv_signal_t> for SignalWatcher {
- fn from_native_handle(handle: *uvll::uv_signal_t) -> SignalWatcher {
- SignalWatcher(handle)
- }
-
- fn native_handle(&self) -> *uvll::uv_signal_t {
- match self { &SignalWatcher(ptr) => ptr }
- }
-}
+++ /dev/null
-// Copyright 2013 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use libc::c_int;
-use option::Some;
-use rt::uv::uvll;
-use rt::uv::{Watcher, Loop, NativeHandle, TimerCallback};
-use rt::uv::status_to_maybe_uv_error;
-
-pub struct TimerWatcher(*uvll::uv_timer_t);
-impl Watcher for TimerWatcher { }
-
-impl TimerWatcher {
- pub fn new(loop_: &mut Loop) -> TimerWatcher {
- unsafe {
- let handle = uvll::malloc_handle(uvll::UV_TIMER);
- assert!(handle.is_not_null());
- assert!(0 == uvll::timer_init(loop_.native_handle(), handle));
- let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle);
- watcher.install_watcher_data();
- return watcher;
- }
- }
-
- pub fn start(&mut self, timeout: u64, repeat: u64, cb: TimerCallback) {
- {
- let data = self.get_watcher_data();
- data.timer_cb = Some(cb);
- }
-
- unsafe {
- uvll::timer_start(self.native_handle(), timer_cb, timeout, repeat);
- }
-
- extern fn timer_cb(handle: *uvll::uv_timer_t, status: c_int) {
- let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle);
- let data = watcher.get_watcher_data();
- let cb = data.timer_cb.get_ref();
- let status = status_to_maybe_uv_error(status);
- (*cb)(watcher, status);
- }
- }
-
- pub fn stop(&mut self) {
- unsafe {
- uvll::timer_stop(self.native_handle());
- }
- }
-}
-
-impl NativeHandle<*uvll::uv_timer_t> for TimerWatcher {
- fn from_native_handle(handle: *uvll::uv_timer_t) -> TimerWatcher {
- TimerWatcher(handle)
- }
- fn native_handle(&self) -> *uvll::uv_idle_t {
- match self { &TimerWatcher(ptr) => ptr }
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::*;
- use rt::uv::Loop;
- use unstable::run_in_bare_thread;
-
- #[test]
- fn smoke_test() {
- do run_in_bare_thread {
- let mut count = 0;
- let count_ptr: *mut int = &mut count;
- let mut loop_ = Loop::new();
- let mut timer = TimerWatcher::new(&mut loop_);
- do timer.start(10, 0) |timer, status| {
- assert!(status.is_none());
- unsafe { *count_ptr += 1 };
- timer.close(||());
- }
- loop_.run();
- loop_.close();
- assert!(count == 1);
- }
- }
-
- #[test]
- fn start_twice() {
- do run_in_bare_thread {
- let mut count = 0;
- let count_ptr: *mut int = &mut count;
- let mut loop_ = Loop::new();
- let mut timer = TimerWatcher::new(&mut loop_);
- do timer.start(10, 0) |timer, status| {
- let mut timer = timer;
- assert!(status.is_none());
- unsafe { *count_ptr += 1 };
- do timer.start(10, 0) |timer, status| {
- assert!(status.is_none());
- unsafe { *count_ptr += 1 };
- timer.close(||());
- }
- }
- loop_.run();
- loop_.close();
- assert!(count == 2);
- }
- }
-
- #[test]
- fn repeat_stop() {
- do run_in_bare_thread {
- let mut count = 0;
- let count_ptr: *mut int = &mut count;
- let mut loop_ = Loop::new();
- let mut timer = TimerWatcher::new(&mut loop_);
- do timer.start(1, 2) |timer, status| {
- assert!(status.is_none());
- unsafe {
- *count_ptr += 1;
-
- if *count_ptr == 10 {
-
- // Stop the timer and do something else
- let mut timer = timer;
- timer.stop();
- // Freeze timer so it can be captured
- let timer = timer;
-
- let mut loop_ = timer.event_loop();
- let mut timer2 = TimerWatcher::new(&mut loop_);
- do timer2.start(10, 0) |timer2, _| {
-
- *count_ptr += 1;
-
- timer2.close(||());
-
- // Restart the original timer
- let mut timer = timer;
- do timer.start(1, 0) |timer, _| {
- *count_ptr += 1;
- timer.close(||());
- }
- }
- }
- };
- }
- loop_.run();
- loop_.close();
- assert!(count == 12);
- }
- }
-
-}
+++ /dev/null
-// Copyright 2013 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use prelude::*;
-use libc;
-
-use rt::uv;
-use rt::uv::net;
-use rt::uv::uvll;
-
-/// A process wraps the handle of the underlying uv_process_t.
-pub struct TTY(*uvll::uv_tty_t);
-
-impl uv::Watcher for TTY {}
-
-impl TTY {
- #[fixed_stack_segment] #[inline(never)]
- pub fn new(loop_: &uv::Loop, fd: libc::c_int, readable: bool) ->
- Result<TTY, uv::UvError>
- {
- let handle = unsafe { uvll::malloc_handle(uvll::UV_TTY) };
- assert!(handle.is_not_null());
-
- let ret = unsafe {
- uvll::tty_init(loop_.native_handle(), handle, fd as libc::c_int,
- readable as libc::c_int)
- };
- match ret {
- 0 => {
- let mut ret: TTY = uv::NativeHandle::from_native_handle(handle);
- ret.install_watcher_data();
- Ok(ret)
- }
- n => {
- unsafe { uvll::free_handle(handle); }
- Err(uv::UvError(n))
- }
- }
- }
-
- pub fn as_stream(&self) -> net::StreamWatcher {
- net::StreamWatcher(**self as *uvll::uv_stream_t)
- }
-
- #[fixed_stack_segment] #[inline(never)]
- pub fn set_mode(&self, raw: bool) -> Result<(), uv::UvError> {
- let raw = raw as libc::c_int;
- match unsafe { uvll::tty_set_mode(self.native_handle(), raw) } {
- 0 => Ok(()),
- n => Err(uv::UvError(n))
- }
- }
-
- #[fixed_stack_segment] #[inline(never)] #[allow(unused_mut)]
- pub fn get_winsize(&self) -> Result<(int, int), uv::UvError> {
- let mut width: libc::c_int = 0;
- let mut height: libc::c_int = 0;
- let widthptr: *libc::c_int = &width;
- let heightptr: *libc::c_int = &width;
-
- match unsafe { uvll::tty_get_winsize(self.native_handle(),
- widthptr, heightptr) } {
- 0 => Ok((width as int, height as int)),
- n => Err(uv::UvError(n))
- }
- }
-}
-
-impl uv::NativeHandle<*uvll::uv_tty_t> for TTY {
- fn from_native_handle(handle: *uvll::uv_tty_t) -> TTY {
- TTY(handle)
- }
- fn native_handle(&self) -> *uvll::uv_tty_t {
- match self { &TTY(ptr) => ptr }
- }
-}
-
+++ /dev/null
-// Copyright 2013 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use c_str::{ToCStr, CString};
-use cast::transmute;
-use cast;
-use cell::Cell;
-use clone::Clone;
-use comm::{SendDeferred, SharedChan, Port, PortOne, GenericChan};
-use libc::{c_int, c_uint, c_void, pid_t};
-use ops::Drop;
-use option::*;
-use ptr;
-use str;
-use result::*;
-use rt::io::IoError;
-use rt::io::net::ip::{SocketAddr, IpAddr};
-use rt::io::{standard_error, OtherIoError, SeekStyle, SeekSet, SeekCur, SeekEnd};
-use rt::io::process::ProcessConfig;
-use rt::kill::BlockedTask;
-use rt::local::Local;
-use rt::rtio::*;
-use rt::sched::{Scheduler, SchedHandle};
-use rt::tube::Tube;
-use rt::task::Task;
-use rt::uv::*;
-use rt::uv::idle::IdleWatcher;
-use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr};
-use rt::uv::addrinfo::{GetAddrInfoRequest, accum_addrinfo};
-use unstable::sync::Exclusive;
-use path::{GenericPath, Path};
-use libc::{lseek, off_t, O_CREAT, O_APPEND, O_TRUNC, O_RDWR, O_RDONLY, O_WRONLY,
- S_IRUSR, S_IWUSR, S_IRWXU};
-use rt::io::{FileMode, FileAccess, OpenOrCreate, Open, Create,
- CreateOrTruncate, Append, Truncate, Read, Write, ReadWrite,
- FileStat};
-use rt::io::signal::Signum;
-use task;
-use ai = rt::io::net::addrinfo;
-
-#[cfg(test)] use container::Container;
-#[cfg(test)] use unstable::run_in_bare_thread;
-#[cfg(test)] use rt::test::{spawntask,
- next_test_ip4,
- run_in_mt_newsched_task};
-#[cfg(test)] use iter::{Iterator, range};
-#[cfg(test)] use rt::comm::oneshot;
-
-// XXX we should not be calling uvll functions in here.
-
-trait HomingIO {
-
- fn home<'r>(&'r mut self) -> &'r mut SchedHandle;
-
- /// This function will move tasks to run on their home I/O scheduler. Note
- /// that this function does *not* pin the task to the I/O scheduler, but
- /// rather it simply moves it to running on the I/O scheduler.
- fn go_to_IO_home(&mut self) -> uint {
- use rt::sched::RunOnce;
-
- let current_sched_id = do Local::borrow |sched: &mut Scheduler| {
- sched.sched_id()
- };
-
- // Only need to invoke a context switch if we're not on the right
- // scheduler.
- if current_sched_id != self.home().sched_id {
- do task::unkillable { // FIXME(#8674)
- let scheduler: ~Scheduler = Local::take();
- do scheduler.deschedule_running_task_and_then |_, task| {
- /* FIXME(#8674) if the task was already killed then wake
- * will return None. In that case, the home pointer will
- * never be set.
- *
- * RESOLUTION IDEA: Since the task is dead, we should
- * just abort the IO action.
- */
- do task.wake().map |task| {
- self.home().send(RunOnce(task));
- };
- }
- }
- }
-
- self.home().sched_id
- }
-
- // XXX: dummy self parameter
- fn restore_original_home(_: Option<Self>, io_home: uint) {
- // It would truly be a sad day if we had moved off the home I/O
- // scheduler while we were doing I/O.
- assert_eq!(Local::borrow(|sched: &mut Scheduler| sched.sched_id()),
- io_home);
-
- // If we were a homed task, then we must send ourselves back to the
- // original scheduler. Otherwise, we can just return and keep running
- if !Task::on_appropriate_sched() {
- do task::unkillable { // FIXME(#8674)
- let scheduler: ~Scheduler = Local::take();
- do scheduler.deschedule_running_task_and_then |_, task| {
- do task.wake().map |task| {
- Scheduler::run_task(task);
- };
- }
- }
- }
- }
-
- fn home_for_io<A>(&mut self, io: &fn(&mut Self) -> A) -> A {
- let home = self.go_to_IO_home();
- let a = io(self); // do IO
- HomingIO::restore_original_home(None::<Self>, home);
- a // return the result of the IO
- }
-
- fn home_for_io_consume<A>(mut self, io: &fn(Self) -> A) -> A {
- let home = self.go_to_IO_home();
- let a = io(self); // do IO
- HomingIO::restore_original_home(None::<Self>, home);
- a // return the result of the IO
- }
-
- fn home_for_io_with_sched<A>(&mut self, io_sched: &fn(&mut Self, ~Scheduler) -> A) -> A {
- let home = self.go_to_IO_home();
- let a = do task::unkillable { // FIXME(#8674)
- let scheduler: ~Scheduler = Local::take();
- io_sched(self, scheduler) // do IO and scheduling action
- };
- HomingIO::restore_original_home(None::<Self>, home);
- a // return result of IO
- }
-}
-
-// get a handle for the current scheduler
-macro_rules! get_handle_to_current_scheduler(
- () => (do Local::borrow |sched: &mut Scheduler| { sched.make_handle() })
-)
-
-enum SocketNameKind {
- TcpPeer,
- Tcp,
- Udp
-}
-
-fn socket_name<T, U: Watcher + NativeHandle<*T>>(sk: SocketNameKind,
- handle: U) -> Result<SocketAddr, IoError> {
- let getsockname = match sk {
- TcpPeer => uvll::tcp_getpeername,
- Tcp => uvll::tcp_getsockname,
- Udp => uvll::udp_getsockname,
- };
-
- // Allocate a sockaddr_storage
- // since we don't know if it's ipv4 or ipv6
- let r_addr = unsafe { uvll::malloc_sockaddr_storage() };
-
- let r = unsafe {
- getsockname(handle.native_handle() as *c_void, r_addr as *uvll::sockaddr_storage)
- };
-
- if r != 0 {
- let status = status_to_maybe_uv_error(r);
- return Err(uv_error_to_io_error(status.unwrap()));
- }
-
- let addr = unsafe {
- if uvll::is_ip6_addr(r_addr as *uvll::sockaddr) {
- net::uv_socket_addr_to_socket_addr(UvIpv6SocketAddr(r_addr as *uvll::sockaddr_in6))
- } else {
- net::uv_socket_addr_to_socket_addr(UvIpv4SocketAddr(r_addr as *uvll::sockaddr_in))
- }
- };
-
- unsafe { uvll::free_sockaddr_storage(r_addr); }
-
- Ok(addr)
-
-}
-
-// Obviously an Event Loop is always home.
-pub struct UvEventLoop {
- priv uvio: UvIoFactory
-}
-
-impl UvEventLoop {
- pub fn new() -> UvEventLoop {
- UvEventLoop {
- uvio: UvIoFactory(Loop::new())
- }
- }
-}
-
-impl Drop for UvEventLoop {
- fn drop(&mut self) {
- self.uvio.uv_loop().close();
- }
-}
-
-impl EventLoop for UvEventLoop {
- fn run(&mut self) {
- self.uvio.uv_loop().run();
- }
-
- fn callback(&mut self, f: ~fn()) {
- let mut idle_watcher = IdleWatcher::new(self.uvio.uv_loop());
- do idle_watcher.start |mut idle_watcher, status| {
- assert!(status.is_none());
- idle_watcher.stop();
- idle_watcher.close(||());
- f();
- }
- }
-
- fn pausible_idle_callback(&mut self) -> ~PausibleIdleCallback {
- let idle_watcher = IdleWatcher::new(self.uvio.uv_loop());
- ~UvPausibleIdleCallback {
- watcher: idle_watcher,
- idle_flag: false,
- closed: false
- } as ~PausibleIdleCallback
- }
-
- fn remote_callback(&mut self, f: ~fn()) -> ~RemoteCallback {
- ~UvRemoteCallback::new(self.uvio.uv_loop(), f) as ~RemoteCallback
- }
-
- fn io<'a>(&'a mut self, f: &fn(&'a mut IoFactory)) {
- f(&mut self.uvio as &mut IoFactory)
- }
-}
-
-#[cfg(not(stage0))]
-#[lang = "event_loop_factory"]
-pub extern "C" fn new_loop() -> ~EventLoop {
- ~UvEventLoop::new() as ~EventLoop
-}
-
-pub struct UvPausibleIdleCallback {
- priv watcher: IdleWatcher,
- priv idle_flag: bool,
- priv closed: bool
-}
-
-impl PausibleIdleCallback for UvPausibleIdleCallback {
- #[inline]
- fn start(&mut self, f: ~fn()) {
- do self.watcher.start |_idle_watcher, _status| {
- f();
- };
- self.idle_flag = true;
- }
- #[inline]
- fn pause(&mut self) {
- if self.idle_flag == true {
- self.watcher.stop();
- self.idle_flag = false;
- }
- }
- #[inline]
- fn resume(&mut self) {
- if self.idle_flag == false {
- self.watcher.restart();
- self.idle_flag = true;
- }
- }
- #[inline]
- fn close(&mut self) {
- self.pause();
- if !self.closed {
- self.closed = true;
- self.watcher.close(||{});
- }
- }
-}
-
-#[test]
-fn test_callback_run_once() {
- do run_in_bare_thread {
- let mut event_loop = UvEventLoop::new();
- let mut count = 0;
- let count_ptr: *mut int = &mut count;
- do event_loop.callback {
- unsafe { *count_ptr += 1 }
- }
- event_loop.run();
- assert_eq!(count, 1);
- }
-}
-
-// The entire point of async is to call into a loop from other threads so it does not need to home.
-pub struct UvRemoteCallback {
- // The uv async handle for triggering the callback
- priv async: AsyncWatcher,
- // A flag to tell the callback to exit, set from the dtor. This is
- // almost never contested - only in rare races with the dtor.
- priv exit_flag: Exclusive<bool>
-}
-
-impl UvRemoteCallback {
- pub fn new(loop_: &mut Loop, f: ~fn()) -> UvRemoteCallback {
- let exit_flag = Exclusive::new(false);
- let exit_flag_clone = exit_flag.clone();
- let async = do AsyncWatcher::new(loop_) |watcher, status| {
- assert!(status.is_none());
-
- // The synchronization logic here is subtle. To review,
- // the uv async handle type promises that, after it is
- // triggered the remote callback is definitely called at
- // least once. UvRemoteCallback needs to maintain those
- // semantics while also shutting down cleanly from the
- // dtor. In our case that means that, when the
- // UvRemoteCallback dtor calls `async.send()`, here `f` is
- // always called later.
-
- // In the dtor both the exit flag is set and the async
- // callback fired under a lock. Here, before calling `f`,
- // we take the lock and check the flag. Because we are
- // checking the flag before calling `f`, and the flag is
- // set under the same lock as the send, then if the flag
- // is set then we're guaranteed to call `f` after the
- // final send.
-
- // If the check was done after `f()` then there would be a
- // period between that call and the check where the dtor
- // could be called in the other thread, missing the final
- // callback while still destroying the handle.
-
- let should_exit = unsafe {
- exit_flag_clone.with_imm(|&should_exit| should_exit)
- };
-
- f();
-
- if should_exit {
- watcher.close(||());
- }
-
- };
- UvRemoteCallback {
- async: async,
- exit_flag: exit_flag
- }
- }
-}
-
-impl RemoteCallback for UvRemoteCallback {
- fn fire(&mut self) { self.async.send() }
-}
-
-impl Drop for UvRemoteCallback {
- fn drop(&mut self) {
- unsafe {
- let this: &mut UvRemoteCallback = cast::transmute_mut(self);
- do this.exit_flag.with |should_exit| {
- // NB: These two things need to happen atomically. Otherwise
- // the event handler could wake up due to a *previous*
- // signal and see the exit flag, destroying the handle
- // before the final send.
- *should_exit = true;
- this.async.send();
- }
- }
- }
-}
-
-#[cfg(test)]
-mod test_remote {
- use cell::Cell;
- use rt::test::*;
- use rt::thread::Thread;
- use rt::tube::Tube;
- use rt::rtio::EventLoop;
- use rt::local::Local;
- use rt::sched::Scheduler;
-
- #[test]
- fn test_uv_remote() {
- do run_in_mt_newsched_task {
- let mut tube = Tube::new();
- let tube_clone = tube.clone();
- let remote_cell = Cell::new_empty();
- do Local::borrow |sched: &mut Scheduler| {
- let tube_clone = tube_clone.clone();
- let tube_clone_cell = Cell::new(tube_clone);
- let remote = do sched.event_loop.remote_callback {
- // This could be called multiple times
- if !tube_clone_cell.is_empty() {
- tube_clone_cell.take().send(1);
- }
- };
- remote_cell.put_back(remote);
- }
- let thread = do Thread::start {
- remote_cell.take().fire();
- };
-
- assert!(tube.recv() == 1);
- thread.join();
- }
- }
-}
-
-pub struct UvIoFactory(Loop);
-
-impl UvIoFactory {
- pub fn uv_loop<'a>(&'a mut self) -> &'a mut Loop {
- match self { &UvIoFactory(ref mut ptr) => ptr }
- }
-}
-
-/// Helper for a variety of simple uv_fs_* functions that
-/// have no ret val
-fn uv_fs_helper(loop_: &mut Loop, path: &CString,
- cb: ~fn(&mut FsRequest, &mut Loop, &CString,
- ~fn(&FsRequest, Option<UvError>)))
- -> Result<(), IoError> {
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
- let path_cell = Cell::new(path);
- do task::unkillable { // FIXME(#8674)
- let scheduler: ~Scheduler = Local::take();
- let mut new_req = FsRequest::new();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- let path = path_cell.take();
- do cb(&mut new_req, loop_, path) |_, err| {
- let res = match err {
- None => Ok(()),
- Some(err) => Err(uv_error_to_io_error(err))
- };
- unsafe { (*result_cell_ptr).put_back(res); }
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- };
- }
- }
- assert!(!result_cell.is_empty());
- return result_cell.take();
-}
-
-impl IoFactory for UvIoFactory {
- // Connect to an address and return a new stream
- // NB: This blocks the task waiting on the connection.
- // It would probably be better to return a future
- fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStream, IoError> {
- // Create a cell in the task to hold the result. We will fill
- // the cell before resuming the task.
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<~RtioTcpStream, IoError>> = &result_cell;
-
- // Block this task and take ownership, switch to scheduler context
- do task::unkillable { // FIXME(#8674)
- let scheduler: ~Scheduler = Local::take();
- do scheduler.deschedule_running_task_and_then |_, task| {
-
- let mut tcp = TcpWatcher::new(self.uv_loop());
- let task_cell = Cell::new(task);
-
- // Wait for a connection
- do tcp.connect(addr) |stream, status| {
- match status {
- None => {
- let tcp = NativeHandle::from_native_handle(stream.native_handle());
- let home = get_handle_to_current_scheduler!();
- let res = Ok(~UvTcpStream { watcher: tcp, home: home }
- as ~RtioTcpStream);
-
- // Store the stream in the task's stack
- unsafe { (*result_cell_ptr).put_back(res); }
-
- // Context switch
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- Some(_) => {
- let task_cell = Cell::new(task_cell.take());
- do stream.close {
- let res = Err(uv_error_to_io_error(status.unwrap()));
- unsafe { (*result_cell_ptr).put_back(res); }
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
- }
- }
- }
- }
-
- assert!(!result_cell.is_empty());
- return result_cell.take();
- }
-
- fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListener, IoError> {
- let mut watcher = TcpWatcher::new(self.uv_loop());
- match watcher.bind(addr) {
- Ok(_) => {
- let home = get_handle_to_current_scheduler!();
- Ok(~UvTcpListener::new(watcher, home) as ~RtioTcpListener)
- }
- Err(uverr) => {
- do task::unkillable { // FIXME(#8674)
- let scheduler: ~Scheduler = Local::take();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- do watcher.as_stream().close {
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
- Err(uv_error_to_io_error(uverr))
- }
- }
- }
- }
-
- fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocket, IoError> {
- let mut watcher = UdpWatcher::new(self.uv_loop());
- match watcher.bind(addr) {
- Ok(_) => {
- let home = get_handle_to_current_scheduler!();
- Ok(~UvUdpSocket { watcher: watcher, home: home } as ~RtioUdpSocket)
- }
- Err(uverr) => {
- do task::unkillable { // FIXME(#8674)
- let scheduler: ~Scheduler = Local::take();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- do watcher.close {
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
- Err(uv_error_to_io_error(uverr))
- }
- }
- }
- }
-
- fn timer_init(&mut self) -> Result<~RtioTimer, IoError> {
- let watcher = TimerWatcher::new(self.uv_loop());
- let home = get_handle_to_current_scheduler!();
- Ok(~UvTimer::new(watcher, home) as ~RtioTimer)
- }
-
- fn fs_from_raw_fd(&mut self, fd: c_int, close: CloseBehavior) -> ~RtioFileStream {
- let loop_ = Loop {handle: self.uv_loop().native_handle()};
- let home = get_handle_to_current_scheduler!();
- ~UvFileStream::new(loop_, fd, close, home) as ~RtioFileStream
- }
-
- fn fs_open(&mut self, path: &CString, fm: FileMode, fa: FileAccess)
- -> Result<~RtioFileStream, IoError> {
- let mut flags = match fm {
- Open => 0,
- Create => O_CREAT,
- OpenOrCreate => O_CREAT,
- Append => O_APPEND,
- Truncate => O_TRUNC,
- CreateOrTruncate => O_TRUNC | O_CREAT
- };
- flags = match fa {
- Read => flags | O_RDONLY,
- Write => flags | O_WRONLY,
- ReadWrite => flags | O_RDWR
- };
- let create_mode = match fm {
- Create|OpenOrCreate|CreateOrTruncate =>
- S_IRUSR | S_IWUSR,
- _ => 0
- };
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<~RtioFileStream,
- IoError>> = &result_cell;
- let path_cell = Cell::new(path);
- do task::unkillable { // FIXME(#8674)
- let scheduler: ~Scheduler = Local::take();
- let open_req = file::FsRequest::new();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- let path = path_cell.take();
- do open_req.open(self.uv_loop(), path, flags as int, create_mode as int)
- |req,err| {
- if err.is_none() {
- let loop_ = Loop {handle: req.get_loop().native_handle()};
- let home = get_handle_to_current_scheduler!();
- let fd = req.get_result() as c_int;
- let fs = ~UvFileStream::new(
- loop_, fd, CloseSynchronously, home) as ~RtioFileStream;
- let res = Ok(fs);
- unsafe { (*result_cell_ptr).put_back(res); }
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- } else {
- let res = Err(uv_error_to_io_error(err.unwrap()));
- unsafe { (*result_cell_ptr).put_back(res); }
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- };
- };
- };
- assert!(!result_cell.is_empty());
- return result_cell.take();
- }
-
- fn fs_unlink(&mut self, path: &CString) -> Result<(), IoError> {
- do uv_fs_helper(self.uv_loop(), path) |unlink_req, l, p, cb| {
- do unlink_req.unlink(l, p) |req, err| {
- cb(req, err)
- };
- }
- }
- fn fs_stat(&mut self, path: &CString) -> Result<FileStat, IoError> {
- use str::StrSlice;
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<FileStat,
- IoError>> = &result_cell;
- let path_cell = Cell::new(path);
- do task::unkillable { // FIXME(#8674)
- let scheduler: ~Scheduler = Local::take();
- let stat_req = file::FsRequest::new();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- let path = path_cell.take();
- // Don't pick up the null byte
- let slice = path.as_bytes().slice(0, path.len());
- let path_instance = Cell::new(Path::new(slice));
- do stat_req.stat(self.uv_loop(), path) |req,err| {
- let res = match err {
- None => {
- let stat = req.get_stat();
- Ok(FileStat {
- path: path_instance.take(),
- is_file: stat.is_file(),
- is_dir: stat.is_dir(),
- device: stat.st_dev,
- mode: stat.st_mode,
- inode: stat.st_ino,
- size: stat.st_size,
- created: stat.st_ctim.tv_sec as u64,
- modified: stat.st_mtim.tv_sec as u64,
- accessed: stat.st_atim.tv_sec as u64
- })
- },
- Some(e) => {
- Err(uv_error_to_io_error(e))
- }
- };
- unsafe { (*result_cell_ptr).put_back(res); }
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- };
- };
- };
- assert!(!result_cell.is_empty());
- return result_cell.take();
- }
-
- fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
- hint: Option<ai::Hint>) -> Result<~[ai::Info], IoError> {
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<~[ai::Info], IoError>> = &result_cell;
- let host_ptr: *Option<&str> = &host;
- let servname_ptr: *Option<&str> = &servname;
- let hint_ptr: *Option<ai::Hint> = &hint;
- let addrinfo_req = GetAddrInfoRequest::new();
- let addrinfo_req_cell = Cell::new(addrinfo_req);
-
- do task::unkillable { // FIXME(#8674)
- let scheduler: ~Scheduler = Local::take();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- let mut addrinfo_req = addrinfo_req_cell.take();
- unsafe {
- do addrinfo_req.getaddrinfo(self.uv_loop(),
- *host_ptr, *servname_ptr,
- *hint_ptr) |_, addrinfo, err| {
- let res = match err {
- None => Ok(accum_addrinfo(addrinfo)),
- Some(err) => Err(uv_error_to_io_error(err))
- };
- (*result_cell_ptr).put_back(res);
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
- }
- }
- addrinfo_req.delete();
- assert!(!result_cell.is_empty());
- return result_cell.take();
- }
- fn fs_mkdir(&mut self, path: &CString) -> Result<(), IoError> {
- let mode = S_IRWXU as int;
- do uv_fs_helper(self.uv_loop(), path) |mkdir_req, l, p, cb| {
- do mkdir_req.mkdir(l, p, mode as int) |req, err| {
- cb(req, err)
- };
- }
- }
- fn fs_rmdir(&mut self, path: &CString) -> Result<(), IoError> {
- do uv_fs_helper(self.uv_loop(), path) |rmdir_req, l, p, cb| {
- do rmdir_req.rmdir(l, p) |req, err| {
- cb(req, err)
- };
- }
- }
- fn fs_readdir(&mut self, path: &CString, flags: c_int) ->
- Result<~[Path], IoError> {
- use str::StrSlice;
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<~[Path],
- IoError>> = &result_cell;
- let path_cell = Cell::new(path);
- do task::unkillable { // FIXME(#8674)
- let scheduler: ~Scheduler = Local::take();
- let stat_req = file::FsRequest::new();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- let path = path_cell.take();
- // Don't pick up the null byte
- let slice = path.as_bytes().slice(0, path.len());
- let path_parent = Cell::new(Path::new(slice));
- do stat_req.readdir(self.uv_loop(), path, flags) |req,err| {
- let parent = path_parent.take();
- let res = match err {
- None => {
- let mut paths = ~[];
- do req.each_path |rel_path| {
- let p = rel_path.as_bytes();
- paths.push(parent.join(p.slice_to(rel_path.len())));
- }
- Ok(paths)
- },
- Some(e) => {
- Err(uv_error_to_io_error(e))
- }
- };
- unsafe { (*result_cell_ptr).put_back(res); }
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- };
- };
- };
- assert!(!result_cell.is_empty());
- return result_cell.take();
- }
-
- fn spawn(&mut self, config: ProcessConfig)
- -> Result<(~RtioProcess, ~[Option<~RtioPipe>]), IoError>
- {
- // Sadly, we must create the UvProcess before we actually call uv_spawn
- // so that the exit_cb can close over it and notify it when the process
- // has exited.
- let mut ret = ~UvProcess {
- process: Process::new(),
- home: None,
- exit_status: None,
- term_signal: None,
- exit_error: None,
- descheduled: None,
- };
- let ret_ptr = unsafe {
- *cast::transmute::<&~UvProcess, &*mut UvProcess>(&ret)
- };
-
- // The purpose of this exit callback is to record the data about the
- // exit and then wake up the task which may be waiting for the process
- // to exit. This is all performed in the current io-loop, and the
- // implementation of UvProcess ensures that reading these fields always
- // occurs on the current io-loop.
- let exit_cb: ExitCallback = |_, exit_status, term_signal, error| {
- unsafe {
- assert!((*ret_ptr).exit_status.is_none());
- (*ret_ptr).exit_status = Some(exit_status);
- (*ret_ptr).term_signal = Some(term_signal);
- (*ret_ptr).exit_error = error;
- match (*ret_ptr).descheduled.take() {
- Some(task) => {
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task);
- }
- None => {}
- }
- }
- };
-
- match ret.process.spawn(self.uv_loop(), config, exit_cb) {
- Ok(io) => {
- // Only now do we actually get a handle to this scheduler.
- ret.home = Some(get_handle_to_current_scheduler!());
- Ok((ret as ~RtioProcess,
- io.move_iter().map(|p| p.map(|p| p as ~RtioPipe)).collect()))
- }
- Err(uverr) => {
- // We still need to close the process handle we created, but
- // that's taken care for us in the destructor of UvProcess
- Err(uv_error_to_io_error(uverr))
- }
- }
- }
-
- fn unix_bind(&mut self, path: &CString) ->
- Result<~RtioUnixListener, IoError> {
- let mut pipe = UvUnboundPipe::new(self.uv_loop());
- match pipe.pipe.bind(path) {
- Ok(()) => Ok(~UvUnixListener::new(pipe) as ~RtioUnixListener),
- Err(e) => Err(uv_error_to_io_error(e)),
- }
- }
-
- fn unix_connect(&mut self, path: &CString) -> Result<~RtioPipe, IoError> {
- let pipe = UvUnboundPipe::new(self.uv_loop());
- let mut rawpipe = pipe.pipe;
-
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<~RtioPipe, IoError>> = &result_cell;
- let pipe_cell = Cell::new(pipe);
- let pipe_cell_ptr: *Cell<UvUnboundPipe> = &pipe_cell;
-
- let scheduler: ~Scheduler = Local::take();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- do rawpipe.connect(path) |_stream, err| {
- let res = match err {
- None => {
- let pipe = unsafe { (*pipe_cell_ptr).take() };
- Ok(~UvPipeStream::new(pipe) as ~RtioPipe)
- }
- Some(e) => Err(uv_error_to_io_error(e)),
- };
- unsafe { (*result_cell_ptr).put_back(res); }
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
-
- assert!(!result_cell.is_empty());
- return result_cell.take();
- }
-
- fn tty_open(&mut self, fd: c_int, readable: bool)
- -> Result<~RtioTTY, IoError> {
- match tty::TTY::new(self.uv_loop(), fd, readable) {
- Ok(tty) => Ok(~UvTTY {
- home: get_handle_to_current_scheduler!(),
- tty: tty,
- fd: fd,
- } as ~RtioTTY),
- Err(e) => Err(uv_error_to_io_error(e))
- }
- }
-
- fn pipe_open(&mut self, fd: c_int) -> Result<~RtioPipe, IoError> {
- let mut pipe = UvUnboundPipe::new(self.uv_loop());
- match pipe.pipe.open(fd) {
- Ok(()) => Ok(~UvPipeStream::new(pipe) as ~RtioPipe),
- Err(e) => Err(uv_error_to_io_error(e))
- }
- }
-
- fn signal(&mut self, signum: Signum, channel: SharedChan<Signum>)
- -> Result<~RtioSignal, IoError> {
- let watcher = SignalWatcher::new(self.uv_loop());
- let home = get_handle_to_current_scheduler!();
- let mut signal = ~UvSignal::new(watcher, home);
- match signal.watcher.start(signum, |_, _| channel.send_deferred(signum)) {
- Ok(()) => Ok(signal as ~RtioSignal),
- Err(e) => Err(uv_error_to_io_error(e)),
- }
- }
-}
-
-pub struct UvTcpListener {
- priv watcher : TcpWatcher,
- priv home: SchedHandle,
-}
-
-impl HomingIO for UvTcpListener {
- fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
-}
-
-impl UvTcpListener {
- fn new(watcher: TcpWatcher, home: SchedHandle) -> UvTcpListener {
- UvTcpListener { watcher: watcher, home: home }
- }
-}
-
-impl Drop for UvTcpListener {
- fn drop(&mut self) {
- do self.home_for_io_with_sched |self_, scheduler| {
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task = Cell::new(task);
- do self_.watcher.as_stream().close {
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task.take());
- }
- }
- }
- }
-}
-
-impl RtioSocket for UvTcpListener {
- fn socket_name(&mut self) -> Result<SocketAddr, IoError> {
- do self.home_for_io |self_| {
- socket_name(Tcp, self_.watcher)
- }
- }
-}
-
-impl RtioTcpListener for UvTcpListener {
- fn listen(~self) -> Result<~RtioTcpAcceptor, IoError> {
- do self.home_for_io_consume |self_| {
- let acceptor = ~UvTcpAcceptor::new(self_);
- let incoming = Cell::new(acceptor.incoming.clone());
- let mut stream = acceptor.listener.watcher.as_stream();
- let res = do stream.listen |mut server, status| {
- do incoming.with_mut_ref |incoming| {
- let inc = match status {
- Some(_) => Err(standard_error(OtherIoError)),
- None => {
- let inc = TcpWatcher::new(&server.event_loop());
- // first accept call in the callback guarenteed to succeed
- server.accept(inc.as_stream());
- let home = get_handle_to_current_scheduler!();
- Ok(~UvTcpStream { watcher: inc, home: home }
- as ~RtioTcpStream)
- }
- };
- incoming.send(inc);
- }
- };
- match res {
- Ok(()) => Ok(acceptor as ~RtioTcpAcceptor),
- Err(e) => Err(uv_error_to_io_error(e)),
- }
- }
- }
-}
-
-pub struct UvTcpAcceptor {
- priv listener: UvTcpListener,
- priv incoming: Tube<Result<~RtioTcpStream, IoError>>,
-}
-
-impl HomingIO for UvTcpAcceptor {
- fn home<'r>(&'r mut self) -> &'r mut SchedHandle { self.listener.home() }
-}
-
-impl UvTcpAcceptor {
- fn new(listener: UvTcpListener) -> UvTcpAcceptor {
- UvTcpAcceptor { listener: listener, incoming: Tube::new() }
- }
-}
-
-impl RtioSocket for UvTcpAcceptor {
- fn socket_name(&mut self) -> Result<SocketAddr, IoError> {
- do self.home_for_io |self_| {
- socket_name(Tcp, self_.listener.watcher)
- }
- }
-}
-
-fn accept_simultaneously(stream: StreamWatcher, a: int) -> Result<(), IoError> {
- let r = unsafe {
- uvll::tcp_simultaneous_accepts(stream.native_handle(), a as c_int)
- };
-
- match status_to_maybe_uv_error(r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
- }
-}
-
-impl RtioTcpAcceptor for UvTcpAcceptor {
- fn accept(&mut self) -> Result<~RtioTcpStream, IoError> {
- do self.home_for_io |self_| {
- self_.incoming.recv()
- }
- }
-
- fn accept_simultaneously(&mut self) -> Result<(), IoError> {
- do self.home_for_io |self_| {
- accept_simultaneously(self_.listener.watcher.as_stream(), 1)
- }
- }
-
- fn dont_accept_simultaneously(&mut self) -> Result<(), IoError> {
- do self.home_for_io |self_| {
- accept_simultaneously(self_.listener.watcher.as_stream(), 0)
- }
- }
-}
-
-fn read_stream(mut watcher: StreamWatcher,
- scheduler: ~Scheduler,
- buf: &mut [u8]) -> Result<uint, IoError> {
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<uint, IoError>> = &result_cell;
-
- let buf_ptr: *&mut [u8] = &buf;
- do scheduler.deschedule_running_task_and_then |_sched, task| {
- let task_cell = Cell::new(task);
- // XXX: We shouldn't reallocate these callbacks every
- // call to read
- let alloc: AllocCallback = |_| unsafe {
- slice_to_uv_buf(*buf_ptr)
- };
- do watcher.read_start(alloc) |mut watcher, nread, _buf, status| {
-
- // Stop reading so that no read callbacks are
- // triggered before the user calls `read` again.
- // XXX: Is there a performance impact to calling
- // stop here?
- watcher.read_stop();
-
- let result = if status.is_none() {
- assert!(nread >= 0);
- Ok(nread as uint)
- } else {
- Err(uv_error_to_io_error(status.unwrap()))
- };
-
- unsafe { (*result_cell_ptr).put_back(result); }
-
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
-
- assert!(!result_cell.is_empty());
- result_cell.take()
-}
-
-fn write_stream(mut watcher: StreamWatcher,
- scheduler: ~Scheduler,
- buf: &[u8]) -> Result<(), IoError> {
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
- let buf_ptr: *&[u8] = &buf;
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
- do watcher.write(buf) |_watcher, status| {
- let result = if status.is_none() {
- Ok(())
- } else {
- Err(uv_error_to_io_error(status.unwrap()))
- };
-
- unsafe { (*result_cell_ptr).put_back(result); }
-
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
-
- assert!(!result_cell.is_empty());
- result_cell.take()
-}
-
-pub struct UvUnboundPipe {
- pipe: Pipe,
- priv home: SchedHandle,
-}
-
-impl UvUnboundPipe {
- /// Creates a new unbound pipe homed to the current scheduler, placed on the
- /// specified event loop
- pub fn new(loop_: &Loop) -> UvUnboundPipe {
- UvUnboundPipe {
- pipe: Pipe::new(loop_, false),
- home: get_handle_to_current_scheduler!(),
- }
- }
-}
-
-impl HomingIO for UvUnboundPipe {
- fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
-}
-
-impl Drop for UvUnboundPipe {
- fn drop(&mut self) {
- do self.home_for_io |self_| {
- let scheduler: ~Scheduler = Local::take();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- do self_.pipe.close {
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
- }
- }
-}
-
-pub struct UvPipeStream {
- priv inner: UvUnboundPipe,
-}
-
-impl UvPipeStream {
- pub fn new(inner: UvUnboundPipe) -> UvPipeStream {
- UvPipeStream { inner: inner }
- }
-}
-
-impl RtioPipe for UvPipeStream {
- fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
- do self.inner.home_for_io_with_sched |self_, scheduler| {
- read_stream(self_.pipe.as_stream(), scheduler, buf)
- }
- }
- fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
- do self.inner.home_for_io_with_sched |self_, scheduler| {
- write_stream(self_.pipe.as_stream(), scheduler, buf)
- }
- }
-}
-
-pub struct UvTcpStream {
- priv watcher: TcpWatcher,
- priv home: SchedHandle,
-}
-
-impl HomingIO for UvTcpStream {
- fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
-}
-
-impl Drop for UvTcpStream {
- fn drop(&mut self) {
- do self.home_for_io_with_sched |self_, scheduler| {
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- do self_.watcher.as_stream().close {
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
- }
- }
-}
-
-impl RtioSocket for UvTcpStream {
- fn socket_name(&mut self) -> Result<SocketAddr, IoError> {
- do self.home_for_io |self_| {
- socket_name(Tcp, self_.watcher)
- }
- }
-}
-
-impl RtioTcpStream for UvTcpStream {
- fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
- do self.home_for_io_with_sched |self_, scheduler| {
- read_stream(self_.watcher.as_stream(), scheduler, buf)
- }
- }
-
- fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
- do self.home_for_io_with_sched |self_, scheduler| {
- write_stream(self_.watcher.as_stream(), scheduler, buf)
- }
- }
-
- fn peer_name(&mut self) -> Result<SocketAddr, IoError> {
- do self.home_for_io |self_| {
- socket_name(TcpPeer, self_.watcher)
- }
- }
-
- fn control_congestion(&mut self) -> Result<(), IoError> {
- do self.home_for_io |self_| {
- let r = unsafe { uvll::tcp_nodelay(self_.watcher.native_handle(), 0 as c_int) };
-
- match status_to_maybe_uv_error(r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
- }
- }
- }
-
- fn nodelay(&mut self) -> Result<(), IoError> {
- do self.home_for_io |self_| {
- let r = unsafe { uvll::tcp_nodelay(self_.watcher.native_handle(), 1 as c_int) };
-
- match status_to_maybe_uv_error(r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
- }
- }
- }
-
- fn keepalive(&mut self, delay_in_seconds: uint) -> Result<(), IoError> {
- do self.home_for_io |self_| {
- let r = unsafe {
- uvll::tcp_keepalive(self_.watcher.native_handle(), 1 as c_int,
- delay_in_seconds as c_uint)
- };
-
- match status_to_maybe_uv_error(r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
- }
- }
- }
-
- fn letdie(&mut self) -> Result<(), IoError> {
- do self.home_for_io |self_| {
- let r = unsafe {
- uvll::tcp_keepalive(self_.watcher.native_handle(), 0 as c_int, 0 as c_uint)
- };
-
- match status_to_maybe_uv_error(r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
- }
- }
- }
-}
-
-pub struct UvUdpSocket {
- priv watcher: UdpWatcher,
- priv home: SchedHandle,
-}
-
-impl HomingIO for UvUdpSocket {
- fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
-}
-
-impl Drop for UvUdpSocket {
- fn drop(&mut self) {
- do self.home_for_io_with_sched |self_, scheduler| {
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- do self_.watcher.close {
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
- }
- }
-}
-
-impl RtioSocket for UvUdpSocket {
- fn socket_name(&mut self) -> Result<SocketAddr, IoError> {
- do self.home_for_io |self_| {
- socket_name(Udp, self_.watcher)
- }
- }
-}
-
-impl RtioUdpSocket for UvUdpSocket {
- fn recvfrom(&mut self, buf: &mut [u8]) -> Result<(uint, SocketAddr), IoError> {
- do self.home_for_io_with_sched |self_, scheduler| {
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<(uint, SocketAddr), IoError>> = &result_cell;
-
- let buf_ptr: *&mut [u8] = &buf;
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- let alloc: AllocCallback = |_| unsafe { slice_to_uv_buf(*buf_ptr) };
- do self_.watcher.recv_start(alloc) |mut watcher, nread, _buf, addr, flags, status| {
- let _ = flags; // /XXX add handling for partials?
-
- watcher.recv_stop();
-
- let result = match status {
- None => {
- assert!(nread >= 0);
- Ok((nread as uint, addr))
- }
- Some(err) => Err(uv_error_to_io_error(err)),
- };
-
- unsafe { (*result_cell_ptr).put_back(result); }
-
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
-
- assert!(!result_cell.is_empty());
- result_cell.take()
- }
- }
-
- fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> Result<(), IoError> {
- do self.home_for_io_with_sched |self_, scheduler| {
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
- let buf_ptr: *&[u8] = &buf;
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
- do self_.watcher.send(buf, dst) |_watcher, status| {
-
- let result = match status {
- None => Ok(()),
- Some(err) => Err(uv_error_to_io_error(err)),
- };
-
- unsafe { (*result_cell_ptr).put_back(result); }
-
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
-
- assert!(!result_cell.is_empty());
- result_cell.take()
- }
- }
-
- fn join_multicast(&mut self, multi: IpAddr) -> Result<(), IoError> {
- do self.home_for_io |self_| {
- let r = unsafe {
- do multi.to_str().with_c_str |m_addr| {
- uvll::udp_set_membership(self_.watcher.native_handle(), m_addr,
- ptr::null(), uvll::UV_JOIN_GROUP)
- }
- };
-
- match status_to_maybe_uv_error(r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
- }
- }
- }
-
- fn leave_multicast(&mut self, multi: IpAddr) -> Result<(), IoError> {
- do self.home_for_io |self_| {
- let r = unsafe {
- do multi.to_str().with_c_str |m_addr| {
- uvll::udp_set_membership(self_.watcher.native_handle(), m_addr,
- ptr::null(), uvll::UV_LEAVE_GROUP)
- }
- };
-
- match status_to_maybe_uv_error(r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
- }
- }
- }
-
- fn loop_multicast_locally(&mut self) -> Result<(), IoError> {
- do self.home_for_io |self_| {
-
- let r = unsafe {
- uvll::udp_set_multicast_loop(self_.watcher.native_handle(), 1 as c_int)
- };
-
- match status_to_maybe_uv_error(r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
- }
- }
- }
-
- fn dont_loop_multicast_locally(&mut self) -> Result<(), IoError> {
- do self.home_for_io |self_| {
-
- let r = unsafe {
- uvll::udp_set_multicast_loop(self_.watcher.native_handle(), 0 as c_int)
- };
-
- match status_to_maybe_uv_error(r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
- }
- }
- }
-
- fn multicast_time_to_live(&mut self, ttl: int) -> Result<(), IoError> {
- do self.home_for_io |self_| {
-
- let r = unsafe {
- uvll::udp_set_multicast_ttl(self_.watcher.native_handle(), ttl as c_int)
- };
-
- match status_to_maybe_uv_error(r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
- }
- }
- }
-
- fn time_to_live(&mut self, ttl: int) -> Result<(), IoError> {
- do self.home_for_io |self_| {
-
- let r = unsafe {
- uvll::udp_set_ttl(self_.watcher.native_handle(), ttl as c_int)
- };
-
- match status_to_maybe_uv_error(r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
- }
- }
- }
-
- fn hear_broadcasts(&mut self) -> Result<(), IoError> {
- do self.home_for_io |self_| {
-
- let r = unsafe {
- uvll::udp_set_broadcast(self_.watcher.native_handle(), 1 as c_int)
- };
-
- match status_to_maybe_uv_error(r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
- }
- }
- }
-
- fn ignore_broadcasts(&mut self) -> Result<(), IoError> {
- do self.home_for_io |self_| {
-
- let r = unsafe {
- uvll::udp_set_broadcast(self_.watcher.native_handle(), 0 as c_int)
- };
-
- match status_to_maybe_uv_error(r) {
- Some(err) => Err(uv_error_to_io_error(err)),
- None => Ok(())
- }
- }
- }
-}
-
-pub struct UvTimer {
- priv watcher: timer::TimerWatcher,
- priv home: SchedHandle,
-}
-
-impl HomingIO for UvTimer {
- fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
-}
-
-impl UvTimer {
- fn new(w: timer::TimerWatcher, home: SchedHandle) -> UvTimer {
- UvTimer { watcher: w, home: home }
- }
-}
-
-impl Drop for UvTimer {
- fn drop(&mut self) {
- do self.home_for_io_with_sched |self_, scheduler| {
- rtdebug!("closing UvTimer");
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- do self_.watcher.close {
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
- }
- }
-}
-
-impl RtioTimer for UvTimer {
- fn sleep(&mut self, msecs: u64) {
- do self.home_for_io_with_sched |self_, scheduler| {
- do scheduler.deschedule_running_task_and_then |_sched, task| {
- rtdebug!("sleep: entered scheduler context");
- let task_cell = Cell::new(task);
- do self_.watcher.start(msecs, 0) |_, status| {
- assert!(status.is_none());
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
- self_.watcher.stop();
- }
- }
-
- fn oneshot(&mut self, msecs: u64) -> PortOne<()> {
- use comm::oneshot;
-
- let (port, chan) = oneshot();
- let chan = Cell::new(chan);
- do self.home_for_io |self_| {
- let chan = Cell::new(chan.take());
- do self_.watcher.start(msecs, 0) |_, status| {
- assert!(status.is_none());
- assert!(!chan.is_empty());
- chan.take().send_deferred(());
- }
- }
-
- return port;
- }
-
- fn period(&mut self, msecs: u64) -> Port<()> {
- use comm::stream;
-
- let (port, chan) = stream();
- let chan = Cell::new(chan);
- do self.home_for_io |self_| {
- let chan = Cell::new(chan.take());
- do self_.watcher.start(msecs, msecs) |_, status| {
- assert!(status.is_none());
- do chan.with_ref |chan| {
- chan.send_deferred(());
- }
- }
- }
-
- return port;
- }
-}
-
-pub struct UvFileStream {
- priv loop_: Loop,
- priv fd: c_int,
- priv close: CloseBehavior,
- priv home: SchedHandle,
-}
-
-impl HomingIO for UvFileStream {
- fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
-}
-
-impl UvFileStream {
- fn new(loop_: Loop, fd: c_int, close: CloseBehavior,
- home: SchedHandle) -> UvFileStream {
- UvFileStream {
- loop_: loop_,
- fd: fd,
- close: close,
- home: home,
- }
- }
- fn base_read(&mut self, buf: &mut [u8], offset: i64) -> Result<int, IoError> {
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<int, IoError>> = &result_cell;
- let buf_ptr: *&mut [u8] = &buf;
- do self.home_for_io_with_sched |self_, scheduler| {
- do scheduler.deschedule_running_task_and_then |_, task| {
- let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
- let task_cell = Cell::new(task);
- let read_req = file::FsRequest::new();
- do read_req.read(&self_.loop_, self_.fd, buf, offset) |req, uverr| {
- let res = match uverr {
- None => Ok(req.get_result() as int),
- Some(err) => Err(uv_error_to_io_error(err))
- };
- unsafe { (*result_cell_ptr).put_back(res); }
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
- }
- result_cell.take()
- }
- fn base_write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError> {
- let result_cell = Cell::new_empty();
- let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
- let buf_ptr: *&[u8] = &buf;
- do self.home_for_io_with_sched |self_, scheduler| {
- do scheduler.deschedule_running_task_and_then |_, task| {
- let buf = unsafe { slice_to_uv_buf(*buf_ptr) };
- let task_cell = Cell::new(task);
- let write_req = file::FsRequest::new();
- do write_req.write(&self_.loop_, self_.fd, buf, offset) |_, uverr| {
- let res = match uverr {
- None => Ok(()),
- Some(err) => Err(uv_error_to_io_error(err))
- };
- unsafe { (*result_cell_ptr).put_back(res); }
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
- }
- result_cell.take()
- }
- fn seek_common(&mut self, pos: i64, whence: c_int) ->
- Result<u64, IoError>{
- #[fixed_stack_segment]; #[inline(never)];
- unsafe {
- match lseek(self.fd, pos as off_t, whence) {
- -1 => {
- Err(IoError {
- kind: OtherIoError,
- desc: "Failed to lseek.",
- detail: None
- })
- },
- n => Ok(n as u64)
- }
- }
- }
-}
-
-impl Drop for UvFileStream {
- fn drop(&mut self) {
- match self.close {
- DontClose => {}
- CloseAsynchronously => {
- let close_req = file::FsRequest::new();
- do close_req.close(&self.loop_, self.fd) |_,_| {}
- }
- CloseSynchronously => {
- do self.home_for_io_with_sched |self_, scheduler| {
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- let close_req = file::FsRequest::new();
- do close_req.close(&self_.loop_, self_.fd) |_,_| {
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
- }
- }
- }
- }
-}
-
-impl RtioFileStream for UvFileStream {
- fn read(&mut self, buf: &mut [u8]) -> Result<int, IoError> {
- self.base_read(buf, -1)
- }
- fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
- self.base_write(buf, -1)
- }
- fn pread(&mut self, buf: &mut [u8], offset: u64) -> Result<int, IoError> {
- self.base_read(buf, offset as i64)
- }
- fn pwrite(&mut self, buf: &[u8], offset: u64) -> Result<(), IoError> {
- self.base_write(buf, offset as i64)
- }
- fn seek(&mut self, pos: i64, whence: SeekStyle) -> Result<u64, IoError> {
- use libc::{SEEK_SET, SEEK_CUR, SEEK_END};
- let whence = match whence {
- SeekSet => SEEK_SET,
- SeekCur => SEEK_CUR,
- SeekEnd => SEEK_END
- };
- self.seek_common(pos, whence)
- }
- fn tell(&self) -> Result<u64, IoError> {
- use libc::SEEK_CUR;
- // this is temporary
- let self_ = unsafe { cast::transmute::<&UvFileStream, &mut UvFileStream>(self) };
- self_.seek_common(0, SEEK_CUR)
- }
- fn flush(&mut self) -> Result<(), IoError> {
- Ok(())
- }
-}
-
-pub struct UvProcess {
- priv process: process::Process,
-
- // Sadly, this structure must be created before we return it, so in that
- // brief interim the `home` is None.
- priv home: Option<SchedHandle>,
-
- // All None until the process exits (exit_error may stay None)
- priv exit_status: Option<int>,
- priv term_signal: Option<int>,
- priv exit_error: Option<UvError>,
-
- // Used to store which task to wake up from the exit_cb
- priv descheduled: Option<BlockedTask>,
-}
-
-impl HomingIO for UvProcess {
- fn home<'r>(&'r mut self) -> &'r mut SchedHandle { self.home.get_mut_ref() }
-}
-
-impl Drop for UvProcess {
- fn drop(&mut self) {
- let close = |self_: &mut UvProcess| {
- let scheduler: ~Scheduler = Local::take();
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task = Cell::new(task);
- do self_.process.close {
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task.take());
- }
- }
- };
-
- // If home is none, then this process never actually successfully
- // spawned, so there's no need to switch event loops
- if self.home.is_none() {
- close(self)
- } else {
- self.home_for_io(close)
- }
- }
-}
-
-impl RtioProcess for UvProcess {
- fn id(&self) -> pid_t {
- self.process.pid()
- }
-
- fn kill(&mut self, signal: int) -> Result<(), IoError> {
- do self.home_for_io |self_| {
- match self_.process.kill(signal) {
- Ok(()) => Ok(()),
- Err(uverr) => Err(uv_error_to_io_error(uverr))
- }
- }
- }
-
- fn wait(&mut self) -> int {
- // Make sure (on the home scheduler) that we have an exit status listed
- do self.home_for_io |self_| {
- match self_.exit_status {
- Some(*) => {}
- None => {
- // If there's no exit code previously listed, then the
- // process's exit callback has yet to be invoked. We just
- // need to deschedule ourselves and wait to be reawoken.
- let scheduler: ~Scheduler = Local::take();
- do scheduler.deschedule_running_task_and_then |_, task| {
- assert!(self_.descheduled.is_none());
- self_.descheduled = Some(task);
- }
- assert!(self_.exit_status.is_some());
- }
- }
- }
-
- self.exit_status.unwrap()
- }
-}
-
-pub struct UvUnixListener {
- priv inner: UvUnboundPipe
-}
-
-impl HomingIO for UvUnixListener {
- fn home<'r>(&'r mut self) -> &'r mut SchedHandle { self.inner.home() }
-}
-
-impl UvUnixListener {
- fn new(pipe: UvUnboundPipe) -> UvUnixListener {
- UvUnixListener { inner: pipe }
- }
-}
-
-impl RtioUnixListener for UvUnixListener {
- fn listen(~self) -> Result<~RtioUnixAcceptor, IoError> {
- do self.home_for_io_consume |self_| {
- let acceptor = ~UvUnixAcceptor::new(self_);
- let incoming = Cell::new(acceptor.incoming.clone());
- let mut stream = acceptor.listener.inner.pipe.as_stream();
- let res = do stream.listen |mut server, status| {
- do incoming.with_mut_ref |incoming| {
- let inc = match status {
- Some(e) => Err(uv_error_to_io_error(e)),
- None => {
- let pipe = UvUnboundPipe::new(&server.event_loop());
- server.accept(pipe.pipe.as_stream());
- Ok(~UvPipeStream::new(pipe) as ~RtioPipe)
- }
- };
- incoming.send(inc);
- }
- };
- match res {
- Ok(()) => Ok(acceptor as ~RtioUnixAcceptor),
- Err(e) => Err(uv_error_to_io_error(e)),
- }
- }
- }
-}
-
-pub struct UvTTY {
- tty: tty::TTY,
- home: SchedHandle,
- fd: c_int,
-}
-
-impl HomingIO for UvTTY {
- fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
-}
-
-impl Drop for UvTTY {
- fn drop(&mut self) {
- // TTY handles are used for the logger in a task, so this destructor is
- // run when a task is destroyed. When a task is being destroyed, a local
- // scheduler isn't available, so we can't do the normal "take the
- // scheduler and resume once close is done". Instead close operations on
- // a TTY are asynchronous.
- self.tty.close_async();
- }
-}
-
-impl RtioTTY for UvTTY {
- fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> {
- do self.home_for_io_with_sched |self_, scheduler| {
- read_stream(self_.tty.as_stream(), scheduler, buf)
- }
- }
-
- fn write(&mut self, buf: &[u8]) -> Result<(), IoError> {
- do self.home_for_io_with_sched |self_, scheduler| {
- write_stream(self_.tty.as_stream(), scheduler, buf)
- }
- }
-
- fn set_raw(&mut self, raw: bool) -> Result<(), IoError> {
- do self.home_for_io |self_| {
- match self_.tty.set_mode(raw) {
- Ok(p) => Ok(p), Err(e) => Err(uv_error_to_io_error(e))
- }
- }
- }
-
- fn get_winsize(&mut self) -> Result<(int, int), IoError> {
- do self.home_for_io |self_| {
- match self_.tty.get_winsize() {
- Ok(p) => Ok(p), Err(e) => Err(uv_error_to_io_error(e))
- }
- }
- }
-
- fn isatty(&self) -> bool {
- unsafe { uvll::guess_handle(self.fd) == uvll::UV_TTY as c_int }
- }
-}
-
-pub struct UvUnixAcceptor {
- listener: UvUnixListener,
- incoming: Tube<Result<~RtioPipe, IoError>>,
-}
-
-impl HomingIO for UvUnixAcceptor {
- fn home<'r>(&'r mut self) -> &'r mut SchedHandle { self.listener.home() }
-}
-
-impl UvUnixAcceptor {
- fn new(listener: UvUnixListener) -> UvUnixAcceptor {
- UvUnixAcceptor { listener: listener, incoming: Tube::new() }
- }
-}
-
-impl RtioUnixAcceptor for UvUnixAcceptor {
- fn accept(&mut self) -> Result<~RtioPipe, IoError> {
- do self.home_for_io |self_| {
- self_.incoming.recv()
- }
- }
-
- fn accept_simultaneously(&mut self) -> Result<(), IoError> {
- do self.home_for_io |self_| {
- accept_simultaneously(self_.listener.inner.pipe.as_stream(), 1)
- }
- }
-
- fn dont_accept_simultaneously(&mut self) -> Result<(), IoError> {
- do self.home_for_io |self_| {
- accept_simultaneously(self_.listener.inner.pipe.as_stream(), 0)
- }
- }
-}
-
-pub struct UvSignal {
- watcher: signal::SignalWatcher,
- home: SchedHandle,
-}
-
-impl HomingIO for UvSignal {
- fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
-}
-
-impl UvSignal {
- fn new(w: signal::SignalWatcher, home: SchedHandle) -> UvSignal {
- UvSignal { watcher: w, home: home }
- }
-}
-
-impl RtioSignal for UvSignal {}
-
-impl Drop for UvSignal {
- fn drop(&mut self) {
- do self.home_for_io_with_sched |self_, scheduler| {
- rtdebug!("closing UvSignal");
- do scheduler.deschedule_running_task_and_then |_, task| {
- let task_cell = Cell::new(task);
- do self_.watcher.close {
- let scheduler: ~Scheduler = Local::take();
- scheduler.resume_blocked_task_immediately(task_cell.take());
- }
- }
- }
- }
-}
-
-// this function is full of lies
-unsafe fn local_io() -> &'static mut IoFactory {
- do Local::borrow |sched: &mut Scheduler| {
- let mut io = None;
- sched.event_loop.io(|i| io = Some(i));
- cast::transmute(io.unwrap())
- }
-}
-
-#[test]
-fn test_simple_io_no_connect() {
- do run_in_mt_newsched_task {
- unsafe {
- let io = local_io();
- let addr = next_test_ip4();
- let maybe_chan = io.tcp_connect(addr);
- assert!(maybe_chan.is_err());
- }
- }
-}
-
-#[test]
-fn test_simple_udp_io_bind_only() {
- do run_in_mt_newsched_task {
- unsafe {
- let io = local_io();
- let addr = next_test_ip4();
- let maybe_socket = io.udp_bind(addr);
- assert!(maybe_socket.is_ok());
- }
- }
-}
-
-#[test]
-fn test_simple_homed_udp_io_bind_then_move_task_then_home_and_close() {
- use rt::sleeper_list::SleeperList;
- use rt::work_queue::WorkQueue;
- use rt::thread::Thread;
- use rt::task::Task;
- use rt::sched::{Shutdown, TaskFromFriend};
- use rt::task::UnwindResult;
- do run_in_bare_thread {
- let sleepers = SleeperList::new();
- let work_queue1 = WorkQueue::new();
- let work_queue2 = WorkQueue::new();
- let queues = ~[work_queue1.clone(), work_queue2.clone()];
-
- let loop1 = ~UvEventLoop::new() as ~EventLoop;
- let mut sched1 = ~Scheduler::new(loop1, work_queue1, queues.clone(),
- sleepers.clone());
- let loop2 = ~UvEventLoop::new() as ~EventLoop;
- let mut sched2 = ~Scheduler::new(loop2, work_queue2, queues.clone(),
- sleepers.clone());
-
- let handle1 = Cell::new(sched1.make_handle());
- let handle2 = Cell::new(sched2.make_handle());
- let tasksFriendHandle = Cell::new(sched2.make_handle());
-
- let on_exit: ~fn(UnwindResult) = |exit_status| {
- handle1.take().send(Shutdown);
- handle2.take().send(Shutdown);
- rtassert!(exit_status.is_success());
- };
-
- let test_function: ~fn() = || {
- let io = unsafe { local_io() };
- let addr = next_test_ip4();
- let maybe_socket = io.udp_bind(addr);
- // this socket is bound to this event loop
- assert!(maybe_socket.is_ok());
-
- // block self on sched1
- do task::unkillable { // FIXME(#8674)
- let scheduler: ~Scheduler = Local::take();
- do scheduler.deschedule_running_task_and_then |_, task| {
- // unblock task
- do task.wake().map |task| {
- // send self to sched2
- tasksFriendHandle.take().send(TaskFromFriend(task));
- };
- // sched1 should now sleep since it has nothing else to do
- }
- }
- // sched2 will wake up and get the task
- // as we do nothing else, the function ends and the socket goes out of scope
- // sched2 will start to run the destructor
- // the destructor will first block the task, set it's home as sched1, then enqueue it
- // sched2 will dequeue the task, see that it has a home, and send it to sched1
- // sched1 will wake up, exec the close function on the correct loop, and then we're done
- };
-
- let mut main_task = ~Task::new_root(&mut sched1.stack_pool, None, test_function);
- main_task.death.on_exit = Some(on_exit);
- let main_task = Cell::new(main_task);
-
- let null_task = Cell::new(~do Task::new_root(&mut sched2.stack_pool, None) || {});
-
- let sched1 = Cell::new(sched1);
- let sched2 = Cell::new(sched2);
-
- let thread1 = do Thread::start {
- sched1.take().bootstrap(main_task.take());
- };
- let thread2 = do Thread::start {
- sched2.take().bootstrap(null_task.take());
- };
-
- thread1.join();
- thread2.join();
- }
-}
-
-#[test]
-fn test_simple_homed_udp_io_bind_then_move_handle_then_home_and_close() {
- use rt::sleeper_list::SleeperList;
- use rt::work_queue::WorkQueue;
- use rt::thread::Thread;
- use rt::task::Task;
- use rt::comm::oneshot;
- use rt::sched::Shutdown;
- use rt::task::UnwindResult;
- do run_in_bare_thread {
- let sleepers = SleeperList::new();
- let work_queue1 = WorkQueue::new();
- let work_queue2 = WorkQueue::new();
- let queues = ~[work_queue1.clone(), work_queue2.clone()];
-
- let loop1 = ~UvEventLoop::new() as ~EventLoop;
- let mut sched1 = ~Scheduler::new(loop1, work_queue1, queues.clone(),
- sleepers.clone());
- let loop2 = ~UvEventLoop::new() as ~EventLoop;
- let mut sched2 = ~Scheduler::new(loop2, work_queue2, queues.clone(),
- sleepers.clone());
-
- let handle1 = Cell::new(sched1.make_handle());
- let handle2 = Cell::new(sched2.make_handle());
-
- let (port, chan) = oneshot();
- let port = Cell::new(port);
- let chan = Cell::new(chan);
-
- let body1: ~fn() = || {
- let io = unsafe { local_io() };
- let addr = next_test_ip4();
- let socket = io.udp_bind(addr);
- assert!(socket.is_ok());
- chan.take().send(socket);
- };
-
- let body2: ~fn() = || {
- let socket = port.take().recv();
- assert!(socket.is_ok());
- /* The socket goes out of scope and the destructor is called.
- * The destructor:
- * - sends itself back to sched1
- * - frees the socket
- * - resets the home of the task to whatever it was previously
- */
- };
-
- let on_exit: ~fn(UnwindResult) = |exit| {
- handle1.take().send(Shutdown);
- handle2.take().send(Shutdown);
- rtassert!(exit.is_success());
- };
-
- let task1 = Cell::new(~Task::new_root(&mut sched1.stack_pool, None, body1));
-
- let mut task2 = ~Task::new_root(&mut sched2.stack_pool, None, body2);
- task2.death.on_exit = Some(on_exit);
- let task2 = Cell::new(task2);
-
- let sched1 = Cell::new(sched1);
- let sched2 = Cell::new(sched2);
-
- let thread1 = do Thread::start {
- sched1.take().bootstrap(task1.take());
- };
- let thread2 = do Thread::start {
- sched2.take().bootstrap(task2.take());
- };
-
- thread1.join();
- thread2.join();
- }
-}
-
-#[test]
-fn test_simple_tcp_server_and_client() {
- do run_in_mt_newsched_task {
- let addr = next_test_ip4();
- let (port, chan) = oneshot();
- let port = Cell::new(port);
- let chan = Cell::new(chan);
-
- // Start the server first so it's listening when we connect
- do spawntask {
- unsafe {
- let io = local_io();
- let listener = io.tcp_bind(addr).unwrap();
- let mut acceptor = listener.listen().unwrap();
- chan.take().send(());
- let mut stream = acceptor.accept().unwrap();
- let mut buf = [0, .. 2048];
- let nread = stream.read(buf).unwrap();
- assert_eq!(nread, 8);
- for i in range(0u, nread) {
- rtdebug!("{}", buf[i]);
- assert_eq!(buf[i], i as u8);
- }
- }
- }
-
- do spawntask {
- unsafe {
- port.take().recv();
- let io = local_io();
- let mut stream = io.tcp_connect(addr).unwrap();
- stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
- }
- }
- }
-}
-
-#[test]
-fn test_simple_tcp_server_and_client_on_diff_threads() {
- use rt::sleeper_list::SleeperList;
- use rt::work_queue::WorkQueue;
- use rt::thread::Thread;
- use rt::task::Task;
- use rt::sched::{Shutdown};
- use rt::task::UnwindResult;
- do run_in_bare_thread {
- let sleepers = SleeperList::new();
-
- let server_addr = next_test_ip4();
- let client_addr = server_addr.clone();
-
- let server_work_queue = WorkQueue::new();
- let client_work_queue = WorkQueue::new();
- let queues = ~[server_work_queue.clone(), client_work_queue.clone()];
-
- let sloop = ~UvEventLoop::new() as ~EventLoop;
- let mut server_sched = ~Scheduler::new(sloop, server_work_queue,
- queues.clone(), sleepers.clone());
- let cloop = ~UvEventLoop::new() as ~EventLoop;
- let mut client_sched = ~Scheduler::new(cloop, client_work_queue,
- queues.clone(), sleepers.clone());
-
- let server_handle = Cell::new(server_sched.make_handle());
- let client_handle = Cell::new(client_sched.make_handle());
-
- let server_on_exit: ~fn(UnwindResult) = |exit_status| {
- server_handle.take().send(Shutdown);
- rtassert!(exit_status.is_success());
- };
-
- let client_on_exit: ~fn(UnwindResult) = |exit_status| {
- client_handle.take().send(Shutdown);
- rtassert!(exit_status.is_success());
- };
-
- let server_fn: ~fn() = || {
- let io = unsafe { local_io() };
- let listener = io.tcp_bind(server_addr).unwrap();
- let mut acceptor = listener.listen().unwrap();
- let mut stream = acceptor.accept().unwrap();
- let mut buf = [0, .. 2048];
- let nread = stream.read(buf).unwrap();
- assert_eq!(nread, 8);
- for i in range(0u, nread) {
- assert_eq!(buf[i], i as u8);
- }
- };
-
- let client_fn: ~fn() = || {
- let io = unsafe { local_io() };
- let mut stream = io.tcp_connect(client_addr);
- while stream.is_err() {
- stream = io.tcp_connect(client_addr);
- }
- stream.unwrap().write([0, 1, 2, 3, 4, 5, 6, 7]);
- };
-
- let mut server_task = ~Task::new_root(&mut server_sched.stack_pool, None, server_fn);
- server_task.death.on_exit = Some(server_on_exit);
- let server_task = Cell::new(server_task);
-
- let mut client_task = ~Task::new_root(&mut client_sched.stack_pool, None, client_fn);
- client_task.death.on_exit = Some(client_on_exit);
- let client_task = Cell::new(client_task);
-
- let server_sched = Cell::new(server_sched);
- let client_sched = Cell::new(client_sched);
-
- let server_thread = do Thread::start {
- server_sched.take().bootstrap(server_task.take());
- };
- let client_thread = do Thread::start {
- client_sched.take().bootstrap(client_task.take());
- };
-
- server_thread.join();
- client_thread.join();
- }
-}
-
-#[test]
-fn test_simple_udp_server_and_client() {
- do run_in_mt_newsched_task {
- let server_addr = next_test_ip4();
- let client_addr = next_test_ip4();
- let (port, chan) = oneshot();
- let port = Cell::new(port);
- let chan = Cell::new(chan);
-
- do spawntask {
- unsafe {
- let io = local_io();
- let mut server_socket = io.udp_bind(server_addr).unwrap();
- chan.take().send(());
- let mut buf = [0, .. 2048];
- let (nread,src) = server_socket.recvfrom(buf).unwrap();
- assert_eq!(nread, 8);
- for i in range(0u, nread) {
- rtdebug!("{}", buf[i]);
- assert_eq!(buf[i], i as u8);
- }
- assert_eq!(src, client_addr);
- }
- }
-
- do spawntask {
- unsafe {
- let io = local_io();
- let mut client_socket = io.udp_bind(client_addr).unwrap();
- port.take().recv();
- client_socket.sendto([0, 1, 2, 3, 4, 5, 6, 7], server_addr);
- }
- }
- }
-}
-
-#[test] #[ignore(reason = "busted")]
-fn test_read_and_block() {
- do run_in_mt_newsched_task {
- let addr = next_test_ip4();
- let (port, chan) = oneshot();
- let port = Cell::new(port);
- let chan = Cell::new(chan);
-
- do spawntask {
- let io = unsafe { local_io() };
- let listener = io.tcp_bind(addr).unwrap();
- let mut acceptor = listener.listen().unwrap();
- chan.take().send(());
- let mut stream = acceptor.accept().unwrap();
- let mut buf = [0, .. 2048];
-
- let expected = 32;
- let mut current = 0;
- let mut reads = 0;
-
- while current < expected {
- let nread = stream.read(buf).unwrap();
- for i in range(0u, nread) {
- let val = buf[i] as uint;
- assert_eq!(val, current % 8);
- current += 1;
- }
- reads += 1;
-
- do task::unkillable { // FIXME(#8674)
- let scheduler: ~Scheduler = Local::take();
- // Yield to the other task in hopes that it
- // will trigger a read callback while we are
- // not ready for it
- do scheduler.deschedule_running_task_and_then |sched, task| {
- let task = Cell::new(task);
- sched.enqueue_blocked_task(task.take());
- }
- }
- }
-
- // Make sure we had multiple reads
- assert!(reads > 1);
- }
-
- do spawntask {
- unsafe {
- port.take().recv();
- let io = local_io();
- let mut stream = io.tcp_connect(addr).unwrap();
- stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
- stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
- stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
- stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
- }
- }
-
- }
-}
-
-#[test]
-fn test_read_read_read() {
- do run_in_mt_newsched_task {
- let addr = next_test_ip4();
- static MAX: uint = 500000;
- let (port, chan) = oneshot();
- let port = Cell::new(port);
- let chan = Cell::new(chan);
-
- do spawntask {
- unsafe {
- let io = local_io();
- let listener = io.tcp_bind(addr).unwrap();
- let mut acceptor = listener.listen().unwrap();
- chan.take().send(());
- let mut stream = acceptor.accept().unwrap();
- let buf = [1, .. 2048];
- let mut total_bytes_written = 0;
- while total_bytes_written < MAX {
- stream.write(buf);
- total_bytes_written += buf.len();
- }
- }
- }
-
- do spawntask {
- unsafe {
- port.take().recv();
- let io = local_io();
- let mut stream = io.tcp_connect(addr).unwrap();
- let mut buf = [0, .. 2048];
- let mut total_bytes_read = 0;
- while total_bytes_read < MAX {
- let nread = stream.read(buf).unwrap();
- rtdebug!("read {} bytes", nread);
- total_bytes_read += nread;
- for i in range(0u, nread) {
- assert_eq!(buf[i], 1);
- }
- }
- rtdebug!("read {} bytes total", total_bytes_read);
- }
- }
- }
-}
-
-#[test]
-#[ignore(cfg(windows))] // FIXME(#10102) the server never sees the second send
-fn test_udp_twice() {
- do run_in_mt_newsched_task {
- let server_addr = next_test_ip4();
- let client_addr = next_test_ip4();
- let (port, chan) = oneshot();
- let port = Cell::new(port);
- let chan = Cell::new(chan);
-
- do spawntask {
- unsafe {
- let io = local_io();
- let mut client = io.udp_bind(client_addr).unwrap();
- port.take().recv();
- assert!(client.sendto([1], server_addr).is_ok());
- assert!(client.sendto([2], server_addr).is_ok());
- }
- }
-
- do spawntask {
- unsafe {
- let io = local_io();
- let mut server = io.udp_bind(server_addr).unwrap();
- chan.take().send(());
- let mut buf1 = [0];
- let mut buf2 = [0];
- let (nread1, src1) = server.recvfrom(buf1).unwrap();
- let (nread2, src2) = server.recvfrom(buf2).unwrap();
- assert_eq!(nread1, 1);
- assert_eq!(nread2, 1);
- assert_eq!(src1, client_addr);
- assert_eq!(src2, client_addr);
- assert_eq!(buf1[0], 1);
- assert_eq!(buf2[0], 2);
- }
- }
- }
-}
-
-#[test]
-fn test_udp_many_read() {
- do run_in_mt_newsched_task {
- let server_out_addr = next_test_ip4();
- let server_in_addr = next_test_ip4();
- let client_out_addr = next_test_ip4();
- let client_in_addr = next_test_ip4();
- static MAX: uint = 500_000;
-
- let (p1, c1) = oneshot();
- let (p2, c2) = oneshot();
-
- let first = Cell::new((p1, c2));
- let second = Cell::new((p2, c1));
-
- do spawntask {
- unsafe {
- let io = local_io();
- let mut server_out = io.udp_bind(server_out_addr).unwrap();
- let mut server_in = io.udp_bind(server_in_addr).unwrap();
- let (port, chan) = first.take();
- chan.send(());
- port.recv();
- let msg = [1, .. 2048];
- let mut total_bytes_sent = 0;
- let mut buf = [1];
- while buf[0] == 1 {
- // send more data
- assert!(server_out.sendto(msg, client_in_addr).is_ok());
- total_bytes_sent += msg.len();
- // check if the client has received enough
- let res = server_in.recvfrom(buf);
- assert!(res.is_ok());
- let (nread, src) = res.unwrap();
- assert_eq!(nread, 1);
- assert_eq!(src, client_out_addr);
- }
- assert!(total_bytes_sent >= MAX);
- }
- }
-
- do spawntask {
- unsafe {
- let io = local_io();
- let mut client_out = io.udp_bind(client_out_addr).unwrap();
- let mut client_in = io.udp_bind(client_in_addr).unwrap();
- let (port, chan) = second.take();
- port.recv();
- chan.send(());
- let mut total_bytes_recv = 0;
- let mut buf = [0, .. 2048];
- while total_bytes_recv < MAX {
- // ask for more
- assert!(client_out.sendto([1], server_in_addr).is_ok());
- // wait for data
- let res = client_in.recvfrom(buf);
- assert!(res.is_ok());
- let (nread, src) = res.unwrap();
- assert_eq!(src, server_out_addr);
- total_bytes_recv += nread;
- for i in range(0u, nread) {
- assert_eq!(buf[i], 1);
- }
- }
- // tell the server we're done
- assert!(client_out.sendto([0], server_in_addr).is_ok());
- }
- }
- }
-}
-
-#[test]
-fn test_timer_sleep_simple() {
- do run_in_mt_newsched_task {
- unsafe {
- let io = local_io();
- let timer = io.timer_init();
- do timer.map_move |mut t| { t.sleep(1) };
- }
- }
-}
-
-fn file_test_uvio_full_simple_impl() {
- use str::StrSlice; // why does this have to be explicitly imported to work?
- // compiler was complaining about no trait for str that
- // does .as_bytes() ..
- use rt::io::{Open, Create, ReadWrite, Read};
- unsafe {
- let io = local_io();
- let write_val = "hello uvio!";
- let path = "./tmp/file_test_uvio_full.txt";
- {
- let create_fm = Create;
- let create_fa = ReadWrite;
- let mut fd = io.fs_open(&path.to_c_str(), create_fm, create_fa).unwrap();
- let write_buf = write_val.as_bytes();
- fd.write(write_buf);
- }
- {
- let ro_fm = Open;
- let ro_fa = Read;
- let mut fd = io.fs_open(&path.to_c_str(), ro_fm, ro_fa).unwrap();
- let mut read_vec = [0, .. 1028];
- let nread = fd.read(read_vec).unwrap();
- let read_val = str::from_utf8(read_vec.slice(0, nread as uint));
- assert!(read_val == write_val.to_owned());
- }
- io.fs_unlink(&path.to_c_str());
- }
-}
-
-#[test]
-fn file_test_uvio_full_simple() {
- do run_in_mt_newsched_task {
- file_test_uvio_full_simple_impl();
- }
-}
-
-fn uvio_naive_print(input: &str) {
- use str::StrSlice;
- unsafe {
- use libc::{STDOUT_FILENO};
- let io = local_io();
- {
- let mut fd = io.fs_from_raw_fd(STDOUT_FILENO, DontClose);
- let write_buf = input.as_bytes();
- fd.write(write_buf);
- }
- }
-}
-
-#[test]
-fn file_test_uvio_write_to_stdout() {
- do run_in_mt_newsched_task {
- uvio_naive_print("jubilation\n");
- }
-}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*!
- * Low-level bindings to the libuv library.
- *
- * This module contains a set of direct, 'bare-metal' wrappers around
- * the libuv C-API.
- *
- * We're not bothering yet to redefine uv's structs as Rust structs
- * because they are quite large and change often between versions.
- * The maintenance burden is just too high. Instead we use the uv's
- * `uv_handle_size` and `uv_req_size` to find the correct size of the
- * structs and allocate them on the heap. This can be revisited later.
- *
- * There are also a collection of helper functions to ease interacting
- * with the low-level API.
- *
- * As new functionality, existent in uv.h, is added to the rust stdlib,
- * the mappings should be added in this module.
- */
-
-#[allow(non_camel_case_types)]; // C types
-
-use c_str::ToCStr;
-use libc::{size_t, c_int, c_uint, c_void, c_char, uintptr_t};
-use libc::ssize_t;
-use libc::{malloc, free};
-use libc;
-use prelude::*;
-use ptr;
-use vec;
-
-pub use self::errors::*;
-
-pub static OK: c_int = 0;
-pub static EOF: c_int = -4095;
-pub static UNKNOWN: c_int = -4094;
-
-// uv-errno.h redefines error codes for windows, but not for unix...
-
-#[cfg(windows)]
-pub mod errors {
- use libc::c_int;
-
- pub static EACCES: c_int = -4093;
- pub static ECONNREFUSED: c_int = -4079;
- pub static ECONNRESET: c_int = -4078;
- pub static ENOTCONN: c_int = -4054;
- pub static EPIPE: c_int = -4048;
- pub static ECONNABORTED: c_int = -4080;
-}
-#[cfg(not(windows))]
-pub mod errors {
- use libc;
- use libc::c_int;
-
- pub static EACCES: c_int = -libc::EACCES;
- pub static ECONNREFUSED: c_int = -libc::ECONNREFUSED;
- pub static ECONNRESET: c_int = -libc::ECONNRESET;
- pub static ENOTCONN: c_int = -libc::ENOTCONN;
- pub static EPIPE: c_int = -libc::EPIPE;
- pub static ECONNABORTED: c_int = -libc::ECONNABORTED;
-}
-
-pub static PROCESS_SETUID: c_int = 1 << 0;
-pub static PROCESS_SETGID: c_int = 1 << 1;
-pub static PROCESS_WINDOWS_VERBATIM_ARGUMENTS: c_int = 1 << 2;
-pub static PROCESS_DETACHED: c_int = 1 << 3;
-pub static PROCESS_WINDOWS_HIDE: c_int = 1 << 4;
-
-pub static STDIO_IGNORE: c_int = 0x00;
-pub static STDIO_CREATE_PIPE: c_int = 0x01;
-pub static STDIO_INHERIT_FD: c_int = 0x02;
-pub static STDIO_INHERIT_STREAM: c_int = 0x04;
-pub static STDIO_READABLE_PIPE: c_int = 0x10;
-pub static STDIO_WRITABLE_PIPE: c_int = 0x20;
-
-// see libuv/include/uv-unix.h
-#[cfg(unix)]
-pub struct uv_buf_t {
- base: *u8,
- len: libc::size_t,
-}
-
-// see libuv/include/uv-win.h
-#[cfg(windows)]
-pub struct uv_buf_t {
- len: u32,
- base: *u8,
-}
-
-pub struct uv_process_options_t {
- exit_cb: uv_exit_cb,
- file: *libc::c_char,
- args: **libc::c_char,
- env: **libc::c_char,
- cwd: *libc::c_char,
- flags: libc::c_uint,
- stdio_count: libc::c_int,
- stdio: *uv_stdio_container_t,
- uid: uv_uid_t,
- gid: uv_gid_t,
-}
-
-// These fields are private because they must be interfaced with through the
-// functions below.
-pub struct uv_stdio_container_t {
- priv flags: libc::c_int,
- priv stream: *uv_stream_t,
-}
-
-pub type uv_handle_t = c_void;
-pub type uv_loop_t = c_void;
-pub type uv_idle_t = c_void;
-pub type uv_tcp_t = c_void;
-pub type uv_udp_t = c_void;
-pub type uv_connect_t = c_void;
-pub type uv_connection_t = c_void;
-pub type uv_write_t = c_void;
-pub type uv_async_t = c_void;
-pub type uv_timer_t = c_void;
-pub type uv_stream_t = c_void;
-pub type uv_fs_t = c_void;
-pub type uv_udp_send_t = c_void;
-pub type uv_getaddrinfo_t = c_void;
-pub type uv_process_t = c_void;
-pub type uv_pipe_t = c_void;
-pub type uv_tty_t = c_void;
-pub type uv_signal_t = c_void;
-
-pub struct uv_timespec_t {
- tv_sec: libc::c_long,
- priv tv_nsec: libc::c_long
-}
-
-pub struct uv_stat_t {
- st_dev: libc::uint64_t,
- st_mode: libc::uint64_t,
- priv st_nlink: libc::uint64_t,
- priv st_uid: libc::uint64_t,
- priv st_gid: libc::uint64_t,
- priv st_rdev: libc::uint64_t,
- st_ino: libc::uint64_t,
- st_size: libc::uint64_t,
- priv st_blksize: libc::uint64_t,
- priv st_blocks: libc::uint64_t,
- priv st_flags: libc::uint64_t,
- priv st_gen: libc::uint64_t,
- st_atim: uv_timespec_t,
- st_mtim: uv_timespec_t,
- st_ctim: uv_timespec_t,
- priv st_birthtim: uv_timespec_t
-}
-
-impl uv_stat_t {
- pub fn new() -> uv_stat_t {
- uv_stat_t {
- st_dev: 0,
- st_mode: 0,
- st_nlink: 0,
- st_uid: 0,
- st_gid: 0,
- st_rdev: 0,
- st_ino: 0,
- st_size: 0,
- st_blksize: 0,
- st_blocks: 0,
- st_flags: 0,
- st_gen: 0,
- st_atim: uv_timespec_t { tv_sec: 0, tv_nsec: 0 },
- st_mtim: uv_timespec_t { tv_sec: 0, tv_nsec: 0 },
- st_ctim: uv_timespec_t { tv_sec: 0, tv_nsec: 0 },
- st_birthtim: uv_timespec_t { tv_sec: 0, tv_nsec: 0 }
- }
- }
- pub fn is_file(&self) -> bool {
- ((self.st_mode) & libc::S_IFMT as libc::uint64_t) == libc::S_IFREG as libc::uint64_t
- }
- pub fn is_dir(&self) -> bool {
- ((self.st_mode) & libc::S_IFMT as libc::uint64_t) == libc::S_IFDIR as libc::uint64_t
- }
-}
-
-pub type uv_idle_cb = extern "C" fn(handle: *uv_idle_t,
- status: c_int);
-pub type uv_alloc_cb = extern "C" fn(stream: *uv_stream_t,
- suggested_size: size_t) -> uv_buf_t;
-pub type uv_read_cb = extern "C" fn(stream: *uv_stream_t,
- nread: ssize_t,
- buf: uv_buf_t);
-pub type uv_udp_send_cb = extern "C" fn(req: *uv_udp_send_t,
- status: c_int);
-pub type uv_udp_recv_cb = extern "C" fn(handle: *uv_udp_t,
- nread: ssize_t,
- buf: uv_buf_t,
- addr: *sockaddr,
- flags: c_uint);
-pub type uv_close_cb = extern "C" fn(handle: *uv_handle_t);
-pub type uv_walk_cb = extern "C" fn(handle: *uv_handle_t,
- arg: *c_void);
-pub type uv_async_cb = extern "C" fn(handle: *uv_async_t,
- status: c_int);
-pub type uv_connect_cb = extern "C" fn(handle: *uv_connect_t,
- status: c_int);
-pub type uv_connection_cb = extern "C" fn(handle: *uv_connection_t,
- status: c_int);
-pub type uv_timer_cb = extern "C" fn(handle: *uv_timer_t,
- status: c_int);
-pub type uv_write_cb = extern "C" fn(handle: *uv_write_t,
- status: c_int);
-pub type uv_getaddrinfo_cb = extern "C" fn(req: *uv_getaddrinfo_t,
- status: c_int,
- res: *addrinfo);
-pub type uv_exit_cb = extern "C" fn(handle: *uv_process_t,
- exit_status: c_int,
- term_signal: c_int);
-pub type uv_signal_cb = extern "C" fn(handle: *uv_signal_t,
- signum: c_int);
-
-pub type sockaddr = c_void;
-pub type sockaddr_in = c_void;
-pub type sockaddr_in6 = c_void;
-pub type sockaddr_storage = c_void;
-
-#[cfg(unix)]
-pub type socklen_t = c_int;
-
-// XXX: This is a standard C type. Could probably be defined in libc
-#[cfg(target_os = "android")]
-#[cfg(target_os = "linux")]
-pub struct addrinfo {
- ai_flags: c_int,
- ai_family: c_int,
- ai_socktype: c_int,
- ai_protocol: c_int,
- ai_addrlen: socklen_t,
- ai_addr: *sockaddr,
- ai_canonname: *char,
- ai_next: *addrinfo
-}
-
-#[cfg(target_os = "macos")]
-#[cfg(target_os = "freebsd")]
-pub struct addrinfo {
- ai_flags: c_int,
- ai_family: c_int,
- ai_socktype: c_int,
- ai_protocol: c_int,
- ai_addrlen: socklen_t,
- ai_canonname: *char,
- ai_addr: *sockaddr,
- ai_next: *addrinfo
-}
-
-#[cfg(windows)]
-pub struct addrinfo {
- ai_flags: c_int,
- ai_family: c_int,
- ai_socktype: c_int,
- ai_protocol: c_int,
- ai_addrlen: size_t,
- ai_canonname: *char,
- ai_addr: *sockaddr,
- ai_next: *addrinfo
-}
-
-#[cfg(unix)] pub type uv_uid_t = libc::types::os::arch::posix88::uid_t;
-#[cfg(unix)] pub type uv_gid_t = libc::types::os::arch::posix88::gid_t;
-#[cfg(windows)] pub type uv_uid_t = libc::c_uchar;
-#[cfg(windows)] pub type uv_gid_t = libc::c_uchar;
-
-#[deriving(Eq)]
-pub enum uv_handle_type {
- UV_UNKNOWN_HANDLE,
- UV_ASYNC,
- UV_CHECK,
- UV_FS_EVENT,
- UV_FS_POLL,
- UV_HANDLE,
- UV_IDLE,
- UV_NAMED_PIPE,
- UV_POLL,
- UV_PREPARE,
- UV_PROCESS,
- UV_STREAM,
- UV_TCP,
- UV_TIMER,
- UV_TTY,
- UV_UDP,
- UV_SIGNAL,
- UV_FILE,
- UV_HANDLE_TYPE_MAX
-}
-
-#[cfg(unix)]
-#[deriving(Eq)]
-pub enum uv_req_type {
- UV_UNKNOWN_REQ,
- UV_REQ,
- UV_CONNECT,
- UV_WRITE,
- UV_SHUTDOWN,
- UV_UDP_SEND,
- UV_FS,
- UV_WORK,
- UV_GETADDRINFO,
- UV_REQ_TYPE_MAX
-}
-
-// uv_req_type may have additional fields defined by UV_REQ_TYPE_PRIVATE.
-// See UV_REQ_TYPE_PRIVATE at libuv/include/uv-win.h
-#[cfg(windows)]
-#[deriving(Eq)]
-pub enum uv_req_type {
- UV_UNKNOWN_REQ,
- UV_REQ,
- UV_CONNECT,
- UV_WRITE,
- UV_SHUTDOWN,
- UV_UDP_SEND,
- UV_FS,
- UV_WORK,
- UV_GETADDRINFO,
- UV_ACCEPT,
- UV_FS_EVENT_REQ,
- UV_POLL_REQ,
- UV_PROCESS_EXIT,
- UV_READ,
- UV_UDP_RECV,
- UV_WAKEUP,
- UV_SIGNAL_REQ,
- UV_REQ_TYPE_MAX
-}
-
-#[deriving(Eq)]
-pub enum uv_membership {
- UV_LEAVE_GROUP,
- UV_JOIN_GROUP
-}
-
-pub unsafe fn malloc_handle(handle: uv_handle_type) -> *c_void {
- #[fixed_stack_segment]; #[inline(never)];
-
- assert!(handle != UV_UNKNOWN_HANDLE && handle != UV_HANDLE_TYPE_MAX);
- let size = rust_uv_handle_size(handle as uint);
- let p = malloc(size);
- assert!(p.is_not_null());
- return p;
-}
-
-pub unsafe fn free_handle(v: *c_void) {
- #[fixed_stack_segment]; #[inline(never)];
-
- free(v)
-}
-
-pub unsafe fn malloc_req(req: uv_req_type) -> *c_void {
- #[fixed_stack_segment]; #[inline(never)];
-
- assert!(req != UV_UNKNOWN_REQ && req != UV_REQ_TYPE_MAX);
- let size = rust_uv_req_size(req as uint);
- let p = malloc(size);
- assert!(p.is_not_null());
- return p;
-}
-
-pub unsafe fn free_req(v: *c_void) {
- #[fixed_stack_segment]; #[inline(never)];
-
- free(v)
-}
-
-#[test]
-fn handle_sanity_check() {
- #[fixed_stack_segment]; #[inline(never)];
- unsafe {
- assert_eq!(UV_HANDLE_TYPE_MAX as uint, rust_uv_handle_type_max());
- }
-}
-
-#[test]
-fn request_sanity_check() {
- #[fixed_stack_segment]; #[inline(never)];
- unsafe {
- assert_eq!(UV_REQ_TYPE_MAX as uint, rust_uv_req_type_max());
- }
-}
-
-// XXX Event loops ignore SIGPIPE by default.
-pub unsafe fn loop_new() -> *c_void {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_loop_new();
-}
-
-pub unsafe fn loop_delete(loop_handle: *c_void) {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_loop_delete(loop_handle);
-}
-
-pub unsafe fn run(loop_handle: *c_void) {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_run(loop_handle);
-}
-
-pub unsafe fn close<T>(handle: *T, cb: uv_close_cb) {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_close(handle as *c_void, cb);
-}
-
-pub unsafe fn walk(loop_handle: *c_void, cb: uv_walk_cb, arg: *c_void) {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_walk(loop_handle, cb, arg);
-}
-
-pub unsafe fn idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_idle_init(loop_handle, handle)
-}
-
-pub unsafe fn idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_idle_start(handle, cb)
-}
-
-pub unsafe fn idle_stop(handle: *uv_idle_t) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_idle_stop(handle)
-}
-
-pub unsafe fn udp_init(loop_handle: *uv_loop_t, handle: *uv_udp_t) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_udp_init(loop_handle, handle);
-}
-
-pub unsafe fn udp_bind(server: *uv_udp_t, addr: *sockaddr_in, flags: c_uint) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_udp_bind(server, addr, flags);
-}
-
-pub unsafe fn udp_bind6(server: *uv_udp_t, addr: *sockaddr_in6, flags: c_uint) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_udp_bind6(server, addr, flags);
-}
-
-pub unsafe fn udp_send<T>(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t],
- addr: *sockaddr_in, cb: uv_udp_send_cb) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- let buf_ptr = vec::raw::to_ptr(buf_in);
- let buf_cnt = buf_in.len() as i32;
- return rust_uv_udp_send(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb);
-}
-
-pub unsafe fn udp_send6<T>(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t],
- addr: *sockaddr_in6, cb: uv_udp_send_cb) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- let buf_ptr = vec::raw::to_ptr(buf_in);
- let buf_cnt = buf_in.len() as i32;
- return rust_uv_udp_send6(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb);
-}
-
-pub unsafe fn udp_recv_start(server: *uv_udp_t, on_alloc: uv_alloc_cb,
- on_recv: uv_udp_recv_cb) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_udp_recv_start(server, on_alloc, on_recv);
-}
-
-pub unsafe fn udp_recv_stop(server: *uv_udp_t) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_udp_recv_stop(server);
-}
-
-pub unsafe fn get_udp_handle_from_send_req(send_req: *uv_udp_send_t) -> *uv_udp_t {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_get_udp_handle_from_send_req(send_req);
-}
-
-pub unsafe fn udp_getsockname(handle: *uv_udp_t, name: *sockaddr_storage) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_udp_getsockname(handle, name);
-}
-
-pub unsafe fn udp_set_membership(handle: *uv_udp_t, multicast_addr: *c_char,
- interface_addr: *c_char, membership: uv_membership) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_udp_set_membership(handle, multicast_addr, interface_addr, membership as c_int);
-}
-
-pub unsafe fn udp_set_multicast_loop(handle: *uv_udp_t, on: c_int) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_udp_set_multicast_loop(handle, on);
-}
-
-pub unsafe fn udp_set_multicast_ttl(handle: *uv_udp_t, ttl: c_int) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_udp_set_multicast_ttl(handle, ttl);
-}
-
-pub unsafe fn udp_set_ttl(handle: *uv_udp_t, ttl: c_int) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_udp_set_ttl(handle, ttl);
-}
-
-pub unsafe fn udp_set_broadcast(handle: *uv_udp_t, on: c_int) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_udp_set_broadcast(handle, on);
-}
-
-pub unsafe fn tcp_init(loop_handle: *c_void, handle: *uv_tcp_t) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_tcp_init(loop_handle, handle);
-}
-
-pub unsafe fn tcp_connect(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t,
- addr_ptr: *sockaddr_in, after_connect_cb: uv_connect_cb) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_tcp_connect(connect_ptr, tcp_handle_ptr, after_connect_cb, addr_ptr);
-}
-
-pub unsafe fn tcp_connect6(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t,
- addr_ptr: *sockaddr_in6, after_connect_cb: uv_connect_cb) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_tcp_connect6(connect_ptr, tcp_handle_ptr, after_connect_cb, addr_ptr);
-}
-
-pub unsafe fn tcp_bind(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_tcp_bind(tcp_server_ptr, addr_ptr);
-}
-
-pub unsafe fn tcp_bind6(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in6) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_tcp_bind6(tcp_server_ptr, addr_ptr);
-}
-
-pub unsafe fn tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_storage) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_tcp_getpeername(tcp_handle_ptr, name);
-}
-
-pub unsafe fn tcp_getsockname(handle: *uv_tcp_t, name: *sockaddr_storage) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_tcp_getsockname(handle, name);
-}
-
-pub unsafe fn tcp_nodelay(handle: *uv_tcp_t, enable: c_int) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_tcp_nodelay(handle, enable);
-}
-
-pub unsafe fn tcp_keepalive(handle: *uv_tcp_t, enable: c_int, delay: c_uint) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_tcp_keepalive(handle, enable, delay);
-}
-
-pub unsafe fn tcp_simultaneous_accepts(handle: *uv_tcp_t, enable: c_int) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_tcp_simultaneous_accepts(handle, enable);
-}
-
-pub unsafe fn listen<T>(stream: *T, backlog: c_int,
- cb: uv_connection_cb) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_listen(stream as *c_void, backlog, cb);
-}
-
-pub unsafe fn accept(server: *c_void, client: *c_void) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_accept(server as *c_void, client as *c_void);
-}
-
-pub unsafe fn write<T>(req: *uv_write_t,
- stream: *T,
- buf_in: &[uv_buf_t],
- cb: uv_write_cb) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- let buf_ptr = vec::raw::to_ptr(buf_in);
- let buf_cnt = buf_in.len() as i32;
- return rust_uv_write(req as *c_void, stream as *c_void, buf_ptr, buf_cnt, cb);
-}
-pub unsafe fn read_start(stream: *uv_stream_t,
- on_alloc: uv_alloc_cb,
- on_read: uv_read_cb) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_read_start(stream as *c_void, on_alloc, on_read);
-}
-
-pub unsafe fn read_stop(stream: *uv_stream_t) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_read_stop(stream as *c_void);
-}
-
-pub unsafe fn strerror(err: c_int) -> *c_char {
- #[fixed_stack_segment]; #[inline(never)];
- return rust_uv_strerror(err);
-}
-pub unsafe fn err_name(err: c_int) -> *c_char {
- #[fixed_stack_segment]; #[inline(never)];
- return rust_uv_err_name(err);
-}
-
-pub unsafe fn async_init(loop_handle: *c_void,
- async_handle: *uv_async_t,
- cb: uv_async_cb) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_async_init(loop_handle, async_handle, cb);
-}
-
-pub unsafe fn async_send(async_handle: *uv_async_t) {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_async_send(async_handle);
-}
-pub unsafe fn buf_init(input: *u8, len: uint) -> uv_buf_t {
- #[fixed_stack_segment]; #[inline(never)];
-
- let out_buf = uv_buf_t { base: ptr::null(), len: 0 as size_t };
- let out_buf_ptr = ptr::to_unsafe_ptr(&out_buf);
- rust_uv_buf_init(out_buf_ptr, input, len as size_t);
- return out_buf;
-}
-
-pub unsafe fn timer_init(loop_ptr: *c_void, timer_ptr: *uv_timer_t) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_timer_init(loop_ptr, timer_ptr);
-}
-pub unsafe fn timer_start(timer_ptr: *uv_timer_t,
- cb: uv_timer_cb, timeout: u64,
- repeat: u64) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_timer_start(timer_ptr, cb, timeout, repeat);
-}
-pub unsafe fn timer_stop(timer_ptr: *uv_timer_t) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_timer_stop(timer_ptr);
-}
-
-pub unsafe fn is_ip4_addr(addr: *sockaddr) -> bool {
- #[fixed_stack_segment]; #[inline(never)];
-
- match rust_uv_is_ipv4_sockaddr(addr) { 0 => false, _ => true }
-}
-
-pub unsafe fn is_ip6_addr(addr: *sockaddr) -> bool {
- #[fixed_stack_segment]; #[inline(never)];
-
- match rust_uv_is_ipv6_sockaddr(addr) { 0 => false, _ => true }
-}
-
-pub unsafe fn malloc_ip4_addr(ip: &str, port: int) -> *sockaddr_in {
- #[fixed_stack_segment]; #[inline(never)];
- do ip.with_c_str |ip_buf| {
- rust_uv_ip4_addrp(ip_buf as *u8, port as libc::c_int)
- }
-}
-pub unsafe fn malloc_ip6_addr(ip: &str, port: int) -> *sockaddr_in6 {
- #[fixed_stack_segment]; #[inline(never)];
- do ip.with_c_str |ip_buf| {
- rust_uv_ip6_addrp(ip_buf as *u8, port as libc::c_int)
- }
-}
-
-pub unsafe fn malloc_sockaddr_storage() -> *sockaddr_storage {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_malloc_sockaddr_storage()
-}
-
-pub unsafe fn free_sockaddr_storage(ss: *sockaddr_storage) {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_free_sockaddr_storage(ss);
-}
-
-pub unsafe fn free_ip4_addr(addr: *sockaddr_in) {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_free_ip4_addr(addr);
-}
-
-pub unsafe fn free_ip6_addr(addr: *sockaddr_in6) {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_free_ip6_addr(addr);
-}
-
-pub unsafe fn ip4_name(addr: *sockaddr_in, dst: *u8, size: size_t) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_ip4_name(addr, dst, size);
-}
-
-pub unsafe fn ip6_name(addr: *sockaddr_in6, dst: *u8, size: size_t) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_ip6_name(addr, dst, size);
-}
-
-pub unsafe fn ip4_port(addr: *sockaddr_in) -> c_uint {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_ip4_port(addr);
-}
-
-pub unsafe fn ip6_port(addr: *sockaddr_in6) -> c_uint {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_ip6_port(addr);
-}
-
-pub unsafe fn fs_open(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, flags: int, mode: int,
- cb: *u8) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_fs_open(loop_ptr, req, path, flags as c_int, mode as c_int, cb)
-}
-
-pub unsafe fn fs_unlink(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char,
- cb: *u8) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_fs_unlink(loop_ptr, req, path, cb)
-}
-pub unsafe fn fs_write(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, buf: *c_void,
- len: uint, offset: i64, cb: *u8) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_fs_write(loop_ptr, req, fd, buf, len as c_uint, offset, cb)
-}
-pub unsafe fn fs_read(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, buf: *c_void,
- len: uint, offset: i64, cb: *u8) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_fs_read(loop_ptr, req, fd, buf, len as c_uint, offset, cb)
-}
-pub unsafe fn fs_close(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int,
- cb: *u8) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_fs_close(loop_ptr, req, fd, cb)
-}
-pub unsafe fn fs_stat(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, cb: *u8) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_fs_stat(loop_ptr, req, path, cb)
-}
-pub unsafe fn fs_fstat(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, cb: *u8) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_fs_fstat(loop_ptr, req, fd, cb)
-}
-pub unsafe fn fs_mkdir(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, mode: int,
- cb: *u8) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_fs_mkdir(loop_ptr, req, path, mode as c_int, cb)
-}
-pub unsafe fn fs_rmdir(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char,
- cb: *u8) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_fs_rmdir(loop_ptr, req, path, cb)
-}
-pub unsafe fn fs_readdir(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char,
- flags: c_int, cb: *u8) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_fs_readdir(loop_ptr, req, path, flags, cb)
-}
-pub unsafe fn populate_stat(req_in: *uv_fs_t, stat_out: *uv_stat_t) {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_populate_uv_stat(req_in, stat_out)
-}
-pub unsafe fn fs_req_cleanup(req: *uv_fs_t) {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_fs_req_cleanup(req);
-}
-
-pub unsafe fn spawn(loop_ptr: *c_void, result: *uv_process_t,
- options: uv_process_options_t) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
- return rust_uv_spawn(loop_ptr, result, options);
-}
-
-pub unsafe fn process_kill(p: *uv_process_t, signum: c_int) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
- return rust_uv_process_kill(p, signum);
-}
-
-pub unsafe fn process_pid(p: *uv_process_t) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
- return rust_uv_process_pid(p);
-}
-
-pub unsafe fn set_stdio_container_flags(c: *uv_stdio_container_t,
- flags: libc::c_int) {
- #[fixed_stack_segment]; #[inline(never)];
- rust_set_stdio_container_flags(c, flags);
-}
-
-pub unsafe fn set_stdio_container_fd(c: *uv_stdio_container_t,
- fd: libc::c_int) {
- #[fixed_stack_segment]; #[inline(never)];
- rust_set_stdio_container_fd(c, fd);
-}
-
-pub unsafe fn set_stdio_container_stream(c: *uv_stdio_container_t,
- stream: *uv_stream_t) {
- #[fixed_stack_segment]; #[inline(never)];
- rust_set_stdio_container_stream(c, stream);
-}
-
-pub unsafe fn pipe_init(loop_ptr: *c_void, p: *uv_pipe_t, ipc: c_int) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
- rust_uv_pipe_init(loop_ptr, p, ipc)
-}
-
-// data access helpers
-pub unsafe fn get_result_from_fs_req(req: *uv_fs_t) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_get_result_from_fs_req(req)
-}
-pub unsafe fn get_ptr_from_fs_req(req: *uv_fs_t) -> *libc::c_void {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_get_ptr_from_fs_req(req)
-}
-pub unsafe fn get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_get_loop_from_fs_req(req)
-}
-pub unsafe fn get_loop_from_getaddrinfo_req(req: *uv_getaddrinfo_t) -> *uv_loop_t {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_get_loop_from_getaddrinfo_req(req)
-}
-pub unsafe fn get_loop_for_uv_handle<T>(handle: *T) -> *c_void {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_get_loop_for_uv_handle(handle as *c_void);
-}
-pub unsafe fn get_stream_handle_from_connect_req(connect: *uv_connect_t) -> *uv_stream_t {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_get_stream_handle_from_connect_req(connect);
-}
-pub unsafe fn get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_get_stream_handle_from_write_req(write_req);
-}
-pub unsafe fn get_data_for_uv_loop(loop_ptr: *c_void) -> *c_void {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_get_data_for_uv_loop(loop_ptr)
-}
-pub unsafe fn set_data_for_uv_loop(loop_ptr: *c_void, data: *c_void) {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_set_data_for_uv_loop(loop_ptr, data);
-}
-pub unsafe fn get_data_for_uv_handle<T>(handle: *T) -> *c_void {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_get_data_for_uv_handle(handle as *c_void);
-}
-pub unsafe fn set_data_for_uv_handle<T, U>(handle: *T, data: *U) {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_set_data_for_uv_handle(handle as *c_void, data as *c_void);
-}
-pub unsafe fn get_data_for_req<T>(req: *T) -> *c_void {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_get_data_for_req(req as *c_void);
-}
-pub unsafe fn set_data_for_req<T, U>(req: *T, data: *U) {
- #[fixed_stack_segment]; #[inline(never)];
-
- rust_uv_set_data_for_req(req as *c_void, data as *c_void);
-}
-pub unsafe fn get_base_from_buf(buf: uv_buf_t) -> *u8 {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_get_base_from_buf(buf);
-}
-pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> size_t {
- #[fixed_stack_segment]; #[inline(never)];
-
- return rust_uv_get_len_from_buf(buf);
-}
-pub unsafe fn getaddrinfo(loop_: *uv_loop_t, req: *uv_getaddrinfo_t,
- getaddrinfo_cb: uv_getaddrinfo_cb,
- node: *c_char, service: *c_char,
- hints: *addrinfo) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
- return rust_uv_getaddrinfo(loop_, req, getaddrinfo_cb, node, service, hints);
-}
-pub unsafe fn freeaddrinfo(ai: *addrinfo) {
- #[fixed_stack_segment]; #[inline(never)];
- rust_uv_freeaddrinfo(ai);
-}
-pub unsafe fn pipe_open(pipe: *uv_pipe_t, file: c_int) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
- rust_uv_pipe_open(pipe, file)
-}
-pub unsafe fn pipe_bind(pipe: *uv_pipe_t, name: *c_char) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
- rust_uv_pipe_bind(pipe, name)
-}
-pub unsafe fn pipe_connect(req: *uv_connect_t, handle: *uv_pipe_t,
- name: *c_char, cb: uv_connect_cb) {
- #[fixed_stack_segment]; #[inline(never)];
- rust_uv_pipe_connect(req, handle, name, cb)
-}
-pub unsafe fn tty_init(loop_ptr: *uv_loop_t, tty: *uv_tty_t, fd: c_int,
- readable: c_int) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
- rust_uv_tty_init(loop_ptr, tty, fd, readable)
-}
-pub unsafe fn tty_set_mode(tty: *uv_tty_t, mode: c_int) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
- rust_uv_tty_set_mode(tty, mode)
-}
-pub unsafe fn tty_get_winsize(tty: *uv_tty_t, width: *c_int,
- height: *c_int) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
- rust_uv_tty_get_winsize(tty, width, height)
-}
-// FIXME(#9613) this should return uv_handle_type, not a c_int
-pub unsafe fn guess_handle(fd: c_int) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
- rust_uv_guess_handle(fd)
-}
-
-pub unsafe fn signal_init(loop_: *uv_loop_t, handle: *uv_signal_t) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
- return rust_uv_signal_init(loop_, handle);
-}
-pub unsafe fn signal_start(handle: *uv_signal_t,
- signal_cb: uv_signal_cb,
- signum: c_int) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
- return rust_uv_signal_start(handle, signal_cb, signum);
-}
-pub unsafe fn signal_stop(handle: *uv_signal_t) -> c_int {
- #[fixed_stack_segment]; #[inline(never)];
- return rust_uv_signal_stop(handle);
-}
-
-pub struct uv_err_data {
- priv err_name: ~str,
- priv err_msg: ~str,
-}
-
-extern {
-
- fn rust_uv_handle_size(type_: uintptr_t) -> size_t;
- fn rust_uv_req_size(type_: uintptr_t) -> size_t;
- fn rust_uv_handle_type_max() -> uintptr_t;
- fn rust_uv_req_type_max() -> uintptr_t;
-
- // libuv public API
- fn rust_uv_loop_new() -> *c_void;
- fn rust_uv_loop_delete(lp: *c_void);
- fn rust_uv_run(loop_handle: *c_void);
- fn rust_uv_close(handle: *c_void, cb: uv_close_cb);
- fn rust_uv_walk(loop_handle: *c_void, cb: uv_walk_cb, arg: *c_void);
-
- fn rust_uv_idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int;
- fn rust_uv_idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int;
- fn rust_uv_idle_stop(handle: *uv_idle_t) -> c_int;
-
- fn rust_uv_async_send(handle: *uv_async_t);
- fn rust_uv_async_init(loop_handle: *c_void,
- async_handle: *uv_async_t,
- cb: uv_async_cb) -> c_int;
- fn rust_uv_tcp_init(loop_handle: *c_void, handle_ptr: *uv_tcp_t) -> c_int;
- fn rust_uv_buf_init(out_buf: *uv_buf_t, base: *u8, len: size_t);
- fn rust_uv_strerror(err: c_int) -> *c_char;
- fn rust_uv_err_name(err: c_int) -> *c_char;
- fn rust_uv_ip4_addrp(ip: *u8, port: c_int) -> *sockaddr_in;
- fn rust_uv_ip6_addrp(ip: *u8, port: c_int) -> *sockaddr_in6;
- fn rust_uv_free_ip4_addr(addr: *sockaddr_in);
- fn rust_uv_free_ip6_addr(addr: *sockaddr_in6);
- fn rust_uv_ip4_name(src: *sockaddr_in, dst: *u8, size: size_t) -> c_int;
- fn rust_uv_ip6_name(src: *sockaddr_in6, dst: *u8, size: size_t) -> c_int;
- fn rust_uv_ip4_port(src: *sockaddr_in) -> c_uint;
- fn rust_uv_ip6_port(src: *sockaddr_in6) -> c_uint;
- fn rust_uv_tcp_connect(req: *uv_connect_t, handle: *uv_tcp_t,
- cb: uv_connect_cb,
- addr: *sockaddr_in) -> c_int;
- fn rust_uv_tcp_bind(tcp_server: *uv_tcp_t, addr: *sockaddr_in) -> c_int;
- fn rust_uv_tcp_connect6(req: *uv_connect_t, handle: *uv_tcp_t,
- cb: uv_connect_cb,
- addr: *sockaddr_in6) -> c_int;
- fn rust_uv_tcp_bind6(tcp_server: *uv_tcp_t, addr: *sockaddr_in6) -> c_int;
- fn rust_uv_tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_storage) -> c_int;
- fn rust_uv_tcp_getsockname(handle: *uv_tcp_t, name: *sockaddr_storage) -> c_int;
- fn rust_uv_tcp_nodelay(handle: *uv_tcp_t, enable: c_int) -> c_int;
- fn rust_uv_tcp_keepalive(handle: *uv_tcp_t, enable: c_int, delay: c_uint) -> c_int;
- fn rust_uv_tcp_simultaneous_accepts(handle: *uv_tcp_t, enable: c_int) -> c_int;
-
- fn rust_uv_udp_init(loop_handle: *uv_loop_t, handle_ptr: *uv_udp_t) -> c_int;
- fn rust_uv_udp_bind(server: *uv_udp_t, addr: *sockaddr_in, flags: c_uint) -> c_int;
- fn rust_uv_udp_bind6(server: *uv_udp_t, addr: *sockaddr_in6, flags: c_uint) -> c_int;
- fn rust_uv_udp_send(req: *uv_udp_send_t, handle: *uv_udp_t, buf_in: *uv_buf_t,
- buf_cnt: c_int, addr: *sockaddr_in, cb: uv_udp_send_cb) -> c_int;
- fn rust_uv_udp_send6(req: *uv_udp_send_t, handle: *uv_udp_t, buf_in: *uv_buf_t,
- buf_cnt: c_int, addr: *sockaddr_in6, cb: uv_udp_send_cb) -> c_int;
- fn rust_uv_udp_recv_start(server: *uv_udp_t,
- on_alloc: uv_alloc_cb,
- on_recv: uv_udp_recv_cb) -> c_int;
- fn rust_uv_udp_recv_stop(server: *uv_udp_t) -> c_int;
- fn rust_uv_get_udp_handle_from_send_req(req: *uv_udp_send_t) -> *uv_udp_t;
- fn rust_uv_udp_getsockname(handle: *uv_udp_t, name: *sockaddr_storage) -> c_int;
- fn rust_uv_udp_set_membership(handle: *uv_udp_t, multicast_addr: *c_char,
- interface_addr: *c_char, membership: c_int) -> c_int;
- fn rust_uv_udp_set_multicast_loop(handle: *uv_udp_t, on: c_int) -> c_int;
- fn rust_uv_udp_set_multicast_ttl(handle: *uv_udp_t, ttl: c_int) -> c_int;
- fn rust_uv_udp_set_ttl(handle: *uv_udp_t, ttl: c_int) -> c_int;
- fn rust_uv_udp_set_broadcast(handle: *uv_udp_t, on: c_int) -> c_int;
-
- fn rust_uv_is_ipv4_sockaddr(addr: *sockaddr) -> c_int;
- fn rust_uv_is_ipv6_sockaddr(addr: *sockaddr) -> c_int;
- fn rust_uv_malloc_sockaddr_storage() -> *sockaddr_storage;
- fn rust_uv_free_sockaddr_storage(ss: *sockaddr_storage);
-
- fn rust_uv_listen(stream: *c_void, backlog: c_int,
- cb: uv_connection_cb) -> c_int;
- fn rust_uv_accept(server: *c_void, client: *c_void) -> c_int;
- fn rust_uv_write(req: *c_void, stream: *c_void, buf_in: *uv_buf_t, buf_cnt: c_int,
- cb: uv_write_cb) -> c_int;
- fn rust_uv_read_start(stream: *c_void,
- on_alloc: uv_alloc_cb,
- on_read: uv_read_cb) -> c_int;
- fn rust_uv_read_stop(stream: *c_void) -> c_int;
- fn rust_uv_timer_init(loop_handle: *c_void, timer_handle: *uv_timer_t) -> c_int;
- fn rust_uv_timer_start(timer_handle: *uv_timer_t, cb: uv_timer_cb, timeout: libc::uint64_t,
- repeat: libc::uint64_t) -> c_int;
- fn rust_uv_timer_stop(handle: *uv_timer_t) -> c_int;
- fn rust_uv_fs_open(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
- flags: c_int, mode: c_int, cb: *u8) -> c_int;
- fn rust_uv_fs_unlink(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
- cb: *u8) -> c_int;
- fn rust_uv_fs_write(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int,
- buf: *c_void, len: c_uint, offset: i64, cb: *u8) -> c_int;
- fn rust_uv_fs_read(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int,
- buf: *c_void, len: c_uint, offset: i64, cb: *u8) -> c_int;
- fn rust_uv_fs_close(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int,
- cb: *u8) -> c_int;
- fn rust_uv_fs_stat(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char, cb: *u8) -> c_int;
- fn rust_uv_fs_fstat(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int, cb: *u8) -> c_int;
- fn rust_uv_fs_mkdir(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
- mode: c_int, cb: *u8) -> c_int;
- fn rust_uv_fs_rmdir(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
- cb: *u8) -> c_int;
- fn rust_uv_fs_readdir(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
- flags: c_int, cb: *u8) -> c_int;
- fn rust_uv_fs_req_cleanup(req: *uv_fs_t);
- fn rust_uv_populate_uv_stat(req_in: *uv_fs_t, stat_out: *uv_stat_t);
- fn rust_uv_get_result_from_fs_req(req: *uv_fs_t) -> c_int;
- fn rust_uv_get_ptr_from_fs_req(req: *uv_fs_t) -> *libc::c_void;
- fn rust_uv_get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t;
- fn rust_uv_get_loop_from_getaddrinfo_req(req: *uv_fs_t) -> *uv_loop_t;
-
- fn rust_uv_get_stream_handle_from_connect_req(connect_req: *uv_connect_t) -> *uv_stream_t;
- fn rust_uv_get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t;
- fn rust_uv_get_loop_for_uv_handle(handle: *c_void) -> *c_void;
- fn rust_uv_get_data_for_uv_loop(loop_ptr: *c_void) -> *c_void;
- fn rust_uv_set_data_for_uv_loop(loop_ptr: *c_void, data: *c_void);
- fn rust_uv_get_data_for_uv_handle(handle: *c_void) -> *c_void;
- fn rust_uv_set_data_for_uv_handle(handle: *c_void, data: *c_void);
- fn rust_uv_get_data_for_req(req: *c_void) -> *c_void;
- fn rust_uv_set_data_for_req(req: *c_void, data: *c_void);
- fn rust_uv_get_base_from_buf(buf: uv_buf_t) -> *u8;
- fn rust_uv_get_len_from_buf(buf: uv_buf_t) -> size_t;
- fn rust_uv_getaddrinfo(loop_: *uv_loop_t, req: *uv_getaddrinfo_t,
- getaddrinfo_cb: uv_getaddrinfo_cb,
- node: *c_char, service: *c_char,
- hints: *addrinfo) -> c_int;
- fn rust_uv_freeaddrinfo(ai: *addrinfo);
- fn rust_uv_spawn(loop_ptr: *c_void, outptr: *uv_process_t,
- options: uv_process_options_t) -> c_int;
- fn rust_uv_process_kill(p: *uv_process_t, signum: c_int) -> c_int;
- fn rust_uv_process_pid(p: *uv_process_t) -> c_int;
- fn rust_set_stdio_container_flags(c: *uv_stdio_container_t, flags: c_int);
- fn rust_set_stdio_container_fd(c: *uv_stdio_container_t, fd: c_int);
- fn rust_set_stdio_container_stream(c: *uv_stdio_container_t,
- stream: *uv_stream_t);
- fn rust_uv_pipe_init(loop_ptr: *c_void, p: *uv_pipe_t, ipc: c_int) -> c_int;
-
- fn rust_uv_pipe_open(pipe: *uv_pipe_t, file: c_int) -> c_int;
- fn rust_uv_pipe_bind(pipe: *uv_pipe_t, name: *c_char) -> c_int;
- fn rust_uv_pipe_connect(req: *uv_connect_t, handle: *uv_pipe_t,
- name: *c_char, cb: uv_connect_cb);
- fn rust_uv_tty_init(loop_ptr: *uv_loop_t, tty: *uv_tty_t, fd: c_int,
- readable: c_int) -> c_int;
- fn rust_uv_tty_set_mode(tty: *uv_tty_t, mode: c_int) -> c_int;
- fn rust_uv_tty_get_winsize(tty: *uv_tty_t, width: *c_int,
- height: *c_int) -> c_int;
- fn rust_uv_guess_handle(fd: c_int) -> c_int;
-
- // XXX: see comments in addrinfo.rs
- // These should all really be constants...
- //#[rust_stack] pub fn rust_SOCK_STREAM() -> c_int;
- //#[rust_stack] pub fn rust_SOCK_DGRAM() -> c_int;
- //#[rust_stack] pub fn rust_SOCK_RAW() -> c_int;
- //#[rust_stack] pub fn rust_IPPROTO_UDP() -> c_int;
- //#[rust_stack] pub fn rust_IPPROTO_TCP() -> c_int;
- //#[rust_stack] pub fn rust_AI_ADDRCONFIG() -> c_int;
- //#[rust_stack] pub fn rust_AI_ALL() -> c_int;
- //#[rust_stack] pub fn rust_AI_CANONNAME() -> c_int;
- //#[rust_stack] pub fn rust_AI_NUMERICHOST() -> c_int;
- //#[rust_stack] pub fn rust_AI_NUMERICSERV() -> c_int;
- //#[rust_stack] pub fn rust_AI_PASSIVE() -> c_int;
- //#[rust_stack] pub fn rust_AI_V4MAPPED() -> c_int;
-
- fn rust_uv_signal_init(loop_: *uv_loop_t, handle: *uv_signal_t) -> c_int;
- fn rust_uv_signal_start(handle: *uv_signal_t,
- signal_cb: uv_signal_cb,
- signum: c_int) -> c_int;
- fn rust_uv_signal_stop(handle: *uv_signal_t) -> c_int;
-}
pub mod path;
pub mod rand;
pub mod run;
+// NOTE: Remove module after next snapshot
+#[cfg(stage0)]
pub mod sys;
pub mod cast;
pub mod fmt;
pub use logging;
pub use option;
pub use os;
+ pub use rt;
pub use str;
+ // NOTE: Remove import after next snapshot
+ #[cfg(stage0)]
pub use sys;
pub use to_bytes;
pub use to_str;
//! Misc low level stuff
+// NOTE: Remove this module after an snapshot
+
#[allow(missing_doc)];
use any::Any;
use kinds::Send;
-use rt::task::{UnwindReasonStr, UnwindReasonAny};
use rt::task;
-use send_str::{SendStr, IntoSendStr};
-/// Trait for initiating task failure with a sendable cause.
pub trait FailWithCause {
- /// Fail the current task with `cause`.
fn fail_with(cause: Self, file: &'static str, line: uint) -> !;
}
-impl FailWithCause for ~str {
- fn fail_with(cause: ~str, file: &'static str, line: uint) -> ! {
- task::begin_unwind_reason(UnwindReasonStr(cause.into_send_str()), file, line)
- }
-}
-
-impl FailWithCause for &'static str {
- fn fail_with(cause: &'static str, file: &'static str, line: uint) -> ! {
- task::begin_unwind_reason(UnwindReasonStr(cause.into_send_str()), file, line)
- }
-}
-
-impl FailWithCause for SendStr {
- fn fail_with(cause: SendStr, file: &'static str, line: uint) -> ! {
- task::begin_unwind_reason(UnwindReasonStr(cause), file, line)
- }
-}
-
-impl FailWithCause for ~Any {
- fn fail_with(cause: ~Any, file: &'static str, line: uint) -> ! {
- task::begin_unwind_reason(UnwindReasonAny(cause), file, line)
- }
-}
-
-impl<T: Any + Send + 'static> FailWithCause for ~T {
- fn fail_with(cause: ~T, file: &'static str, line: uint) -> ! {
- task::begin_unwind_reason(UnwindReasonAny(cause as ~Any), file, line)
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- use any::Any;
- use cast;
- use send_str::IntoSendStr;
-
- #[test]
- fn synthesize_closure() {
- use unstable::raw::Closure;
- unsafe {
- let x = 10;
- let f: &fn(int) -> int = |y| x + y;
-
- assert_eq!(f(20), 30);
-
- let original_closure: Closure = cast::transmute(f);
-
- let actual_function_pointer = original_closure.code;
- let environment = original_closure.env;
-
- let new_closure = Closure {
- code: actual_function_pointer,
- env: environment
- };
-
- let new_f: &fn(int) -> int = cast::transmute(new_closure);
- assert_eq!(new_f(20), 30);
- }
+impl<T: Any + Send> FailWithCause for T {
+ fn fail_with(msg: T, file: &'static str, line: uint) -> ! {
+ task::begin_unwind(msg, file, line)
}
-
- #[test]
- #[should_fail]
- fn fail_static() { FailWithCause::fail_with("cause", file!(), line!()) }
-
- #[test]
- #[should_fail]
- fn fail_owned() { FailWithCause::fail_with(~"cause", file!(), line!()) }
-
- #[test]
- #[should_fail]
- fn fail_send() { FailWithCause::fail_with("cause".into_send_str(), file!(), line!()) }
-
- #[test]
- #[should_fail]
- fn fail_any() { FailWithCause::fail_with(~612_u16 as ~Any, file!(), line!()) }
-
- #[test]
- #[should_fail]
- fn fail_any_wrap() { FailWithCause::fail_with(~413_u16, file!(), line!()) }
}
use result::{Result, Ok, Err};
use rt::in_green_task_context;
use rt::local::Local;
-use rt::task::{UnwindReasonAny, UnwindReasonLinked, UnwindReasonStr};
+use rt::task::{UnwindMessageAny, UnwindMessageLinked};
+use rt::task::{UnwindMessageStrStatic, UnwindMessageStrOwned};
use rt::task::{UnwindResult, Success, Failure};
use send_str::{SendStr, IntoSendStr};
use unstable::finally::Finally;
fn wrap_as_any(res: UnwindResult) -> TaskResult {
match res {
Success => Ok(()),
- Failure(UnwindReasonStr(s)) => Err(~s as ~Any),
- Failure(UnwindReasonAny(a)) => Err(a),
- Failure(UnwindReasonLinked) => Err(~LinkedFailure as ~Any)
+ Failure(UnwindMessageAny(a)) => Err(a),
+ Failure(UnwindMessageLinked) => Err(~LinkedFailure as ~Any),
+ Failure(UnwindMessageStrOwned(s)) => Err(~s as ~Any),
+ Failure(UnwindMessageStrStatic(s)) => Err(~s as ~Any),
}
}
}
#[test]
-fn test_try_fail_cause_static_str() {
+fn test_try_fail_message_static_str() {
match do try {
fail!("static string");
} {
- Err(ref e) if e.is::<SendStr>() => {}
- Err(_) | Ok(()) => fail!()
+ Err(e) => {
+ type T = &'static str;
+ assert!(e.is::<T>());
+ assert_eq!(*e.move::<T>().unwrap(), "static string");
+ }
+ Ok(()) => fail!()
}
}
#[test]
-fn test_try_fail_cause_owned_str() {
+fn test_try_fail_message_owned_str() {
match do try {
fail!(~"owned string");
} {
- Err(ref e) if e.is::<SendStr>() => {}
- Err(_) | Ok(()) => fail!()
+ Err(e) => {
+ type T = ~str;
+ assert!(e.is::<T>());
+ assert_eq!(*e.move::<T>().unwrap(), ~"owned string");
+ }
+ Ok(()) => fail!()
}
}
#[test]
-fn test_try_fail_cause_any() {
+fn test_try_fail_message_any() {
match do try {
fail!(~413u16 as ~Any);
} {
- Err(ref e) if e.is::<u16>() => {}
- Err(_) | Ok(()) => fail!()
+ Err(e) => {
+ type T = ~Any;
+ assert!(e.is::<T>());
+ let any = e.move::<T>().unwrap();
+ assert!(any.is::<u16>());
+ assert_eq!(*any.move::<u16>().unwrap(), 413u16);
+ }
+ Ok(()) => fail!()
}
}
#[ignore(reason = "linked failure")]
#[test]
-fn test_try_fail_cause_linked() {
+fn test_try_fail_message_linked() {
match do try {
do spawn {
fail!()
}
#[test]
-fn test_try_fail_cause_any_wrapped() {
+fn test_try_fail_message_unit_struct() {
struct Juju;
match do try {
- fail!(~Juju)
+ fail!(Juju)
} {
Err(ref e) if e.is::<Juju>() => {}
Err(_) | Ok(()) => fail!()
use rt::local::Local;
use rt::sched::{Scheduler, Shutdown, TaskFromFriend};
use rt::task::{Task, Sched};
-use rt::task::{UnwindReasonLinked, UnwindReasonStr};
+use rt::task::{UnwindMessageLinked, UnwindMessageStrStatic};
use rt::task::{UnwindResult, Success, Failure};
use rt::thread::Thread;
use rt::work_queue::WorkQueue;
use rt::{in_green_task_context, new_event_loop, KillHandle};
-use send_str::IntoSendStr;
use task::SingleThreaded;
use task::TaskOpts;
use task::unkillable;
do RuntimeGlue::with_task_handle_and_failing |me, failing| {
if failing {
for x in self.notifier.mut_iter() {
- x.task_result = Some(Failure(UnwindReasonLinked));
+ x.task_result = Some(Failure(UnwindMessageLinked));
}
// Take everybody down with us. After this point, every
// other task in the group will see 'tg' as none, which
notify_chan: chan,
// Un-set above when taskgroup successfully made.
- task_result: Some(Failure(UnwindReasonStr("AutoNotify::new()".into_send_str())))
+ task_result: Some(Failure(UnwindMessageStrStatic("AutoNotify::new()")))
}
}
}
#[cfg(not(test))]
pub enum Opaque { }
+#[cfg(stage0)]
+pub type Disr = int;
+#[cfg(not(stage0))]
+pub type Disr = u64;
+
#[lang="ty_visitor"]
#[cfg(not(test))]
pub trait TyVisitor {
sz: uint, align: uint) -> bool;
fn visit_enter_enum(&mut self, n_variants: uint,
- get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+ get_disr: extern unsafe fn(ptr: *Opaque) -> Disr,
sz: uint, align: uint) -> bool;
fn visit_enter_enum_variant(&mut self, variant: uint,
- disr_val: int,
+ disr_val: Disr,
n_fields: uint,
name: &str) -> bool;
fn visit_enum_variant_field(&mut self, i: uint, offset: uint, inner: *TyDesc) -> bool;
fn visit_leave_enum_variant(&mut self, variant: uint,
- disr_val: int,
+ disr_val: Disr,
n_fields: uint,
name: &str) -> bool;
fn visit_leave_enum(&mut self, n_variants: uint,
- get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+ get_disr: extern unsafe fn(ptr: *Opaque) -> Disr,
sz: uint, align: uint) -> bool;
fn visit_enter_fn(&mut self, purity: uint, proto: uint,
#[cold]
#[lang="fail_"]
pub fn fail_(expr: *c_char, file: *c_char, line: size_t) -> ! {
- task::begin_unwind(expr, file, line);
+ task::begin_unwind_raw(expr, file, line);
}
#[cold]
// sure would be nice to have this
// impl<T> Repr<*Vec<T>> for ~[T] {}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use cast;
+
+ #[test]
+ fn synthesize_closure() {
+ unsafe {
+ let x = 10;
+ let f: &fn(int) -> int = |y| x + y;
+
+ assert_eq!(f(20), 30);
+
+ let original_closure: Closure = cast::transmute(f);
+
+ let actual_function_pointer = original_closure.code;
+ let environment = original_closure.env;
+
+ let new_closure = Closure {
+ code: actual_function_pointer,
+ env: environment
+ };
+
+ let new_f: &fn(int) -> int = cast::transmute(new_closure);
+ assert_eq!(new_f(20), 30);
+ }
+ }
+}
use ast;
use ast::{Attribute, Attribute_, MetaItem, MetaWord, MetaNameValue, MetaList};
-use codemap::{Spanned, spanned, dummy_spanned};
+use codemap::{Span, Spanned, spanned, dummy_spanned};
use codemap::BytePos;
use diagnostic::span_handler;
use parse::comments::{doc_comment_style, strip_doc_comment_decoration};
}
}
}
+
+
+/**
+ * Fold this over attributes to parse #[repr(...)] forms.
+ *
+ * Valid repr contents: any of the primitive integral type names (see
+ * `int_type_of_word`, below) to specify the discriminant type; and `C`, to use
+ * the same discriminant size that the corresponding C enum would. These are
+ * not allowed on univariant or zero-variant enums, which have no discriminant.
+ *
+ * If a discriminant type is so specified, then the discriminant will be
+ * present (before fields, if any) with that type; reprensentation
+ * optimizations which would remove it will not be done.
+ */
+pub fn find_repr_attr(diagnostic: @mut span_handler, attr: @ast::MetaItem, acc: ReprAttr)
+ -> ReprAttr {
+ let mut acc = acc;
+ match attr.node {
+ ast::MetaList(s, ref items) if "repr" == s => {
+ for item in items.iter() {
+ match item.node {
+ ast::MetaWord(word) => {
+ let hint = match word.as_slice() {
+ // Can't use "extern" because it's not a lexical identifier.
+ "C" => ReprExtern,
+ _ => match int_type_of_word(word) {
+ Some(ity) => ReprInt(item.span, ity),
+ None => {
+ // Not a word we recognize
+ diagnostic.span_err(item.span,
+ "unrecognized representation hint");
+ ReprAny
+ }
+ }
+ };
+ if hint != ReprAny {
+ if acc == ReprAny {
+ acc = hint;
+ } else if acc != hint {
+ diagnostic.span_warn(item.span,
+ "conflicting representation hint ignored")
+ }
+ }
+ }
+ // Not a word:
+ _ => diagnostic.span_err(item.span, "unrecognized representation hint")
+ }
+ }
+ }
+ // Not a "repr" hint: ignore.
+ _ => { }
+ }
+ return acc;
+}
+
+fn int_type_of_word(s: &str) -> Option<IntType> {
+ match s {
+ "i8" => Some(SignedInt(ast::ty_i8)),
+ "u8" => Some(UnsignedInt(ast::ty_u8)),
+ "i16" => Some(SignedInt(ast::ty_i16)),
+ "u16" => Some(UnsignedInt(ast::ty_u16)),
+ "i32" => Some(SignedInt(ast::ty_i32)),
+ "u32" => Some(UnsignedInt(ast::ty_u32)),
+ "i64" => Some(SignedInt(ast::ty_i64)),
+ "u64" => Some(UnsignedInt(ast::ty_u64)),
+ "int" => Some(SignedInt(ast::ty_i)),
+ "uint" => Some(UnsignedInt(ast::ty_u)),
+ _ => None
+ }
+}
+
+#[deriving(Eq)]
+pub enum ReprAttr {
+ ReprAny,
+ ReprInt(Span, IntType),
+ ReprExtern
+}
+
+impl ReprAttr {
+ pub fn is_ffi_safe(&self) -> bool {
+ match *self {
+ ReprAny => false,
+ ReprInt(_sp, ity) => ity.is_ffi_safe(),
+ ReprExtern => true
+ }
+ }
+}
+
+#[deriving(Eq)]
+pub enum IntType {
+ SignedInt(ast::int_ty),
+ UnsignedInt(ast::uint_ty)
+}
+
+impl IntType {
+ #[inline]
+ pub fn is_signed(self) -> bool {
+ match self {
+ SignedInt(*) => true,
+ UnsignedInt(*) => false
+ }
+ }
+ fn is_ffi_safe(self) -> bool {
+ match self {
+ SignedInt(ast::ty_i8) | UnsignedInt(ast::ty_u8) |
+ SignedInt(ast::ty_i16) | UnsignedInt(ast::ty_u16) |
+ SignedInt(ast::ty_i32) | UnsignedInt(ast::ty_u32) |
+ SignedInt(ast::ty_i64) | UnsignedInt(ast::ty_u64) => true,
+ _ => false
+ }
+ }
+}
span,
~[
self.ident_of("std"),
- self.ident_of("sys"),
- self.ident_of("FailWithCause"),
- self.ident_of("fail_with"),
+ self.ident_of("rt"),
+ self.ident_of("task"),
+ self.ident_of("begin_unwind"),
],
~[
self.expr_str(span, msg),
// syntax elements.
pub fn std_macros() -> @str {
- return
-@"mod __std_macros {
+@r#"mod __std_macros {
#[macro_escape];
#[doc(hidden)];
macro_rules! fail(
() => (
- fail!(\"explicit failure\")
+ fail!("explicit failure")
);
- ($fmt:expr) => (
- ::std::sys::FailWithCause::fail_with($fmt, file!(), line!())
+ ($msg:expr) => (
+ ::std::rt::task::begin_unwind($msg, file!(), line!())
);
($fmt:expr, $($arg:tt)*) => (
- ::std::sys::FailWithCause::fail_with(format!($fmt, $($arg)*), file!(), line!())
+ ::std::rt::task::begin_unwind(format!($fmt, $($arg)*), file!(), line!())
)
)
macro_rules! assert(
($cond:expr) => {
if !$cond {
- ::std::sys::FailWithCause::fail_with(
- \"assertion failed: \" + stringify!($cond), file!(), line!())
+ fail!("assertion failed: {:s}", stringify!($cond))
}
};
($cond:expr, $msg:expr) => {
if !$cond {
- ::std::sys::FailWithCause::fail_with($msg, file!(), line!())
+ fail!($msg)
}
};
($cond:expr, $( $arg:expr ),+) => {
if !$cond {
- ::std::sys::FailWithCause::fail_with(format!( $($arg),+ ), file!(), line!())
+ fail!( $($arg),+ )
}
}
)
// check both directions of equality....
if !((*given_val == *expected_val) &&
(*expected_val == *given_val)) {
- fail!(\"assertion failed: `(left == right) && (right == \
- left)` (left: `{:?}`, right: `{:?}`)\",
- *given_val, *expected_val);
+ fail!("assertion failed: `(left == right) && (right == left)` \
+ (left: `{:?}`, right: `{:?}`)", *given_val, *expected_val)
}
}
)
given_val.approx_eq(&expected_val) &&
expected_val.approx_eq(&given_val)
) {
- fail!(\"left: {:?} does not approximately equal right: {:?}\",
+ fail!("left: {:?} does not approximately equal right: {:?}",
given_val, expected_val);
}
}
given_val.approx_eq_eps(&expected_val, &epsilon_val) &&
expected_val.approx_eq_eps(&given_val, &epsilon_val)
) {
- fail!(\"left: {:?} does not approximately equal right: \
- {:?} with epsilon: {:?}\",
+ fail!("left: {:?} does not approximately equal right: \
+ {:?} with epsilon: {:?}",
given_val, expected_val, epsilon_val);
}
}
)
)
- // FIXME(#6266): change the /* to /** when attributes are supported on macros
- // (Though even then—is it going to work according to the clear intent here?)
- /*
- A utility macro for indicating unreachable code. It will fail if
- executed. This is occasionally useful to put after loops that never
- terminate normally, but instead directly return from a function.
-
- # Example
-
- ```rust
- fn choose_weighted_item(v: &[Item]) -> Item {
- assert!(!v.is_empty());
- let mut so_far = 0u;
- for v.each |item| {
- so_far += item.weight;
- if so_far > 100 {
- return item;
- }
- }
- // The above loop always returns, so we must hint to the
- // type checker that it isn't possible to get down here
- unreachable!();
- }
- ```
-
- */
+ /// A utility macro for indicating unreachable code. It will fail if
+ /// executed. This is occasionally useful to put after loops that never
+ /// terminate normally, but instead directly return from a function.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// fn choose_weighted_item(v: &[Item]) -> Item {
+ /// assert!(!v.is_empty());
+ /// let mut so_far = 0u;
+ /// for item in v.iter() {
+ /// so_far += item.weight;
+ /// if so_far > 100 {
+ /// return item;
+ /// }
+ /// }
+ /// // The above loop always returns, so we must hint to the
+ /// // type checker that it isn't possible to get down here
+ /// unreachable!();
+ /// }
+ /// ```
macro_rules! unreachable (() => (
- fail!(\"internal error: entered unreachable code\");
+ fail!("internal error: entered unreachable code");
))
macro_rules! condition (
)
)
- // externfn! declares a wrapper for an external function.
- // It is intended to be used like:
- //
- // externfn!(#[nolink]
- // fn memcmp(cx: *u8, ct: *u8, n: u32) -> u32)
- //
- // Due to limitations in the macro parser, this pattern must be
- // implemented with 4 distinct patterns (with attrs / without
- // attrs CROSS with args / without ARGS).
- //
- // Also, this macro grammar allows for any number of return types
- // because I couldn't figure out the syntax to specify at most one.
+ /// externfn! declares a wrapper for an external function.
+ /// It is intended to be used like:
+ ///
+ /// externfn!(#[nolink]
+ /// fn memcmp(cx: *u8, ct: *u8, n: u32) -> u32)
+ ///
+ /// Due to limitations in the macro parser, this pattern must be
+ /// implemented with 4 distinct patterns (with attrs / without
+ /// attrs CROSS with args / without ARGS).
+ ///
+ /// Also, this macro grammar allows for any number of return types
+ /// because I couldn't figure out the syntax to specify at most one.
macro_rules! externfn(
(fn $name:ident () $(-> $ret_ty:ty),*) => (
pub unsafe fn $name() $(-> $ret_ty),* {
)
)
-}";
+}"#
}
struct Injector {
struct _Unwind_Context;
struct _Unwind_Exception;
-typedef void (*CDECL stack_switch_shim)(void*);
-
-/**********************************************************************
- * Switches to the C-stack and invokes |fn_ptr|, passing |args| as argument.
- * This is used by the C compiler to call foreign functions and by other
- * upcalls to switch to the C stack. The return value is passed through a
- * field in the args parameter. This upcall is specifically for switching
- * to the shim functions generated by rustc.
- */
-extern "C" CDECL void
-upcall_call_shim_on_c_stack(void *args, void *fn_ptr) {
- stack_switch_shim f = (stack_switch_shim)fn_ptr;
- f(args);
-}
-
-/*
- * The opposite of above. Starts on a C stack and switches to the Rust
- * stack. This is the only upcall that runs from the C stack.
- */
-extern "C" CDECL void
-upcall_call_shim_on_rust_stack(void *args, void *fn_ptr) {
- // There's no task. Call the function and hope for the best
- stack_switch_shim f = (stack_switch_shim)fn_ptr;
- f(args);
-}
-
-/**********************************************************************/
-
#ifdef __SEH__
# define PERSONALITY_FUNC __gxx_personality_seh0
#else
return args.retval;
}
-// NB: This needs to be blazing fast. Don't switch stacks
-extern "C" CDECL void *
-upcall_new_stack(size_t stk_sz, void *args_addr, size_t args_sz) {
- assert(false && "newsched shouldn't be growing the stack");
- return NULL;
-}
-
-// NB: This needs to be blazing fast. Don't switch stacks
-extern "C" CDECL void
-upcall_del_stack() {
- assert(false && "newsched shouldn't be growing the stack");
-}
-
// Landing pads need to call this to insert the
// correct limit into TLS.
// NB: This must run on the Rust stack because it
rust_win32_rand_gen
rust_win32_rand_release
upcall_rust_personality
-upcall_call_shim_on_c_stack
-upcall_call_shim_on_rust_stack
-upcall_new_stack
-upcall_del_stack
upcall_reset_stack_limit
rust_uv_loop_new
rust_uv_loop_delete
#endif
thread = 0;
}
-
-void
-rust_thread::detach() {
-#if !defined(__WIN32__)
- // Don't leak pthread resources.
- // http://crosstantine.blogspot.com/2010/01/pthreadcreate-memory-leak.html
- CHECKED(pthread_detach(thread));
-#endif
-}
virtual void run() = 0;
void join();
- void detach();
};
#endif /* RUST_THREAD_H */
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#ifndef ARRAY_LIST_H
-#define ARRAY_LIST_H
-
-#include <inttypes.h>
-#include <stddef.h>
-#include <new>
-
-/**
- * A simple, resizable array list. Note that this only works with POD types
- * (because data is grown via realloc).
- */
-template<typename T> class array_list {
- static const size_t INITIAL_CAPACITY = 8;
- size_t _size;
- T * _data;
- size_t _capacity;
-private:
- // private and left undefined to disable copying
- array_list(const array_list& rhs);
- array_list& operator=(const array_list& rhs);
-public:
- array_list();
- ~array_list();
- size_t size() const;
- int32_t append(T value);
- int32_t push(T value);
- void pop(T *value);
- bool replace(T old_value, T new_value);
- int32_t index_of(T value) const;
- bool is_empty() const;
- T* data();
- const T* data() const;
- T & operator[](size_t index);
- const T & operator[](size_t index) const;
-};
-
-template<typename T>
-array_list<T>::array_list() {
- _size = 0;
- _capacity = INITIAL_CAPACITY;
- _data = (T *) malloc(sizeof(T) * _capacity);
-}
-
-template<typename T>
-array_list<T>::~array_list() {
- free(_data);
-}
-
-template<typename T> size_t
-array_list<T>::size() const {
- return _size;
-}
-
-template<typename T> int32_t
-array_list<T>::append(T value) {
- return push(value);
-}
-
-template<typename T> int32_t
-array_list<T>::push(T value) {
- if (_size == _capacity) {
- size_t new_capacity = _capacity * 2;
- void* buffer = realloc(_data, new_capacity * sizeof(T));
- if (buffer == NULL) {
- fprintf(stderr,
- "array_list::push> "
- "Out of memory allocating %ld bytes",
- (long int) (new_capacity * sizeof(T)));
- abort();
- }
- _data = (T *) buffer;
- _capacity = new_capacity;
- }
- _data[_size ++] = value;
- return _size - 1;
-}
-
-template<typename T> void
-array_list<T>::pop(T *value) {
- assert(_size > 0);
- if (value != NULL) {
- *value = _data[-- _size];
- } else {
- -- _size;
- }
-}
-
-/**
- * Replaces the old_value in the list with the new_value.
- * Returns the true if the replacement succeeded, or false otherwise.
- */
-template<typename T> bool
-array_list<T>::replace(T old_value, T new_value) {
- int index = index_of(old_value);
- if (index < 0) {
- return false;
- }
- _data[index] = new_value;
- return true;
-}
-
-template<typename T> int32_t
-array_list<T>::index_of(T value) const {
- for (size_t i = 0; i < _size; i++) {
- if (_data[i] == value) {
- return i;
- }
- }
- return -1;
-}
-
-template<typename T> T &
-array_list<T>::operator[](size_t index) {
- assert(index < size());
- return _data[index];
-}
-
-template<typename T> const T &
-array_list<T>::operator[](size_t index) const {
- assert(index < size());
- return _data[index];
-}
-
-template<typename T> bool
-array_list<T>::is_empty() const {
- return _size == 0;
-}
-
-template<typename T> T*
-array_list<T>::data() {
- return _data;
-}
-
-template<typename T> const T*
-array_list<T>::data() const {
- return _data;
-}
-
-#endif /* ARRAY_LIST_H */
+S 2013-10-29 fed48cc
+ freebsd-x86_64 4a43216b432511a5fd6b727753aedb749f6a68dc
+ linux-i386 53f65d4b1377c17fc12d05d7c4a0fbd92eea071f
+ linux-x86_64 afa5f19a37a2cf137e5d4277951fa07efda8e072
+ macos-i386 7522c24f78ed35020e2877e3eada058ea8a11f35
+ macos-x86_64 a18afdcbbdbb81c1fdf08788b24f0d3ea8701eb1
+ winnt-i386 c78f0839c9524eda33c54a5232121886021b5352
+
S 2013-10-28 2ab4a6f
freebsd-x86_64 08af04bcf739930bdb7d0ad244b2c8094cd5096a
linux-i386 c233de1ed09872d5c7a3e1ce9ab9eb6e16631201
// except according to those terms.
extern mod extra;
+
+use std::iter::range_step;
use extra::arena::Arena;
+use extra::future::Future;
enum Tree<'self> {
Nil,
- Node(&'self Tree<'self>, &'self Tree<'self>, int),
+ Node(&'self Tree<'self>, &'self Tree<'self>, int)
}
fn item_check(t: &Tree) -> int {
match *t {
- Nil => { return 0; }
- Node(left, right, item) => {
- return item + item_check(left) - item_check(right);
- }
+ Nil => 0,
+ Node(l, r, i) => i + item_check(l) - item_check(r)
}
}
-fn bottom_up_tree<'r>(arena: &'r Arena, item: int, depth: int)
- -> &'r Tree<'r> {
+fn bottom_up_tree<'r>(arena: &'r Arena, item: int, depth: int) -> &'r Tree<'r> {
if depth > 0 {
- return arena.alloc(
- || Node(bottom_up_tree(arena, 2 * item - 1, depth - 1),
- bottom_up_tree(arena, 2 * item, depth - 1),
- item));
- }
- return arena.alloc(|| Nil);
+ do arena.alloc {
+ Node(bottom_up_tree(arena, 2 * item - 1, depth - 1),
+ bottom_up_tree(arena, 2 * item, depth - 1),
+ item)
+ }
+ } else {arena.alloc(|| Nil)}
}
fn main() {
- use std::os;
- use std::int;
let args = std::os::args();
- let args = if os::getenv("RUST_BENCH").is_some() {
- ~[~"", ~"17"]
+ let n = if std::os::getenv("RUST_BENCH").is_some() {
+ 17
} else if args.len() <= 1u {
- ~[~"", ~"8"]
+ 8
} else {
- args
+ from_str(args[1]).unwrap()
};
-
- let n = from_str::<int>(args[1]).unwrap();
let min_depth = 4;
- let mut max_depth;
- if min_depth + 2 > n {
- max_depth = min_depth + 2;
- } else {
- max_depth = n;
- }
+ let max_depth = if min_depth + 2 > n {min_depth + 2} else {n};
- let stretch_arena = Arena::new();
- let stretch_depth = max_depth + 1;
- let stretch_tree = bottom_up_tree(&stretch_arena, 0, stretch_depth);
+ {
+ let arena = Arena::new();
+ let depth = max_depth + 1;
+ let tree = bottom_up_tree(&arena, 0, depth);
- println!("stretch tree of depth {}\t check: {}",
- stretch_depth,
- item_check(stretch_tree));
+ println!("stretch tree of depth {}\t check: {}",
+ depth, item_check(tree));
+ }
let long_lived_arena = Arena::new();
let long_lived_tree = bottom_up_tree(&long_lived_arena, 0, max_depth);
- let mut depth = min_depth;
- while depth <= max_depth {
- let iterations = int::pow(2, (max_depth - depth + min_depth) as uint);
- let mut chk = 0;
- let mut i = 1;
- while i <= iterations {
- let mut temp_tree = bottom_up_tree(&long_lived_arena, i, depth);
- chk += item_check(temp_tree);
- temp_tree = bottom_up_tree(&long_lived_arena, -i, depth);
- chk += item_check(temp_tree);
- i += 1;
- }
- println!("{}\t trees of depth {}\t check: {}",
- iterations * 2, depth, chk);
- depth += 2;
+
+ let mut messages = range_step(min_depth, max_depth + 1, 2).map(|depth| {
+ use std::int::pow;
+ let iterations = pow(2, (max_depth - depth + min_depth) as uint);
+ do Future::spawn {
+ let mut chk = 0;
+ for i in range(1, iterations + 1) {
+ let arena = Arena::new();
+ let a = bottom_up_tree(&arena, i, depth);
+ let b = bottom_up_tree(&arena, -i, depth);
+ chk += item_check(a) + item_check(b);
+ }
+ format!("{}\t trees of depth {}\t check: {}",
+ iterations * 2, depth, chk)
+ }
+ }).to_owned_vec();
+
+ for message in messages.mut_iter() {
+ println(*message.get_ref());
}
+
println!("long lived tree of depth {}\t check: {}",
- max_depth,
- item_check(long_lived_tree));
+ max_depth, item_check(long_lived_tree));
}
--- /dev/null
+// Copyright 2012-2013 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ 1 = 2; //~ ERROR illegal left-hand side expression
+ 1 += 2; //~ ERROR illegal left-hand side expression
+ (1, 2) = (3, 4); //~ ERROR illegal left-hand side expression
+
+ let (a, b) = (1, 2);
+ (a, b) = (3, 4); //~ ERROR illegal left-hand side expression
+
+ None = Some(3); //~ ERROR illegal left-hand side expression
+}
fn main() {
// assigning to various global constants
- None = Some(3); //~ ERROR cannot assign to immutable static item
foo = 6; //~ ERROR cannot assign to immutable static item
}
--- /dev/null
+// Copyright 2013 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[repr(u8)] //~ NOTE discriminant type specified here
+enum Eu8 {
+ Au8 = 23,
+ Bu8 = 223,
+ Cu8 = -23, //~ ERROR discriminant value outside specified type
+}
+
+#[repr(i8)] //~ NOTE discriminant type specified here
+enum Ei8 {
+ Ai8 = 23,
+ Bi8 = -23,
+ Ci8 = 223, //~ ERROR discriminant value outside specified type
+}
+
+#[repr(u16)] //~ NOTE discriminant type specified here
+enum Eu16 {
+ Au16 = 23,
+ Bu16 = 55555,
+ Cu16 = -22333, //~ ERROR discriminant value outside specified type
+}
+
+#[repr(i16)] //~ NOTE discriminant type specified here
+enum Ei16 {
+ Ai16 = 23,
+ Bi16 = -22333,
+ Ci16 = 55555, //~ ERROR discriminant value outside specified type
+}
+
+#[repr(u32)] //~ NOTE discriminant type specified here
+enum Eu32 {
+ Au32 = 23,
+ Bu32 = 3_000_000_000,
+ Cu32 = -2_000_000_000, //~ ERROR discriminant value outside specified type
+}
+
+#[repr(i32)] //~ NOTE discriminant type specified here
+enum Ei32 {
+ Ai32 = 23,
+ Bi32 = -2_000_000_000,
+ Ci32 = 3_000_000_000, //~ ERROR discriminant value outside specified type
+}
+
+// u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`. This is a
+// little counterintuitive, but since the discriminant can store all the bits, and extracting it
+// with a cast requires specifying the signedness, there is no loss of information in those cases.
+// This also applies to int and uint on 64-bit targets.
+
+pub fn main() { }
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// error-pattern:failed to find an implementation of trait std::sys::FailWithCause for int
-
-fn main() { fail!(5); }
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// error-pattern:failed to find an implementation of trait std::sys::FailWithCause for ~[int]
-fn main() { fail!(~[0i]); }
--- /dev/null
+// Copyright 2013 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[deny(ctypes)];
+
+enum Z { }
+enum U { A }
+enum B { C, D }
+enum T { E, F, G }
+
+extern {
+ fn zf(x: Z);
+ fn uf(x: U);
+ fn bf(x: B); //~ ERROR found enum type without foreign-function-safe
+ fn tf(x: T); //~ ERROR found enum type without foreign-function-safe
+}
+
+pub fn main() { }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//error-pattern:discriminator value already exists
+//error-pattern:discriminant value already exists
// black and white have the same discriminator value ...
// STACK BY REF
// debugger:finish
// debugger:print *self
-// check:$1 = {{Variant2, x = 1799, y = 1799}, {Variant2, 117901063}}
+// check:$1 = {{Variant2, [...]}, {Variant2, 117901063}}
// debugger:print arg1
// check:$2 = -1
// debugger:print arg2
// STACK BY VAL
// debugger:finish
// d ebugger:print self -- ignored for now because of issue #8512
-// c heck:$X = {{Variant2, x = 1799, y = 1799}, {Variant2, 117901063}}
+// c heck:$X = {{Variant2, [...]}, {Variant2, 117901063}}
// debugger:print arg1
// check:$4 = -3
// debugger:print arg2
// OWNED BY REF
// debugger:finish
// debugger:print *self
-// check:$6 = {{Variant1, x = 1799, y = 1799}, {Variant1, 117901063}}
+// check:$6 = {{Variant1, x = 1799, y = 1799}, {Variant1, [...]}}
// debugger:print arg1
// check:$7 = -5
// debugger:print arg2
// OWNED BY VAL
// debugger:finish
// d ebugger:print self -- ignored for now because of issue #8512
-// c heck:$X = {{Variant1, x = 1799, y = 1799}, {Variant1, 117901063}}
+// c heck:$X = {{Variant1, x = 1799, y = 1799}, {Variant1, [...]}}
// debugger:print arg1
// check:$9 = -7
// debugger:print arg2
// OWNED MOVED
// debugger:finish
// debugger:print *self
-// check:$11 = {{Variant1, x = 1799, y = 1799}, {Variant1, 117901063}}
+// check:$11 = {{Variant1, x = 1799, y = 1799}, {Variant1, [...]}}
// debugger:print arg1
// check:$12 = -9
// debugger:print arg2
// MANAGED BY REF
// debugger:finish
// debugger:print *self
-// check:$14 = {{Variant2, x = 1799, y = 1799}, {Variant2, 117901063}}
+// check:$14 = {{Variant2, [...]}, {Variant2, 117901063}}
// debugger:print arg1
// check:$15 = -11
// debugger:print arg2
// MANAGED BY VAL
// debugger:finish
// d ebugger:print self -- ignored for now because of issue #8512
-// c heck:$X = {{Variant2, x = 1799, y = 1799}, {Variant2, 117901063}}
+// c heck:$X = {{Variant2, [...]}, {Variant2, 117901063}}
// debugger:print arg1
// check:$17 = -13
// debugger:print arg2
// MANAGED SELF
// debugger:finish
// debugger:print self->val
-// check:$19 = {{Variant2, x = 1799, y = 1799}, {Variant2, 117901063}}
+// check:$19 = {{Variant2, [...]}, {Variant2, 117901063}}
// debugger:print arg1
// check:$20 = -15
// debugger:print arg2
+++ /dev/null
-// Copyright 2013 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// error-pattern:failed at 'test-fail-send-str'
-
-fn main() {
- fail!("test-fail-send-str".into_send_str());
-}
--- /dev/null
+// Copyright 2013 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::mem::size_of;
+
+enum Ei8 {
+ Ai8 = -1,
+ Bi8 = 0
+}
+
+enum Eu8 {
+ Au8 = 0,
+ Bu8 = 0x80
+}
+
+enum Ei16 {
+ Ai16 = -1,
+ Bi16 = 0x80
+}
+
+enum Eu16 {
+ Au16 = 0,
+ Bu16 = 0x8000
+}
+
+enum Ei32 {
+ Ai32 = -1,
+ Bi32 = 0x8000
+}
+
+enum Eu32 {
+ Au32 = 0,
+ Bu32 = 0x8000_0000
+}
+
+enum Ei64 {
+ Ai64 = -1,
+ Bi64 = 0x8000_0000
+}
+
+enum Eu64 {
+ Au64 = 0,
+ Bu64 = 0x8000_0000_0000_0000
+}
+
+pub fn main() {
+ assert_eq!(size_of::<Ei8>(), 1);
+ assert_eq!(size_of::<Eu8>(), 1);
+ assert_eq!(size_of::<Ei16>(), 2);
+ assert_eq!(size_of::<Eu16>(), 2);
+ assert_eq!(size_of::<Ei32>(), 4);
+ assert_eq!(size_of::<Eu32>(), 4);
+ assert_eq!(size_of::<Ei64>(), 8);
+ assert_eq!(size_of::<Eu64>(), 8);
+}
--- /dev/null
+// Copyright 2013 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::mem::size_of;
+
+#[repr(i8)]
+enum Ei8 {
+ Ai8 = 0,
+ Bi8 = 1
+}
+
+#[repr(u8)]
+enum Eu8 {
+ Au8 = 0,
+ Bu8 = 1
+}
+
+#[repr(i16)]
+enum Ei16 {
+ Ai16 = 0,
+ Bi16 = 1
+}
+
+#[repr(u16)]
+enum Eu16 {
+ Au16 = 0,
+ Bu16 = 1
+}
+
+#[repr(i32)]
+enum Ei32 {
+ Ai32 = 0,
+ Bi32 = 1
+}
+
+#[repr(u32)]
+enum Eu32 {
+ Au32 = 0,
+ Bu32 = 1
+}
+
+#[repr(i64)]
+enum Ei64 {
+ Ai64 = 0,
+ Bi64 = 1
+}
+
+#[repr(u64)]
+enum Eu64 {
+ Au64 = 0,
+ Bu64 = 1
+}
+
+#[repr(int)]
+enum Eint {
+ Aint = 0,
+ Bint = 1
+}
+
+#[repr(uint)]
+enum Euint {
+ Auint = 0,
+ Buint = 1
+}
+
+pub fn main() {
+ assert_eq!(size_of::<Ei8>(), 1);
+ assert_eq!(size_of::<Eu8>(), 1);
+ assert_eq!(size_of::<Ei16>(), 2);
+ assert_eq!(size_of::<Eu16>(), 2);
+ assert_eq!(size_of::<Ei32>(), 4);
+ assert_eq!(size_of::<Eu32>(), 4);
+ assert_eq!(size_of::<Ei64>(), 8);
+ assert_eq!(size_of::<Eu64>(), 8);
+ assert_eq!(size_of::<Eint>(), size_of::<int>());
+ assert_eq!(size_of::<Euint>(), size_of::<uint>());
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::mem;
+#[feature(macro_rules)];
+
+macro_rules! check {
+ ($m:ident, $t:ty, $v:expr) => {{
+ mod $m {
+ use std::mem::size_of;
+ enum E {
+ V = $v,
+ A = 0
+ }
+ static C: E = V;
+ pub fn check() {
+ assert_eq!(size_of::<E>(), size_of::<$t>());
+ assert_eq!(V as $t, $v);
+ assert_eq!(C as $t, $v);
+ assert_eq!(format!("{:?}", V), ~"V");
+ assert_eq!(format!("{:?}", C), ~"V");
+ }
+ }
+ $m::check();
+ }}
+}
pub fn main() {
- enum E { V = 0x1717171717171717 }
- static C: E = V;
- let expected: u64 = if mem::size_of::<uint>() < 8 {
- 0x17171717
- } else {
- 0x1717171717171717
- };
- assert_eq!(expected, V as u64);
- assert_eq!(expected, C as u64);
- assert_eq!(format!("{:?}", V), ~"V");
- assert_eq!(format!("{:?}", C), ~"V");
+ check!(a, u8, 0x17);
+ check!(b, u8, 0xe8);
+ check!(c, u16, 0x1727);
+ check!(d, u16, 0xe8d8);
+ check!(e, u32, 0x17273747);
+ check!(f, u32, 0xe8d8c8b8);
+ check!(g, u64, 0x1727374757677787u64);
+ check!(h, u64, 0xe8d8c8b8a8988878u64);
+
+ check!(z, i8, 0x17);
+ check!(y, i8, -0x17);
+ check!(x, i16, 0x1727);
+ check!(w, i16, -0x1727);
+ check!(v, i32, 0x17273747);
+ check!(u, i32, -0x17273747);
+ check!(t, i64, 0x1727374757677787);
+ check!(s, i64, -0x1727374757677787);
+
+ enum Simple { A, B }
+ assert_eq!(::std::mem::size_of::<Simple>(), 1);
}
}
#[deriving(Eq)]
+ #[repr(int)]
pub enum state {
empty,
full,
use std::libc::c_void;
use std::ptr;
use std::mem;
-use std::unstable::intrinsics::{TyDesc, get_tydesc, visit_tydesc, TyVisitor, Opaque};
+use std::unstable::intrinsics::{TyDesc, get_tydesc, visit_tydesc, TyVisitor, Disr, Opaque};
use std::unstable::raw::Vec;
#[doc = "High-level interfaces to `std::unstable::intrinsics::visit_ty` reflection system."]
}
fn visit_enter_enum(&mut self, n_variants: uint,
- get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+ get_disr: extern unsafe fn(ptr: *Opaque) -> Disr,
sz: uint, align: uint)
-> bool {
self.align(align);
}
fn visit_enter_enum_variant(&mut self, variant: uint,
- disr_val: int,
+ disr_val: Disr,
n_fields: uint,
name: &str) -> bool {
if ! self.inner.visit_enter_enum_variant(variant, disr_val,
}
fn visit_leave_enum_variant(&mut self, variant: uint,
- disr_val: int,
+ disr_val: Disr,
n_fields: uint,
name: &str) -> bool {
if ! self.inner.visit_leave_enum_variant(variant, disr_val,
}
fn visit_leave_enum(&mut self, n_variants: uint,
- get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+ get_disr: extern unsafe fn(ptr: *Opaque) -> Disr,
sz: uint, align: uint)
-> bool {
if ! self.inner.visit_leave_enum(n_variants, get_disr, sz, align) { return false; }
_sz: uint, _align: uint) -> bool { true }
fn visit_enter_enum(&mut self, _n_variants: uint,
- _get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+ _get_disr: extern unsafe fn(ptr: *Opaque) -> Disr,
_sz: uint, _align: uint) -> bool {
// FIXME (#3732): this needs to rewind between enum variants, or something.
true
}
fn visit_enter_enum_variant(&mut self, _variant: uint,
- _disr_val: int,
+ _disr_val: Disr,
_n_fields: uint,
_name: &str) -> bool { true }
fn visit_enum_variant_field(&mut self, _i: uint, _offset: uint, inner: *TyDesc) -> bool {
self.visit_inner(inner)
}
fn visit_leave_enum_variant(&mut self, _variant: uint,
- _disr_val: int,
+ _disr_val: Disr,
_n_fields: uint,
_name: &str) -> bool { true }
fn visit_leave_enum(&mut self, _n_variants: uint,
- _get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+ _get_disr: extern unsafe fn(ptr: *Opaque) -> Disr,
_sz: uint, _align: uint) -> bool { true }
fn visit_enter_fn(&mut self, _purity: uint, _proto: uint,
#[feature(managed_boxes)];
-use std::unstable::intrinsics::{TyDesc, get_tydesc, visit_tydesc, TyVisitor, Opaque};
+use std::unstable::intrinsics::{TyDesc, get_tydesc, visit_tydesc, TyVisitor, Disr, Opaque};
struct MyVisitor {
types: @mut ~[~str],
_sz: uint, _align: uint) -> bool { true }
fn visit_enter_enum(&mut self, _n_variants: uint,
- _get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+ _get_disr: extern unsafe fn(ptr: *Opaque) -> Disr,
_sz: uint, _align: uint) -> bool { true }
fn visit_enter_enum_variant(&mut self,
_variant: uint,
- _disr_val: int,
+ _disr_val: Disr,
_n_fields: uint,
_name: &str) -> bool { true }
fn visit_enum_variant_field(&mut self, _i: uint, _offset: uint, _inner: *TyDesc) -> bool { true }
fn visit_leave_enum_variant(&mut self,
_variant: uint,
- _disr_val: int,
+ _disr_val: Disr,
_n_fields: uint,
_name: &str) -> bool { true }
fn visit_leave_enum(&mut self,
_n_variants: uint,
- _get_disr: extern unsafe fn(ptr: *Opaque) -> int,
+ _get_disr: extern unsafe fn(ptr: *Opaque) -> Disr,
_sz: uint, _align: uint) -> bool { true }
fn visit_enter_fn(&mut self, _purity: uint, _proto: uint,
--- /dev/null
+// Copyright 2013 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/*!
+ * Tests the range assertion wraparound case in trans::middle::adt::load_discr.
+ */
+
+#[repr(u8)]
+enum Eu { Lu = 0, Hu = 255 }
+static CLu: Eu = Lu;
+static CHu: Eu = Hu;
+
+#[repr(i8)]
+enum Es { Ls = -128, Hs = 127 }
+static CLs: Es = Ls;
+static CHs: Es = Hs;
+
+pub fn main() {
+ assert_eq!((Hu as u8) + 1, Lu as u8);
+ assert_eq!((Hs as i8) + 1, Ls as i8);
+ assert_eq!(CLu as u8, Lu as u8);
+ assert_eq!(CHu as u8, Hu as u8);
+ assert_eq!(CLs as i8, Ls as i8);
+ assert_eq!(CHs as i8, Hs as i8);
+}
--- /dev/null
+// Copyright 2013 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[feature(macro_rules)];
+
+use std::mem::size_of;
+
+macro_rules! check {
+ ($t:ty, $sz:expr, $($e:expr, $s:expr),*) => {{
+ assert_eq!(size_of::<$t>(), $sz);
+ $({
+ static S: $t = $e;
+ let v: $t = $e;
+ assert_eq!(S, v);
+ assert_eq!(format!("{:?}", v), ~$s);
+ assert_eq!(format!("{:?}", S), ~$s);
+ });*
+ }}
+}
+
+pub fn main() {
+ check!(Option<u8>, 2,
+ None, "None",
+ Some(129u8), "Some(129u8)");
+ check!(Option<i16>, 4,
+ None, "None",
+ Some(-20000i16), "Some(-20000i16)");
+ check!(Either<u8, i8>, 2,
+ Left(132u8), "Left(132u8)",
+ Right(-32i8), "Right(-32i8)");
+ check!(Either<u8, i16>, 4,
+ Left(132u8), "Left(132u8)",
+ Right(-20000i16), "Right(-20000i16)");
+}
let _b = Foo;
};
- let s = x.unwrap_err().move::<SendStr>().unwrap();
+ let s = x.unwrap_err().move::<&'static str>().unwrap();
assert_eq!(s.as_slice(), "This failure should happen.");
}
--- /dev/null
+// Copyright 2013 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+static mut destructions : int = 3;
+
+pub fn foo() {
+ #[unsafe_no_drop_flag]
+ struct Foo;
+
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ unsafe { destructions -= 1 };
+ }
+ };
+
+ let _x = [Foo, Foo, Foo];
+}
+
+pub fn main() {
+ foo();
+ assert!((unsafe { destructions } == 0));
+}