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