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