]> git.proxmox.com Git - rustc.git/blob - src/libcore/repr.rs
Imported Upstream version 0.6
[rustc.git] / src / libcore / repr.rs
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.
4 //
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.
10
11 /*!
12
13 More runtime type reflection
14
15 */
16
17 use cast::transmute;
18 use char;
19 use intrinsic;
20 use intrinsic::{TyDesc, TyVisitor, visit_tydesc};
21 use io::{Writer, WriterUtil};
22 use libc::c_void;
23 use managed;
24 use ptr;
25 use reflect;
26 use reflect::{MovePtr, align};
27 use sys;
28 use to_str::ToStr;
29 use vec::UnboxedVecRepr;
30 use vec::raw::{VecRepr, SliceRepr};
31 use vec;
32
33 #[cfg(test)] use io;
34
35 pub use managed::raw::BoxRepr;
36
37 /// Helpers
38
39 trait EscapedCharWriter {
40 fn write_escaped_char(&self, ch: char);
41 }
42
43 impl EscapedCharWriter for @Writer {
44 fn write_escaped_char(&self, ch: char) {
45 match ch {
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),
53 _ => {
54 // FIXME #4423: This is inefficient because it requires a
55 // malloc.
56 self.write_str(char::escape_unicode(ch))
57 }
58 }
59 }
60 }
61
62 /// Representations
63
64 trait Repr {
65 fn write_repr(&self, writer: @Writer);
66 }
67
68 impl Repr for () {
69 fn write_repr(&self, writer: @Writer) { writer.write_str("()"); }
70 }
71
72 impl Repr for bool {
73 fn write_repr(&self, writer: @Writer) {
74 writer.write_str(if *self { "true" } else { "false" })
75 }
76 }
77
78 impl Repr for int {
79 fn write_repr(&self, writer: @Writer) { writer.write_int(*self); }
80 }
81 impl Repr for i8 {
82 fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); }
83 }
84 impl Repr for i16 {
85 fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); }
86 }
87 impl Repr for i32 {
88 fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); }
89 }
90 impl Repr for i64 {
91 // FIXME #4424: This can lose precision.
92 fn write_repr(&self, writer: @Writer) { writer.write_int(*self as int); }
93 }
94
95 impl Repr for uint {
96 fn write_repr(&self, writer: @Writer) { writer.write_uint(*self); }
97 }
98 impl Repr for u8 {
99 fn write_repr(&self, writer: @Writer) {
100 writer.write_uint(*self as uint);
101 }
102 }
103 impl Repr for u16 {
104 fn write_repr(&self, writer: @Writer) {
105 writer.write_uint(*self as uint);
106 }
107 }
108 impl Repr for u32 {
109 fn write_repr(&self, writer: @Writer) {
110 writer.write_uint(*self as uint);
111 }
112 }
113 impl Repr for u64 {
114 // FIXME #4424: This can lose precision.
115 fn write_repr(&self, writer: @Writer) {
116 writer.write_uint(*self as uint);
117 }
118 }
119
120 impl Repr for float {
121 // FIXME #4423: This mallocs.
122 fn write_repr(&self, writer: @Writer) { writer.write_str(self.to_str()); }
123 }
124 impl Repr for f32 {
125 // FIXME #4423 This mallocs.
126 fn write_repr(&self, writer: @Writer) { writer.write_str(self.to_str()); }
127 }
128 impl Repr for f64 {
129 // FIXME #4423: This mallocs.
130 fn write_repr(&self, writer: @Writer) { writer.write_str(self.to_str()); }
131 }
132
133 impl Repr for char {
134 fn write_repr(&self, writer: @Writer) { writer.write_char(*self); }
135 }
136
137
138 // New implementation using reflect::MovePtr
139
140 enum VariantState {
141 Degenerate,
142 TagMatch,
143 TagMismatch,
144 }
145
146 pub struct ReprVisitor {
147 mut ptr: *c_void,
148 mut ptr_stk: ~[*c_void],
149 mut var_stk: ~[VariantState],
150 writer: @Writer
151 }
152 pub fn ReprVisitor(ptr: *c_void, writer: @Writer) -> ReprVisitor {
153 ReprVisitor { ptr: ptr,
154 ptr_stk: ~[],
155 var_stk: ~[],
156 writer: writer }
157 }
158
159 impl MovePtr for ReprVisitor {
160 #[inline(always)]
161 fn move_ptr(&self, adjustment: &fn(*c_void) -> *c_void) {
162 self.ptr = adjustment(self.ptr);
163 }
164 fn push_ptr(&self) {
165 self.ptr_stk.push(self.ptr);
166 }
167 fn pop_ptr(&self) {
168 self.ptr = self.ptr_stk.pop();
169 }
170 }
171
172 pub impl ReprVisitor {
173
174 // Various helpers for the TyVisitor impl
175
176 #[inline(always)]
177 fn get<T>(&self, f: &fn(&T)) -> bool {
178 unsafe {
179 f(transmute::<*c_void,&T>(copy self.ptr));
180 }
181 true
182 }
183
184 #[inline(always)]
185 fn bump(&self, sz: uint) {
186 do self.move_ptr() |p| {
187 ((p as uint) + sz) as *c_void
188 };
189 }
190
191 #[inline(always)]
192 fn bump_past<T>(&self) {
193 self.bump(sys::size_of::<T>());
194 }
195
196 #[inline(always)]
197 fn visit_inner(&self, inner: *TyDesc) -> bool {
198 self.visit_ptr_inner(self.ptr, inner)
199 }
200
201 #[inline(always)]
202 fn visit_ptr_inner(&self, ptr: *c_void, inner: *TyDesc) -> bool {
203 unsafe {
204 let mut u = ReprVisitor(ptr, self.writer);
205 let v = reflect::MovePtrAdaptor(u);
206 visit_tydesc(inner, @v as @TyVisitor);
207 true
208 }
209 }
210
211 #[inline(always)]
212 fn write<T:Repr>(&self) -> bool {
213 do self.get |v:&T| {
214 v.write_repr(self.writer);
215 }
216 }
217
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);
222 }
223 self.writer.write_char('"');
224 }
225
226 fn write_mut_qualifier(&self, mtbl: uint) {
227 if mtbl == 0 {
228 self.writer.write_str("mut ");
229 } else if mtbl == 1 {
230 // skip, this is ast::m_imm
231 } else {
232 assert!(mtbl == 2);
233 self.writer.write_str("const ");
234 }
235 }
236
237 fn write_vec_range(&self, mtbl: uint, ptr: *u8, len: uint,
238 inner: *TyDesc) -> bool {
239 let mut p = ptr;
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) {
245 if first {
246 first = false;
247 } else {
248 self.writer.write_str(", ");
249 }
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;
253 }
254 self.writer.write_char(']');
255 true
256 }
257
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),
261 v.fill, inner)
262 }
263
264
265 }
266
267 impl TyVisitor for ReprVisitor {
268 fn visit_bot(&self) -> bool {
269 self.writer.write_str("!");
270 true
271 }
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>() }
279
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>() }
285
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>() }
289
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('\'');
295 }
296 }
297
298 // Type no longer exists, vestigial function.
299 fn visit_str(&self) -> bool { fail!(); }
300
301 fn visit_estr_box(&self) -> bool {
302 do self.get::<@str> |s| {
303 self.writer.write_char('@');
304 self.write_escaped_slice(*s);
305 }
306 }
307 fn visit_estr_uniq(&self) -> bool {
308 do self.get::<~str> |s| {
309 self.writer.write_char('~');
310 self.write_escaped_slice(*s);
311 }
312 }
313 fn visit_estr_slice(&self) -> bool {
314 do self.get::<&str> |s| {
315 self.write_escaped_slice(*s);
316 }
317 }
318
319 // Type no longer exists, vestigial function.
320 fn visit_estr_fixed(&self, _n: uint, _sz: uint,
321 _align: uint) -> bool { fail!(); }
322
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);
329 }
330 }
331
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);
338 }
339 }
340
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 *())",
344 *p as uint));
345 }
346 }
347
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);
353 }
354 }
355
356 // Type no longer exists, vestigial function.
357 fn visit_vec(&self, _mtbl: uint, _inner: *TyDesc) -> bool { fail!(); }
358
359
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);
363 }
364 }
365
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);
370 }
371 }
372
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);
377 }
378 }
379
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);
384 }
385 }
386
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);
391 }
392 }
393
394 fn visit_enter_rec(&self, _n_fields: uint,
395 _sz: uint, _align: uint) -> bool {
396 self.writer.write_char('{');
397 true
398 }
399
400 fn visit_rec_field(&self, i: uint, name: &str,
401 mtbl: uint, inner: *TyDesc) -> bool {
402 if i != 0 {
403 self.writer.write_str(", ");
404 }
405 self.write_mut_qualifier(mtbl);
406 self.writer.write_str(name);
407 self.writer.write_str(": ");
408 self.visit_inner(inner);
409 true
410 }
411
412 fn visit_leave_rec(&self, _n_fields: uint,
413 _sz: uint, _align: uint) -> bool {
414 self.writer.write_char('}');
415 true
416 }
417
418 fn visit_enter_class(&self, _n_fields: uint,
419 _sz: uint, _align: uint) -> bool {
420 self.writer.write_char('{');
421 true
422 }
423 fn visit_class_field(&self, i: uint, name: &str,
424 mtbl: uint, inner: *TyDesc) -> bool {
425 if i != 0 {
426 self.writer.write_str(", ");
427 }
428 self.write_mut_qualifier(mtbl);
429 self.writer.write_str(name);
430 self.writer.write_str(": ");
431 self.visit_inner(inner);
432 true
433 }
434 fn visit_leave_class(&self, _n_fields: uint,
435 _sz: uint, _align: uint) -> bool {
436 self.writer.write_char('}');
437 true
438 }
439
440 fn visit_enter_tup(&self, _n_fields: uint,
441 _sz: uint, _align: uint) -> bool {
442 self.writer.write_char('(');
443 true
444 }
445 fn visit_tup_field(&self, i: uint, inner: *TyDesc) -> bool {
446 if i != 0 {
447 self.writer.write_str(", ");
448 }
449 self.visit_inner(inner);
450 true
451 }
452 fn visit_leave_tup(&self, _n_fields: uint,
453 _sz: uint, _align: uint) -> bool {
454 if _n_fields == 1 {
455 self.writer.write_char(',');
456 }
457 self.writer.write_char(')');
458 true
459 }
460
461 fn visit_enter_enum(&self, n_variants: uint,
462 _sz: uint, _align: uint) -> bool {
463 if n_variants == 1 {
464 self.var_stk.push(Degenerate)
465 } else {
466 self.var_stk.push(TagMatch)
467 }
468 true
469 }
470
471 fn visit_enter_enum_variant(&self, _variant: uint,
472 disr_val: int,
473 n_fields: uint,
474 name: &str) -> bool {
475 let mut write = false;
476 match self.var_stk.pop() {
477 Degenerate => {
478 write = true;
479 self.var_stk.push(Degenerate);
480 }
481 TagMatch | TagMismatch => {
482 do self.get::<int>() |t| {
483 if disr_val == *t {
484 write = true;
485 self.var_stk.push(TagMatch);
486 } else {
487 self.var_stk.push(TagMismatch);
488 }
489 };
490 self.bump_past::<int>();
491 }
492 }
493
494 if write {
495 self.writer.write_str(name);
496 if n_fields > 0 {
497 self.writer.write_char('(');
498 }
499 }
500 true
501 }
502
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 => {
506 if i != 0 {
507 self.writer.write_str(", ");
508 }
509 if ! self.visit_inner(inner) {
510 return false;
511 }
512 }
513 TagMismatch => ()
514 }
515 true
516 }
517
518 fn visit_leave_enum_variant(&self, _variant: uint,
519 _disr_val: int,
520 n_fields: uint,
521 _name: &str) -> bool {
522 match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] {
523 Degenerate | TagMatch => {
524 if n_fields > 0 {
525 self.writer.write_char(')');
526 }
527 }
528 TagMismatch => ()
529 }
530 true
531 }
532
533 fn visit_leave_enum(&self, _n_variants: uint,
534 _sz: uint, _align: uint) -> bool {
535 self.var_stk.pop();
536 true
537 }
538
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 {
542 true
543 }
544 fn visit_fn_output(&self, _retstyle: uint, _inner: *TyDesc) -> bool {
545 true
546 }
547 fn visit_leave_fn(&self, _purity: uint, _proto: uint,
548 _n_inputs: uint, _retstyle: uint) -> bool { true }
549
550
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 }
557
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);
563 }
564 }
565
566 // Type no longer exists, vestigial function.
567 fn visit_constr(&self, _inner: *TyDesc) -> bool { fail!(); }
568
569 fn visit_closure_ptr(&self, _ck: uint) -> bool { true }
570 }
571
572 pub fn write_repr<T>(writer: @Writer, object: &T) {
573 unsafe {
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)
579 }
580 }
581
582 #[test]
583 struct P {a: int, b: float}
584
585 #[test]
586 fn test_repr() {
587
588 fn exact_test<T>(t: &T, e:&str) {
589 let s : &str = io::with_str_writer(|w| write_repr(w, t));
590 if s != e {
591 error!("expected '%s', got '%s'",
592 e, s);
593 }
594 assert!(s == e);
595 }
596
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\"");
604
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");
610 let mut x = 10;
611 exact_test(&(&mut x), "&mut 10");
612
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]),
617 "@[1, 2, 3, 4]");
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"),
631 "(10, ~\"hello\")");
632 exact_test(&(10_u16, ~"hello"),
633 "(10, ~\"hello\")");
634 exact_test(&(10_u32, ~"hello"),
635 "(10, ~\"hello\")");
636 exact_test(&(10_u64, ~"hello"),
637 "(10, ~\"hello\")");
638 }