]> git.lizzy.rs Git - rust.git/blob - src/test/run-pass/issue-3563-3.rs
3c4c4889ba2f81c6a6f1c100a7ad405797dea275
[rust.git] / src / test / run-pass / issue-3563-3.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 // ASCII art shape renderer.
12 // Demonstrates traits, impls, operator overloading, non-copyable struct, unit testing.
13 // To run execute: rustc --test shapes.rs && ./shapes
14
15 // Rust's std library is tightly bound to the language itself so it is automatically linked in.
16 // However the extra library is designed to be optional (for code that must run on constrained
17 //  environments like embedded devices or special environments like kernel code) so it must
18 // be explicitly linked in.
19 extern mod extra;
20
21 // Extern mod controls linkage. Use controls the visibility of names to modules that are
22 // already linked in. Using WriterUtil allows us to use the write_line method.
23 use std::io::WriterUtil;
24 use std::io;
25 use std::str;
26 use std::vec;
27
28 // Represents a position on a canvas.
29 struct Point {
30     x: int,
31     y: int,
32 }
33
34 // Represents an offset on a canvas. (This has the same structure as a Point.
35 // but different semantics).
36 struct Size {
37     width: int,
38     height: int,
39 }
40
41 struct Rect {
42     top_left: Point,
43     size: Size,
44 }
45
46 // TODO: operators
47
48 // Contains the information needed to do shape rendering via ASCII art.
49 struct AsciiArt {
50     width: uint,
51     height: uint,
52     priv fill: char,
53     priv lines: ~[~[char]],
54
55     // This struct can be quite large so we'll disable copying: developers need
56     // to either pass these structs around via borrowed pointers or move them.
57 }
58
59 impl Drop for AsciiArt {
60     fn drop(&self) {}
61 }
62
63 // It's common to define a constructor sort of function to create struct instances.
64 // If there is a canonical constructor it is typically named the same as the type.
65 // Other constructor sort of functions are typically named from_foo, from_bar, etc.
66 fn AsciiArt(width: uint, height: uint, fill: char) -> AsciiArt {
67     // Use an anonymous function to build a vector of vectors containing
68     // blank characters for each position in our canvas.
69     let lines = do vec::build(Some(height)) |push| {
70             do height.times {
71                 push(vec::from_elem(width, '.'));
72             }
73         };
74
75     // Rust code often returns values by omitting the trailing semi-colon
76     // instead of using an explicit return statement.
77     AsciiArt {width: width, height: height, fill: fill, lines: lines}
78 }
79
80 // Methods particular to the AsciiArt struct.
81 impl AsciiArt {
82     fn add_pt(&mut self, x: int, y: int) {
83         if x >= 0 && x < self.width as int {
84             if y >= 0 && y < self.height as int {
85                 // Note that numeric types don't implicitly convert to each other.
86                 let v = y as uint;
87                 let h = x as uint;
88
89                 // Vector subscripting will normally copy the element, but &v[i]
90                 // will return a reference which is what we need because the
91                 // element is:
92                 // 1) potentially large
93                 // 2) needs to be modified
94                 let row = &mut self.lines[v];
95                 row[h] = self.fill;
96             }
97         }
98     }
99 }
100
101 // Allows AsciiArt to be converted to a string using the libcore ToStr trait.
102 // Note that the %s fmt! specifier will not call this automatically.
103 impl ToStr for AsciiArt {
104     fn to_str(&self) -> ~str {
105         // Convert each line into a string.
106         let lines = do self.lines.map |line| {str::from_chars(*line)};
107
108         // Concatenate the lines together using a new-line.
109         lines.connect("\n")
110     }
111 }
112
113 // This is similar to an interface in other languages: it defines a protocol which
114 // developers can implement for arbitrary concrete types.
115 trait Canvas {
116     fn add_point(&mut self, shape: Point);
117     fn add_rect(&mut self, shape: Rect);
118
119     // Unlike interfaces traits support default implementations.
120     // Got an ICE as soon as I added this method.
121     fn add_points(&mut self, shapes: &[Point]) {
122         for pt in shapes.iter() {self.add_point(*pt)};
123     }
124 }
125
126 // Here we provide an implementation of the Canvas methods for AsciiArt.
127 // Other implementations could also be provided (e.g. for PDF or Apple's Quartz)
128 // and code can use them polymorphically via the Canvas trait.
129 impl Canvas for AsciiArt {
130     fn add_point(&mut self, shape: Point) {
131         self.add_pt(shape.x, shape.y);
132     }
133
134     fn add_rect(&mut self, shape: Rect) {
135         // Add the top and bottom lines.
136         for x in range(shape.top_left.x, shape.top_left.x + shape.size.width) {
137             self.add_pt(x, shape.top_left.y);
138             self.add_pt(x, shape.top_left.y + shape.size.height - 1);
139         }
140
141         // Add the left and right lines.
142         for y in range(shape.top_left.y, shape.top_left.y + shape.size.height) {
143             self.add_pt(shape.top_left.x, y);
144             self.add_pt(shape.top_left.x + shape.size.width - 1, y);
145         }
146     }
147 }
148
149 // Rust's unit testing framework is currently a bit under-developed so we'll use
150 // this little helper.
151 pub fn check_strs(actual: &str, expected: &str) -> bool {
152     if actual != expected {
153         io::stderr().write_line(fmt!("Found:\n%s\nbut expected\n%s", actual, expected));
154         return false;
155     }
156     return true;
157 }
158
159
160 fn test_ascii_art_ctor() {
161     let art = AsciiArt(3, 3, '*');
162     assert!(check_strs(art.to_str(), "...\n...\n..."));
163 }
164
165
166 fn test_add_pt() {
167     let mut art = AsciiArt(3, 3, '*');
168     art.add_pt(0, 0);
169     art.add_pt(0, -10);
170     art.add_pt(1, 2);
171     assert!(check_strs(art.to_str(), "*..\n...\n.*."));
172 }
173
174
175 fn test_shapes() {
176     let mut art = AsciiArt(4, 4, '*');
177     art.add_rect(Rect {top_left: Point {x: 0, y: 0}, size: Size {width: 4, height: 4}});
178     art.add_point(Point {x: 2, y: 2});
179     assert!(check_strs(art.to_str(), "****\n*..*\n*.**\n****"));
180 }
181
182 pub fn main() {
183     test_ascii_art_ctor();
184     test_add_pt();
185     test_shapes();
186 }