1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 More runtime type reflection
20 use intrinsic
::{TyDesc, TyVisitor, visit_tydesc}
;
21 use io
::{Writer, WriterUtil}
;
26 use reflect
::{MovePtr, align}
;
29 use vec
::UnboxedVecRepr
;
30 use vec
::raw
::{VecRepr, SliceRepr}
;
35 pub use managed
::raw
::BoxRepr
;
39 trait EscapedCharWriter
{
40 fn write_escaped_char(&self, ch
: char);
43 impl EscapedCharWriter
for @Writer
{
44 fn write_escaped_char(&self, ch
: char) {
46 '
\t'
=> self.write_str("\\t"),
47 '
\r'
=> self.write_str("\\r"),
48 '
\n'
=> self.write_str("\\n"),
49 '
\\'
=> self.write_str("\\\\"),
50 '
\''
=> self.write_str("\\'"),
51 '
"' => self.write_str("\\\""),
52 '\x20'..'\x7e' => self.write_char(ch),
54 // FIXME #4423: This is inefficient because it requires a
56 self.write_str(char::escape_unicode(ch))
65 fn write_repr(&self, writer: @Writer);
69 fn write_repr(&self, writer: @Writer) { writer.write_str("()"); }
73 fn write_repr(&self, writer: @Writer) {
74 writer.write_str(if *self { "true" } else { "false" })
79 fn write_repr(&self, writer: @Writer) { writer.write_int(*self); }
82 fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); }
85 fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); }
88 fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); }
91 // FIXME #4424: This can lose precision.
92 fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); }
96 fn write_repr(&self, writer: @Writer) { writer.write_uint(*self); }
99 fn write_repr(&self, writer: @Writer) {
100 writer.write_uint(*self as uint);
104 fn write_repr(&self, writer: @Writer) {
105 writer.write_uint(*self as uint);
109 fn write_repr(&self, writer: @Writer) {
110 writer.write_uint(*self as uint);
114 // FIXME #4424: This can lose precision.
115 fn write_repr(&self, writer: @Writer) {
116 writer.write_uint(*self as uint);
120 impl Repr for float {
121 // FIXME #4423: This mallocs.
122 fn write_repr(&self, writer: @Writer) { writer.write_str(self.to_str()); }
125 // FIXME #4423 This mallocs.
126 fn write_repr(&self, writer: @Writer) { writer.write_str(self.to_str()); }
129 // FIXME #4423: This mallocs.
130 fn write_repr(&self, writer: @Writer) { writer.write_str(self.to_str()); }
134 fn write_repr(&self, writer: @Writer) { writer.write_char(*self); }
138 // New implementation using reflect::MovePtr
146 pub struct ReprVisitor {
148 mut ptr_stk: ~[*c_void],
149 mut var_stk: ~[VariantState],
152 pub fn ReprVisitor(ptr: *c_void, writer: @Writer) -> ReprVisitor {
153 ReprVisitor { ptr: ptr,
159 impl MovePtr for ReprVisitor {
161 fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void) {
162 self.ptr = adjustment(self.ptr);
165 self.ptr_stk.push(self.ptr);
168 self.ptr = self.ptr_stk.pop();
172 pub impl ReprVisitor {
174 // Various helpers for the TyVisitor impl
177 fn get<T>(&self, f: &fn(&T)) -> bool {
179 f(transmute::<*c_void,&T>(copy self.ptr));
185 fn bump(&self, sz: uint) {
186 do self.move_ptr() |p| {
187 ((p as uint) + sz) as *c_void
192 fn bump_past<T>(&self) {
193 self.bump(sys::size_of::<T>());
197 fn visit_inner(&self, inner: *TyDesc) -> bool {
198 self.visit_ptr_inner(self.ptr, inner)
202 fn visit_ptr_inner(&self, ptr: *c_void, inner: *TyDesc) -> bool {
204 let mut u = ReprVisitor(ptr, self.writer);
205 let v = reflect::MovePtrAdaptor(u);
206 visit_tydesc(inner, @v as @TyVisitor);
212 fn write<T:Repr>(&self) -> bool {
214 v.write_repr(self.writer);
218 fn write_escaped_slice(&self, slice: &str) {
219 self.writer.write_char('"'
);
220 for slice
.each_char
|ch
| {
221 self.writer
.write_escaped_char(ch
);
223 self.writer
.write_char('
"');
226 fn write_mut_qualifier(&self, mtbl: uint) {
228 self.writer.write_str("mut ");
229 } else if mtbl == 1 {
230 // skip, this is ast::m_imm
233 self.writer.write_str("const ");
237 fn write_vec_range(&self, mtbl: uint, ptr: *u8, len: uint,
238 inner: *TyDesc) -> bool {
240 let end = ptr::offset(p, len);
241 let (sz, al) = unsafe { ((*inner).size, (*inner).align) };
242 self.writer.write_char('[');
243 let mut first = true;
244 while (p as uint) < (end as uint) {
248 self.writer.write_str(", ");
250 self.write_mut_qualifier(mtbl);
251 self.visit_ptr_inner(p as *c_void, inner);
252 p = align(ptr::offset(p, sz) as uint, al) as *u8;
254 self.writer.write_char(']');
258 fn write_unboxed_vec_repr(&self, mtbl: uint, v: &UnboxedVecRepr,
259 inner: *TyDesc) -> bool {
260 self.write_vec_range(mtbl, ptr::to_unsafe_ptr(&v.data),
267 impl TyVisitor for ReprVisitor {
268 fn visit_bot(&self) -> bool {
269 self.writer.write_str("!");
272 fn visit_nil(&self) -> bool { self.write::<()>() }
273 fn visit_bool(&self) -> bool { self.write::<bool>() }
274 fn visit_int(&self) -> bool { self.write::<int>() }
275 fn visit_i8(&self) -> bool { self.write::<i8>() }
276 fn visit_i16(&self) -> bool { self.write::<i16>() }
277 fn visit_i32(&self) -> bool { self.write::<i32>() }
278 fn visit_i64(&self) -> bool { self.write::<i64>() }
280 fn visit_uint(&self) -> bool { self.write::<uint>() }
281 fn visit_u8(&self) -> bool { self.write::<u8>() }
282 fn visit_u16(&self) -> bool { self.write::<u16>() }
283 fn visit_u32(&self) -> bool { self.write::<u32>() }
284 fn visit_u64(&self) -> bool { self.write::<u64>() }
286 fn visit_float(&self) -> bool { self.write::<float>() }
287 fn visit_f32(&self) -> bool { self.write::<f32>() }
288 fn visit_f64(&self) -> bool { self.write::<f64>() }
290 fn visit_char(&self) -> bool {
291 do self.get::<char> |&ch| {
292 self.writer.write_char('\'');
293 self.writer.write_escaped_char(ch);
294 self.writer.write_char('\'');
298 // Type no longer exists, vestigial function.
299 fn visit_str(&self) -> bool { fail!(); }
301 fn visit_estr_box(&self) -> bool {
302 do self.get::<@str> |s| {
303 self.writer.write_char('@');
304 self.write_escaped_slice(*s);
307 fn visit_estr_uniq(&self) -> bool {
308 do self.get::<~str> |s| {
309 self.writer.write_char('~');
310 self.write_escaped_slice(*s);
313 fn visit_estr_slice(&self) -> bool {
314 do self.get::<&str> |s| {
315 self.write_escaped_slice(*s);
319 // Type no longer exists, vestigial function.
320 fn visit_estr_fixed(&self, _n: uint, _sz: uint,
321 _align: uint) -> bool { fail!(); }
323 fn visit_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
324 self.writer.write_char('@');
325 self.write_mut_qualifier(mtbl);
326 do self.get::<&managed::raw::BoxRepr> |b| {
327 let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
328 self.visit_ptr_inner(p, inner);
332 fn visit_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool {
333 self.writer.write_char('~');
334 self.write_mut_qualifier(mtbl);
335 do self.get::<&managed::raw::BoxRepr> |b| {
336 let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
337 self.visit_ptr_inner(p, inner);
341 fn visit_ptr(&self, _mtbl: uint, _inner: *TyDesc) -> bool {
342 do self.get::<*c_void> |p| {
343 self.writer.write_str(fmt!("(0x
%x
as *())",
348 fn visit_rptr(&self, mtbl: uint, inner: *TyDesc) -> bool {
349 self.writer.write_char('&');
350 self.write_mut_qualifier(mtbl);
351 do self.get::<*c_void> |p| {
352 self.visit_ptr_inner(*p, inner);
356 // Type no longer exists, vestigial function.
357 fn visit_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { fail!(); }
360 fn visit_unboxed_vec(&self, mtbl: uint, inner: *TyDesc) -> bool {
361 do self.get::<vec::UnboxedVecRepr> |b| {
362 self.write_unboxed_vec_repr(mtbl, b, inner);
366 fn visit_evec_box(&self, mtbl: uint, inner: *TyDesc) -> bool {
367 do self.get::<&VecRepr> |b| {
368 self.writer.write_char('@');
369 self.write_unboxed_vec_repr(mtbl, &b.unboxed, inner);
373 fn visit_evec_uniq(&self, mtbl: uint, inner: *TyDesc) -> bool {
374 do self.get::<&VecRepr> |b| {
375 self.writer.write_char('~');
376 self.write_unboxed_vec_repr(mtbl, &b.unboxed, inner);
380 fn visit_evec_slice(&self, mtbl: uint, inner: *TyDesc) -> bool {
381 do self.get::<SliceRepr> |s| {
382 self.writer.write_char('&');
383 self.write_vec_range(mtbl, s.data, s.len, inner);
387 fn visit_evec_fixed(&self, _n: uint, sz: uint, _align: uint,
388 mtbl: uint, inner: *TyDesc) -> bool {
389 do self.get::<u8> |b| {
390 self.write_vec_range(mtbl, ptr::to_unsafe_ptr(b), sz, inner);
394 fn visit_enter_rec(&self, _n_fields: uint,
395 _sz: uint, _align: uint) -> bool {
396 self.writer.write_char('{');
400 fn visit_rec_field(&self, i: uint, name: &str,
401 mtbl: uint, inner: *TyDesc) -> bool {
403 self.writer.write_str(", ");
405 self.write_mut_qualifier(mtbl);
406 self.writer.write_str(name);
407 self.writer.write_str(": ");
408 self.visit_inner(inner);
412 fn visit_leave_rec(&self, _n_fields: uint,
413 _sz: uint, _align: uint) -> bool {
414 self.writer.write_char('}');
418 fn visit_enter_class(&self, _n_fields: uint,
419 _sz: uint, _align: uint) -> bool {
420 self.writer.write_char('{');
423 fn visit_class_field(&self, i: uint, name: &str,
424 mtbl: uint, inner: *TyDesc) -> bool {
426 self.writer.write_str(", ");
428 self.write_mut_qualifier(mtbl);
429 self.writer.write_str(name);
430 self.writer.write_str(": ");
431 self.visit_inner(inner);
434 fn visit_leave_class(&self, _n_fields: uint,
435 _sz: uint, _align: uint) -> bool {
436 self.writer.write_char('}');
440 fn visit_enter_tup(&self, _n_fields: uint,
441 _sz: uint, _align: uint) -> bool {
442 self.writer.write_char('(');
445 fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool {
447 self.writer.write_str(", ");
449 self.visit_inner(inner);
452 fn visit_leave_tup(&self, _n_fields: uint,
453 _sz: uint, _align: uint) -> bool {
455 self.writer.write_char(',');
457 self.writer.write_char(')');
461 fn visit_enter_enum(&self, n_variants: uint,
462 _sz: uint, _align: uint) -> bool {
464 self.var_stk.push(Degenerate)
466 self.var_stk.push(TagMatch)
471 fn visit_enter_enum_variant(&self, _variant: uint,
474 name: &str) -> bool {
475 let mut write = false;
476 match self.var_stk.pop() {
479 self.var_stk.push(Degenerate);
481 TagMatch | TagMismatch => {
482 do self.get::<int>() |t| {
485 self.var_stk.push(TagMatch);
487 self.var_stk.push(TagMismatch);
490 self.bump_past::<int>();
495 self.writer.write_str(name);
497 self.writer.write_char('(');
503 fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool {
504 match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] {
505 Degenerate | TagMatch => {
507 self.writer.write_str(", ");
509 if ! self.visit_inner(inner) {
518 fn visit_leave_enum_variant(&self, _variant: uint,
521 _name: &str) -> bool {
522 match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] {
523 Degenerate | TagMatch => {
525 self.writer.write_char(')');
533 fn visit_leave_enum(&self, _n_variants: uint,
534 _sz: uint, _align: uint) -> bool {
539 fn visit_enter_fn(&self, _purity: uint, _proto: uint,
540 _n_inputs: uint, _retstyle: uint) -> bool { true }
541 fn visit_fn_input(&self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool {
544 fn visit_fn_output(&self, _retstyle: uint, _inner: *TyDesc) -> bool {
547 fn visit_leave_fn(&self, _purity: uint, _proto: uint,
548 _n_inputs: uint, _retstyle: uint) -> bool { true }
551 fn visit_trait(&self) -> bool { true }
552 fn visit_var(&self) -> bool { true }
553 fn visit_var_integral(&self) -> bool { true }
554 fn visit_param(&self, _i: uint) -> bool { true }
555 fn visit_self(&self) -> bool { true }
556 fn visit_type(&self) -> bool { true }
558 fn visit_opaque_box(&self) -> bool {
559 self.writer.write_char('@');
560 do self.get::<&managed::raw::BoxRepr> |b| {
561 let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
562 self.visit_ptr_inner(p, b.header.type_desc);
566 // Type no longer exists, vestigial function.
567 fn visit_constr(&self, _inner: *TyDesc) -> bool { fail!(); }
569 fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
572 pub fn write_repr<T>(writer: @Writer, object: &T) {
574 let ptr = ptr::to_unsafe_ptr(object) as *c_void;
575 let tydesc = intrinsic::get_tydesc::<T>();
576 let mut u = ReprVisitor(ptr, writer);
577 let v = reflect::MovePtrAdaptor(u);
578 visit_tydesc(tydesc, @v as @TyVisitor)
583 struct P {a: int, b: float}
588 fn exact_test<T>(t: &T, e:&str) {
589 let s : &str = io::with_str_writer(|w| write_repr(w, t));
591 error!("expected '
%s'
, got '
%s'
",
597 exact_test(&10, "10");
598 exact_test(&true, "true");
599 exact_test(&false, "false");
600 exact_test(&1.234, "1.234");
601 exact_test(&(&"hello
"), "\"hello
\"");
602 exact_test(&(@"hello
"), "@
\"hello
\"");
603 exact_test(&(~"he
\u10f3llo
"), "~\"he
\\u10f3llo
\"");
605 // FIXME #4210: the mut fields are a bit off here.
606 exact_test(&(@10), "@
10");
607 exact_test(&(@mut 10), "@
10");
608 exact_test(&(~10), "~10");
609 exact_test(&(&10), "&10");
611 exact_test(&(&mut x), "&mut 10");
613 exact_test(&(1,), "(1,)");
614 exact_test(&(@[1,2,3,4,5,6,7,8]),
615 "@
[1, 2, 3, 4, 5, 6, 7, 8]");
616 exact_test(&(@[1u8,2u8,3u8,4u8]),
618 exact_test(&(@["hi
", "there
"]),
619 "@
[\"hi
\", \"there
\"]");
620 exact_test(&(~["hi
", "there
"]),
621 "~[\"hi
\", \"there
\"]");
622 exact_test(&(&["hi
", "there
"]),
623 "&[\"hi
\", \"there
\"]");
624 exact_test(&(P{a:10, b:1.234}),
625 "{a: 10, b: 1.234}
");
626 exact_test(&(@P{a:10, b:1.234}),
627 "@{a: 10, b: 1.234}
");
628 exact_test(&(~P{a:10, b:1.234}),
629 "~{a: 10, b: 1.234}
");
630 exact_test(&(10_u8, ~"hello
"),
632 exact_test(&(10_u16, ~"hello
"),
634 exact_test(&(10_u32, ~"hello
"),
636 exact_test(&(10_u64, ~"hello
"),