<commit_before>use std::mem;

use orbclient::{Color, Event, EventOption, Window};
use orbclient::event;

const BLACK: Color = Color::rgb(0, 0, 0);
const RED: Color = Color::rgb(194, 54, 33);
const GREEN: Color = Color::rgb(37, 188, 36);
const YELLOW: Color = Color::rgb(173, 173, 39);
const BLUE: Color = Color::rgb(73, 46, 225);
const MAGENTA: Color = Color::rgb(211, 56, 211);
const CYAN: Color = Color::rgb(51, 187, 200);
const WHITE: Color = Color::rgb(203, 204, 205);

pub struct Console {
    pub window: Box<Window>,
    pub point_x: i32,
    pub point_y: i32,
    pub foreground: Color,
    pub background: Color,
    pub redraw: bool,
    pub command: String,
    pub escape: bool,
    pub escape_sequence: bool,
    pub sequence: Vec<String>,
    pub raw_mode: bool,
}

impl Console {
    pub fn new() -> Console {
        let mut window = Window::new(-1, -1, 640, 480, "Terminal").unwrap();
        window.sync();
        Console {
            window: window,
            point_x: 0,
            point_y: 0,
            foreground: WHITE,
            background: BLACK,
            redraw: true,
            command: String::new(),
            escape: false,
            escape_sequence: false,
            sequence: Vec::new(),
            raw_mode: false,
        }
    }

    pub fn code(&mut self, c: char) {
        if self.escape_sequence {
            match c {
                '0' ... '9' => {
                    // Add a number to the sequence list
                    if let Some(mut value) = self.sequence.last_mut() {
                        value.push(c);
                    }
                },
                ';' => {
                    // Split sequence into list
                    self.sequence.push(String::new());
                },
                'm' => {
                    // Display attributes
                    for value in self.sequence.iter() {
                        match value.as_str() {
                            "0" => {
                                self.foreground = WHITE;
                                self.background = BLACK;
                            },
                            "30" => self.foreground = BLACK,
                            "31" => self.foreground = RED,
                            "32" => self.foreground = GREEN,
                            "33" => self.foreground = YELLOW,
                            "34" => self.foreground = BLUE,
                            "35" => self.foreground = MAGENTA,
                            "36" => self.foreground = CYAN,
                            "37" => self.foreground = WHITE,
                            "40" => self.background = BLACK,
                            "41" => self.background = RED,
                            "42" => self.background = GREEN,
                            "43" => self.background = YELLOW,
                            "44" => self.background = BLUE,
                            "45" => self.background = MAGENTA,
                            "46" => self.background = CYAN,
                            "47" => self.background = WHITE,
                            _ => {},
                        }
                    }
                    self.escape_sequence = false;
                },
                'H' | 'f' => {
                    self.window.rect(self.point_x, self.point_y, 8, 16, self.background);

                    let row = self.sequence.get(0).map_or("", |p| &p).parse::<i32>().unwrap_or(0);
                    self.point_y = row * 16;

                    let col = self.sequence.get(1).map_or("", |p| &p).parse::<i32>().unwrap_or(0);
                    self.point_x = col * 8;

                    self.window.rect(self.point_x, self.point_y, 8, 16, self.foreground);
                    self.redraw = true;

                    self.escape_sequence = false;
                },
/*
@MANSTART{terminal-raw-mode}
INTRODUCTION
    Since Redox has no ioctl syscall, it uses escape codes for switching to raw mode.

ENTERING AND EXITING RAW MODE
    Entering raw mode is done using CSI-r (^[r). Unsetting raw mode is done by CSI-R (^[R).

RAW MODE
    Raw mode means that the stdin must be handled solely by the program itself. It will not automatically be printed nor will it be modified in any way (modulo escape codes).

    This means that:
        - stdin is not printed.
        - newlines are interpreted as carriage returns in stdin.
        - stdin is not buffered, meaning that the stream of bytes goes directly to the program, without the user having to press enter.
@MANEND
*/
                'r' => self.raw_mode = true,
                'R' => self.raw_mode = false,
                _ => self.escape_sequence = false,

            }

            if !self.escape_sequence {
                self.sequence.clear();
                self.escape = false;
            }
        } else {
            match c {
                '[' => {
                    // Control sequence initiator

                    self.escape_sequence = true;
                    self.sequence.push(String::new());
                },
                'c' => {
                    // Reset
                    self.point_x = 0;
                    self.point_y = 0;
                    self.foreground = WHITE;
                    self.background = BLACK;
                    self.window.set(self.background);
                    self.redraw = true;

                    self.escape = false;
                }
                _ => self.escape = false,
            }
        }
    }

    pub fn scroll(&mut self, rows: usize) {
        if rows > 0 && rows < self.window.height() as usize {
            let offset = rows * self.window.width() as usize;
            let data = self.window.data_mut();
            for i in 0..data.len() - offset {
                let color = data[i + offset];
                data[i] = color;
            }
            for i in data.len() - offset..data.len() {
                data[i] = self.background;
            }
        }
    }

    pub fn character(&mut self, c: char) {
        self.window.rect(self.point_x, self.point_y, 8, 16, self.background);

        match c {
            '\0' => {},
            '\x1B' => self.escape = true,
            '\n' if self.raw_mode => self.point_x = 0,
            '\n' => {
                self.point_x = 0;
                self.point_y += 16;
            },
            '\t' => self.point_x = ((self.point_x / 64) + 1) * 64,
            '\r' => self.point_x = 0,
            '\x08' if self.raw_mode => {},
            '\x08' => {
                self.point_x -= 8;
                if self.point_x < 0 {
                    self.point_x = 0
                }
                self.window.rect(self.point_x, self.point_y, 8, 16, self.background);
            },
            _ => {
                self.window.char(self.point_x, self.point_y, c, self.foreground);
                self.point_x += 8;
            }
        }

        if self.point_x >= self.window.width() as i32 {
            self.point_x = 0;
            self.point_y += 16;
        }

        while self.point_y + 16 > self.window.height() as i32 {
            self.scroll(16);
            self.point_y -= 16;
        }
        self.window.rect(self.point_x, self.point_y, 8, 16, self.foreground);
        self.redraw = true;
    }

    pub fn event(&mut self, event: Event) -> Option<String> {
        match event.to_option() {
            EventOption::Key(key_event) => {
                if key_event.pressed {
                    match key_event.scancode {
                        event::K_BKSP => if !self.command.is_empty() {
                            self.write(&[8]);
                            self.command.pop();
                        },
                        _ => match key_event.character {
                            '\0' => (),
                            c => {
                                self.command.push(c);
                                if !self.raw_mode {
                                    self.write(&[c as u8]);
                                }

                                if c == '\n' {
                                    let mut command = String::new();
                                    mem::swap(&mut self.command, &mut command);
                                    return Some(command);
                                }
                            }
                        },
                    }
                }
            },
            _ => (),
        }

        None
    }

    pub fn write(&mut self, bytes: &[u8]) {
        for byte in bytes.iter() {
            let c = *byte as char;

            if self.escape {
                self.code(c);
            } else {
                self.character(c);
            }
        }

        if self.redraw {
            self.redraw = false;
            self.window.sync();
        }
    }
}
<commit_msg>Fix raw mode<commit_after>use std::mem;

use orbclient::{Color, Event, EventOption, Window};
use orbclient::event;

const BLACK: Color = Color::rgb(0, 0, 0);
const RED: Color = Color::rgb(194, 54, 33);
const GREEN: Color = Color::rgb(37, 188, 36);
const YELLOW: Color = Color::rgb(173, 173, 39);
const BLUE: Color = Color::rgb(73, 46, 225);
const MAGENTA: Color = Color::rgb(211, 56, 211);
const CYAN: Color = Color::rgb(51, 187, 200);
const WHITE: Color = Color::rgb(203, 204, 205);

pub struct Console {
    pub window: Box<Window>,
    pub point_x: i32,
    pub point_y: i32,
    pub foreground: Color,
    pub background: Color,
    pub redraw: bool,
    pub command: String,
    pub escape: bool,
    pub escape_sequence: bool,
    pub sequence: Vec<String>,
    pub raw_mode: bool,
}

impl Console {
    pub fn new() -> Console {
        let mut window = Window::new(-1, -1, 640, 480, "Terminal").unwrap();
        window.sync();
        Console {
            window: window,
            point_x: 0,
            point_y: 0,
            foreground: WHITE,
            background: BLACK,
            redraw: true,
            command: String::new(),
            escape: false,
            escape_sequence: false,
            sequence: Vec::new(),
            raw_mode: false,
        }
    }

    pub fn code(&mut self, c: char) {
        if self.escape_sequence {
            match c {
                '0' ... '9' => {
                    // Add a number to the sequence list
                    if let Some(mut value) = self.sequence.last_mut() {
                        value.push(c);
                    }
                },
                ';' => {
                    // Split sequence into list
                    self.sequence.push(String::new());
                },
                'm' => {
                    // Display attributes
                    for value in self.sequence.iter() {
                        match value.as_str() {
                            "0" => {
                                self.foreground = WHITE;
                                self.background = BLACK;
                            },
                            "30" => self.foreground = BLACK,
                            "31" => self.foreground = RED,
                            "32" => self.foreground = GREEN,
                            "33" => self.foreground = YELLOW,
                            "34" => self.foreground = BLUE,
                            "35" => self.foreground = MAGENTA,
                            "36" => self.foreground = CYAN,
                            "37" => self.foreground = WHITE,
                            "40" => self.background = BLACK,
                            "41" => self.background = RED,
                            "42" => self.background = GREEN,
                            "43" => self.background = YELLOW,
                            "44" => self.background = BLUE,
                            "45" => self.background = MAGENTA,
                            "46" => self.background = CYAN,
                            "47" => self.background = WHITE,
                            _ => {},
                        }
                    }
                    self.escape_sequence = false;
                },
                'J' => {
                    match self.sequence.get(0).map_or("", |p| &p).parse::<usize>().unwrap_or(0) {
                        0 => {
                            //TODO: Erase down
                        },
                        1 => {
                            //TODO: Erase up
                        },
                        2 => {
                            // Erase all
                            self.point_x = 0;
                            self.point_y = 0;
                            self.window.set(self.background);
                            self.redraw = true;
                        },
                        _ => {}
                    }

                    self.escape_sequence = false;
                },
                'H' | 'f' => {
                    self.window.rect(self.point_x, self.point_y, 8, 16, self.background);

                    let row = self.sequence.get(0).map_or("", |p| &p).parse::<i32>().unwrap_or(0);
                    self.point_y = row * 16;

                    let col = self.sequence.get(1).map_or("", |p| &p).parse::<i32>().unwrap_or(0);
                    self.point_x = col * 8;

                    self.window.rect(self.point_x, self.point_y, 8, 16, self.foreground);
                    self.redraw = true;

                    self.escape_sequence = false;
                },
/*
@MANSTART{terminal-raw-mode}
INTRODUCTION
    Since Redox has no ioctl syscall, it uses escape codes for switching to raw mode.

ENTERING AND EXITING RAW MODE
    Entering raw mode is done using CSI-r (^[r). Unsetting raw mode is done by CSI-R (^[R).

RAW MODE
    Raw mode means that the stdin must be handled solely by the program itself. It will not automatically be printed nor will it be modified in any way (modulo escape codes).

    This means that:
        - stdin is not printed.
        - newlines are interpreted as carriage returns in stdin.
        - stdin is not buffered, meaning that the stream of bytes goes directly to the program, without the user having to press enter.
@MANEND
*/
                'r' => self.raw_mode = true,
                'R' => self.raw_mode = false,
                _ => self.escape_sequence = false,

            }

            if !self.escape_sequence {
                self.sequence.clear();
                self.escape = false;
            }
        } else {
            match c {
                '[' => {
                    // Control sequence initiator

                    self.escape_sequence = true;
                    self.sequence.push(String::new());
                },
                'c' => {
                    // Reset
                    self.point_x = 0;
                    self.point_y = 0;
                    self.raw_mode = false;
                    self.foreground = WHITE;
                    self.background = BLACK;
                    self.window.set(self.background);
                    self.redraw = true;

                    self.escape = false;
                }
                _ => self.escape = false,
            }
        }
    }

    pub fn scroll(&mut self, rows: usize) {
        if rows > 0 && rows < self.window.height() as usize {
            let offset = rows * self.window.width() as usize;
            let data = self.window.data_mut();
            for i in 0..data.len() - offset {
                let color = data[i + offset];
                data[i] = color;
            }
            for i in data.len() - offset..data.len() {
                data[i] = self.background;
            }
        }
    }

    pub fn character(&mut self, c: char) {
        self.window.rect(self.point_x, self.point_y, 8, 16, self.background);

        match c {
            '\0' => {},
            '\x1B' => self.escape = true,
            '\n' => {
                self.point_x = 0;
                self.point_y += 16;
            },
            '\t' => self.point_x = ((self.point_x / 64) + 1) * 64,
            '\r' => self.point_x = 0,
            '\x08' => {
                self.point_x -= 8;
                if self.point_x < 0 {
                    self.point_x = 0
                }
                self.window.rect(self.point_x, self.point_y, 8, 16, self.background);
            },
            _ => {
                self.window.char(self.point_x, self.point_y, c, self.foreground);
                self.point_x += 8;
            }
        }

        if self.point_x >= self.window.width() as i32 {
            self.point_x = 0;
            self.point_y += 16;
        }

        while self.point_y + 16 > self.window.height() as i32 {
            self.scroll(16);
            self.point_y -= 16;
        }
        self.window.rect(self.point_x, self.point_y, 8, 16, self.foreground);
        self.redraw = true;
    }

    pub fn event(&mut self, event: Event) -> Option<String> {
        match event.to_option() {
            EventOption::Key(key_event) => {
                if key_event.pressed {
                    if self.raw_mode {
                        match key_event.scancode {
                            event::K_BKSP => self.command.push_str("\x08 \x08"),
                            event::K_UP => self.command.push_str("\x1B[A"),
                            event::K_DOWN => self.command.push_str("\x1B[B"),
                            event::K_RIGHT => self.command.push_str("\x1B[C"),
                            event::K_LEFT => self.command.push_str("\x1B[D"),
                            _ => match key_event.character {
                                '\0' => {},
                                c => {
                                    self.command.push(c);
                                }
                            },
                        }

                        if ! self.command.is_empty() {
                            let mut command = String::new();
                            mem::swap(&mut self.command, &mut command);
                            return Some(command);
                        }
                    } else {
                        match key_event.scancode {
                            event::K_BKSP => if ! self.command.is_empty() {
                                self.write(&[8]);
                                self.command.pop();
                            },
                            _ => match key_event.character {
                                '\0' => (),
                                c => {
                                    self.write(&[c as u8]);
                                    self.command.push(c);

                                    if c == '\n' {
                                        let mut command = String::new();
                                        mem::swap(&mut self.command, &mut command);
                                        return Some(command);
                                    }
                                }
                            },
                        }
                    }
                }
            },
            _ => (),
        }

        None
    }

    pub fn write(&mut self, bytes: &[u8]) {
        for byte in bytes.iter() {
            let c = *byte as char;

            if self.escape {
                self.code(c);
            } else {
                self.character(c);
            }
        }

        if self.redraw {
            self.redraw = false;
            self.window.sync();
        }
    }
}
<|endoftext|>


<commit_before>	use std::io::{Read, Error};

enum State {
	Code,
	Quote(u8),
	Escape(u8),
	SingleLineComment,
	MultLineComment,
}

/**
 * Filter for removing comments from preprocessed C/C++ code.
 */
pub struct CommentsRemover<R> {
	r: R,
	state: State,
	last: Option<u8>,
}

impl<R: Read> CommentsRemover<R> {
	pub fn new(r: R) -> CommentsRemover<R> {
		CommentsRemover {
			r: r,
			state: State::Code,
			last: None,
		}
	}
}

impl<R: Read> Read for CommentsRemover<R> {
	fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
		if buf.len() == 0 {
			return Ok(0);
		}
		let size = try! (self.r.read(buf));
		let mut offset = 0;
		for index in 0..size {
			let c = buf[index];
			match self.state {
				State::Code => {
					match c {
						b'"' | b'\'' => {
							self.state = State::Quote(c);
						}
						b'/' if self.last == Some(b'/') => {
							self.last = None;
							self.state = State::SingleLineComment;
						}
						b'*' if self.last == Some(b'/') => {
							self.last = None;
							self.state = State::MultLineComment;
						}
						c => {
							match self.last {
								Some(last) => {
									buf[offset] = last;
									offset += 1;
								}
								None => {
								}
							}
							self.last = Some(c);
							continue;
						}
					};
				}
				State::Escape(q) => {
					self.state = State::Quote(q);
				}
				State::Quote(q) => {
					match c {
						b'\\' => {
							self.state = State::Escape(q);
						}
						c if c == q => {
							self.state = State::Code;
						}
						_ => {
						}
					}
				}
				State::SingleLineComment => {
					match c {
						b'\n' | b'\r' => {
							self.state = State::Code;
						}
						_ => {
						}
					}
				}
				State::MultLineComment => {
					match c {
						b'/' if self.last == Some(b'*') => {
							self.last = None;
							self.state = State::Code;
							continue;
						}
						v => {
							self.last = Some(v);
						}
					}
				}
			}
			match self.state {
				State::Code | State::Quote(_) | State::Escape(_) => {
					match self.last {
						Some(c) => {
							buf[offset] = c;
							offset += 1;
						}
						None => {
						}
					}
					self.last = Some(c);
				}
				State::SingleLineComment | State::MultLineComment => {
				}
			}
		}
		if offset < buf.len() {
			match self.state {
				State::Code | State::Quote(_) | State::Escape(_) => {
					match self.last {
						Some(c) if c == b'/' => {
						}
						Some(c) => {
							buf[offset] = c;
							offset += 1;
							self.last = None;
						}
						None => {
						}
					}
				}
				State::SingleLineComment | State::MultLineComment => {
				}
			}
		}
		if size == 0 {
			return Ok(offset);
		}
		match offset {
			0 => self.read(buf),
			_ => Ok(offset),
		}
	}
}

#[cfg(test)]
mod test {
	use std::io::{Read, Write, Cursor};
	use super::CommentsRemover;

	fn check_filter_pass(original: &str, expected: &str, block_size: usize) {
		let mut stream: Vec<u8> = Vec::new();
		stream.write(original.as_bytes()).unwrap();

		let mut filter = CommentsRemover::new(Cursor::new(stream));
		let mut actual = Vec::new();
		let mut buffer = vec![0; block_size];
		loop {
			let size = filter.read(&mut buffer).unwrap();
			if size == 0 {
				break;
			}
			actual.write(&buffer[0..size]).unwrap();
//			assert!(actual.len() <= expected.len());
		}
		assert_eq!(expected, String::from_utf8(actual).unwrap());
	}

	fn check_filter(original: &str, expected: &str) {
		check_filter_pass(original, expected, 1);
		check_filter_pass(original, expected, 10);
		check_filter_pass(original, expected, expected.len() - 1);
		check_filter_pass(original, expected, original.len() - 1);
		check_filter_pass(original, expected, expected.len());
		check_filter_pass(original, expected, original.len());
	}

	#[test]
	fn test_filter_no_comments() {
		let source = r#"#line 1 "sample.cpp"
#line 1 "e:/work/octobuild/test_cl/sample header.h"
# pragma once
void hello();
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#;
		check_filter(source, source);
	}

	#[test]
	fn test_filter_simple_comments() {
		check_filter(
r#"// Some data
#line 1 "e:/work//octobuild/test_cl/sample /* header */.h"
# pragma once /*/ foo */
void hello();
//#line 2 "sample.cpp"

int main(int argc, char **argv /* // Arguments */) {
	return 0;
}
"#,
r#"
#line 1 "e:/work//octobuild/test_cl/sample /* header */.h"
# pragma once
void hello();

int main(int argc, char **argv ) {
	return 0;
}
"#
		);
	}
}
<commit_msg>Fix multiline comments processing<commit_after>	use std::io::{Read, Error};

enum State {
	Code,
	Quote(u8),
	Escape(u8),
	SingleLineComment,
	MultLineComment,
}

/**
 * Filter for removing comments from preprocessed C/C++ code.
 */
pub struct CommentsRemover<R> {
	r: R,
	state: State,
	last: Option<u8>,
}

impl<R: Read> CommentsRemover<R> {
	pub fn new(r: R) -> CommentsRemover<R> {
		CommentsRemover {
			r: r,
			state: State::Code,
			last: None,
		}
	}
}

impl<R: Read> Read for CommentsRemover<R> {
	fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
		if buf.len() == 0 {
			return Ok(0);
		}
		let size = try! (self.r.read(buf));
		let mut offset = 0;
		for index in 0..size {
			let c = buf[index];
			match self.state {
				State::Code => {
					match c {
						b'"' | b'\'' => {
							self.state = State::Quote(c);
						}
						b'/' if self.last == Some(b'/') => {
							self.last = None;
							self.state = State::SingleLineComment;
						}
						b'*' if self.last == Some(b'/') => {
							self.last = None;
							self.state = State::MultLineComment;
						}
						c => {
							match self.last {
								Some(last) => {
									buf[offset] = last;
									offset += 1;
								}
								None => {
								}
							}
							self.last = Some(c);
							continue;
						}
					};
				}
				State::Escape(q) => {
					self.state = State::Quote(q);
				}
				State::Quote(q) => {
					match c {
						b'\\' => {
							self.state = State::Escape(q);
						}
						c if c == q => {
							self.state = State::Code;
						}
						_ => {
						}
					}
				}
				State::SingleLineComment => {
					match c {
						b'\n' | b'\r' => {
							self.state = State::Code;
						}
						_ => {
						}
					}
				}
				State::MultLineComment => {
					match c {
						b'/' if self.last == Some(b'*') => {
							self.last = None;
							self.state = State::Code;
							continue;
						}
						v => {
							self.last = Some(v);
						}
					}
				}
			}
			match self.state {
				State::Code | State::Quote(_) | State::Escape(_) => {
					match self.last {
						Some(c) => {
							buf[offset] = c;
							offset += 1;
						}
						None => {
						}
					}
					self.last = Some(c);
				}
				State::MultLineComment => {
					match c {
						b'\n' | b'\r' => {
							buf[offset] = c;
							offset += 1;
						}
						_ => {
						}
					}
				}
				State::SingleLineComment => {
				}
			}
		}
		if offset < buf.len() {
			match self.state {
				State::Code | State::Quote(_) | State::Escape(_) => {
					match self.last {
						Some(c) if c == b'/' => {
						}
						Some(c) => {
							buf[offset] = c;
							offset += 1;
							self.last = None;
						}
						None => {
						}
					}
				}
				State::SingleLineComment | State::MultLineComment => {
				}
			}
		}
		if size == 0 {
			return Ok(offset);
		}
		match offset {
			0 => self.read(buf),
			_ => Ok(offset),
		}
	}
}

#[cfg(test)]
mod test {
	use std::io::{Read, Write, Cursor};
	use super::CommentsRemover;

	fn check_filter_pass(original: &str, expected: &str, block_size: usize) {
		let mut stream: Vec<u8> = Vec::new();
		stream.write(original.as_bytes()).unwrap();

		let mut filter = CommentsRemover::new(Cursor::new(stream));
		let mut actual = Vec::new();
		let mut buffer = vec![0; block_size];
		loop {
			let size = filter.read(&mut buffer).unwrap();
			if size == 0 {
				break;
			}
			actual.write(&buffer[0..size]).unwrap();
//			assert!(actual.len() <= expected.len());
		}
		assert_eq!(expected, String::from_utf8(actual).unwrap());
	}

	fn check_filter(original: &str, expected: &str) {
		check_filter_pass(original, expected, 1);
		check_filter_pass(original, expected, 10);
		check_filter_pass(original, expected, expected.len() - 1);
		check_filter_pass(original, expected, original.len() - 1);
		check_filter_pass(original, expected, expected.len());
		check_filter_pass(original, expected, original.len());
	}

	#[test]
	fn test_filter_no_comments() {
		let source = r#"#line 1 "sample.cpp"
#line 1 "e:/work/octobuild/test_cl/sample header.h"
# pragma once
void hello();
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#;
		check_filter(source, source);
	}

	#[test]
	fn test_filter_simple_comments() {
		check_filter(
r#"// Some data
#line 1 "e:/work//octobuild/test_cl/sample /* header */.h"
# pragma once /*/ foo */
void hello();
//#line 2 "sample.cpp"

int main(int argc, char **argv /* // Arguments */) {
/*
 * Multiline
 */
	return 0;
}
"#,
r#"
#line 1 "e:/work//octobuild/test_cl/sample /* header */.h"
# pragma once
void hello();

int main(int argc, char **argv ) {

	return 0;
}
"#
		);
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*! The Rust Runtime, including the task scheduler and I/O

The `rt` module provides the private runtime infrastructure necessary
to support core language features like the exchange and local heap,
the garbage collector, logging, local data and unwinding. It also
implements the default task scheduler and task model. Initialization
routines are provided for setting up runtime resources in common
configurations, including that used by `rustc` when generating
executables.

It is intended that the features provided by `rt` can be factored in a
way such that the core library can be built with different 'profiles'
for different use cases, e.g. excluding the task scheduler. A number
of runtime features though are critical to the functioning of the
language and an implementation must be provided regardless of the
execution environment.

Of foremost importance is the global exchange heap, in the module
`global_heap`. Very little practical Rust code can be written without
access to the global heap. Unlike most of `rt` the global heap is
truly a global resource and generally operates independently of the
rest of the runtime.

All other runtime features are task-local, including the local heap,
the garbage collector, local storage, logging and the stack unwinder.

The relationship between `rt` and the rest of the core library is
not entirely clear yet and some modules will be moving into or
out of `rt` as development proceeds.

Several modules in `core` are clients of `rt`:

* `core::task` - The user-facing interface to the Rust task model.
* `core::task::local_data` - The interface to local data.
* `core::gc` - The garbage collector.
* `core::unstable::lang` - Miscellaneous lang items, some of which rely on `core::rt`.
* `core::condition` - Uses local data.
* `core::cleanup` - Local heap destruction.
* `core::io` - In the future `core::io` will use an `rt` implementation.
* `core::logging`
* `core::pipes`
* `core::comm`
* `core::stackwalk`

*/

#[doc(hidden)];
#[deny(unused_imports)];
#[deny(unused_mut)];
#[deny(unused_variable)];

use cell::Cell;
use clone::Clone;
use container::Container;
use from_str::FromStr;
use iterator::IteratorUtil;
use option::{Some, None};
use os;
use ptr::RawPtr;
use uint;
use rt::sched::{Scheduler, Coroutine, Shutdown};
use rt::sleeper_list::SleeperList;
use rt::task::Task;
use rt::thread::Thread;
use rt::work_queue::WorkQueue;
use rt::uv::uvio::UvEventLoop;
use unstable::atomics::{AtomicInt, SeqCst};
use unstable::sync::UnsafeAtomicRcBox;
use vec::{OwnedVector, MutableVector};

/// The global (exchange) heap.
pub mod global_heap;

/// Implementations of language-critical runtime features like @.
pub mod task;

/// The coroutine task scheduler, built on the `io` event loop.
mod sched;

/// Synchronous I/O.
#[path = "io/mod.rs"]
pub mod io;

/// The EventLoop and internal synchronous I/O interface.
mod rtio;

/// libuv and default rtio implementation.
#[path = "uv/mod.rs"]
pub mod uv;

/// The Local trait for types that are accessible via thread-local
/// or task-local storage.
pub mod local;

/// A parallel work-stealing deque.
mod work_queue;

/// A parallel queue.
mod message_queue;

/// A parallel data structure for tracking sleeping schedulers.
mod sleeper_list;

/// Stack segments and caching.
mod stack;

/// CPU context swapping.
mod context;

/// Bindings to system threading libraries.
mod thread;

/// The runtime configuration, read from environment variables
pub mod env;

/// The local, managed heap
mod local_heap;

/// The Logger trait and implementations
pub mod logging;

/// Tools for testing the runtime
pub mod test;

/// Reference counting
pub mod rc;

/// A simple single-threaded channel type for passing buffered data between
/// scheduler and task context
pub mod tube;

/// Simple reimplementation of core::comm
pub mod comm;

// FIXME #5248 shouldn't be pub
/// The runtime needs to be able to put a pointer into thread-local storage.
pub mod local_ptr;

// FIXME #5248: The import in `sched` doesn't resolve unless this is pub!
/// Bindings to pthread/windows thread-local storage.
pub mod thread_local_storage;

/// A concurrent data structure with which parent tasks wait on child tasks.
pub mod join_latch;

pub mod metrics;

// FIXME #5248 shouldn't be pub
/// Just stuff
pub mod util;

/// Set up a default runtime configuration, given compiler-supplied arguments.
///
/// This is invoked by the `start` _language item_ (unstable::lang) to
/// run a Rust executable.
///
/// # Arguments
///
/// * `argc` & `argv` - The argument vector. On Unix this information is used
///   by os::args.
/// * `crate_map` - Runtime information about the executing crate, mostly for logging
///
/// # Return value
///
/// The return value is used as the process return code. 0 on success, 101 on error.
pub fn start(_argc: int, _argv: **u8, crate_map: *u8, main: ~fn()) -> int {

    init(crate_map);
    let exit_code = run(main);
    cleanup();

    return exit_code;
}

/// One-time runtime initialization. Currently all this does is set up logging
/// based on the RUST_LOG environment variable.
pub fn init(crate_map: *u8) {
    logging::init(crate_map);
}

pub fn cleanup() {
    global_heap::cleanup();
}

pub fn run(main: ~fn()) -> int {
    static DEFAULT_ERROR_CODE: int = 101;

    let nthreads = match os::getenv("RUST_THREADS") {
        Some(nstr) => FromStr::from_str(nstr).get(),
        None => unsafe { util::num_cpus() }
    };

    let sleepers = SleeperList::new();
    let work_queue = WorkQueue::new();

    let mut handles = ~[];
    let mut scheds = ~[];

    for uint::range(0, nthreads) |_| {
        let loop_ = ~UvEventLoop::new();
        let mut sched = ~Scheduler::new(loop_, work_queue.clone(), sleepers.clone());
        let handle = sched.make_handle();

        handles.push(handle);
        scheds.push(sched);
    }

    let exit_code = UnsafeAtomicRcBox::new(AtomicInt::new(0));
    let exit_code_clone = exit_code.clone();

    let main_cell = Cell::new(main);
    let handles = Cell::new(handles);
    let mut new_task = ~Task::new_root();
    let on_exit: ~fn(bool) = |exit_success| {

        let mut handles = handles.take();
        // Tell schedulers to exit
        for handles.mut_iter().advance |handle| {
            handle.send(Shutdown);
        }

        unsafe {
            let exit_code = if exit_success { 0 } else { DEFAULT_ERROR_CODE };
            (*exit_code_clone.get()).store(exit_code, SeqCst);
        }
    };
    new_task.on_exit = Some(on_exit);
    let main_task = ~Coroutine::with_task(&mut scheds[0].stack_pool,
                                          new_task, main_cell.take());
    scheds[0].enqueue_task(main_task);

    let mut threads = ~[];

    while !scheds.is_empty() {
        let sched = scheds.pop();
        let sched_cell = Cell::new(sched);
        let thread = do Thread::start {
            let sched = sched_cell.take();
            sched.run();
        };

        threads.push(thread);
    }

    // Wait for schedulers
    let _threads = threads;

    unsafe {
        (*exit_code.get()).load(SeqCst)
    }
}

/// Possible contexts in which Rust code may be executing.
/// Different runtime services are available depending on context.
/// Mostly used for determining if we're using the new scheduler
/// or the old scheduler.
#[deriving(Eq)]
pub enum RuntimeContext {
    // Only the exchange heap is available
    GlobalContext,
    // The scheduler may be accessed
    SchedulerContext,
    // Full task services, e.g. local heap, unwinding
    TaskContext,
    // Running in an old-style task
    OldTaskContext
}

/// Determine the current RuntimeContext
pub fn context() -> RuntimeContext {

    use task::rt::rust_task;
    use self::local::Local;
    use self::sched::Scheduler;

    // XXX: Hitting TLS twice to check if the scheduler exists
    // then to check for the task is not good for perf
    if unsafe { rust_try_get_task().is_not_null() } {
        return OldTaskContext;
    } else {
        if Local::exists::<Scheduler>() {
            let context = Cell::new_empty();
            do Local::borrow::<Scheduler, ()> |sched| {
                if sched.in_task_context() {
                    context.put_back(TaskContext);
                } else {
                    context.put_back(SchedulerContext);
                }
            }
            return context.take();
        } else {
            return GlobalContext;
        }
    }

    pub extern {
        #[rust_stack]
        fn rust_try_get_task() -> *rust_task;
    }
}

#[test]
fn test_context() {
    use unstable::run_in_bare_thread;
    use self::sched::{Scheduler, Coroutine};
    use rt::local::Local;
    use rt::test::new_test_uv_sched;

    assert_eq!(context(), OldTaskContext);
    do run_in_bare_thread {
        assert_eq!(context(), GlobalContext);
        let mut sched = ~new_test_uv_sched();
        let task = ~do Coroutine::new_root(&mut sched.stack_pool) {
            assert_eq!(context(), TaskContext);
            let sched = Local::take::<Scheduler>();
            do sched.deschedule_running_task_and_then() |sched, task| {
                assert_eq!(context(), SchedulerContext);
                sched.enqueue_task(task);
            }
        };
        sched.enqueue_task(task);
        sched.run();
    }
}
<commit_msg>std::rt: Document and cleanup the run function<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*! The Rust Runtime, including the task scheduler and I/O

The `rt` module provides the private runtime infrastructure necessary
to support core language features like the exchange and local heap,
the garbage collector, logging, local data and unwinding. It also
implements the default task scheduler and task model. Initialization
routines are provided for setting up runtime resources in common
configurations, including that used by `rustc` when generating
executables.

It is intended that the features provided by `rt` can be factored in a
way such that the core library can be built with different 'profiles'
for different use cases, e.g. excluding the task scheduler. A number
of runtime features though are critical to the functioning of the
language and an implementation must be provided regardless of the
execution environment.

Of foremost importance is the global exchange heap, in the module
`global_heap`. Very little practical Rust code can be written without
access to the global heap. Unlike most of `rt` the global heap is
truly a global resource and generally operates independently of the
rest of the runtime.

All other runtime features are task-local, including the local heap,
the garbage collector, local storage, logging and the stack unwinder.

The relationship between `rt` and the rest of the core library is
not entirely clear yet and some modules will be moving into or
out of `rt` as development proceeds.

Several modules in `core` are clients of `rt`:

* `core::task` - The user-facing interface to the Rust task model.
* `core::task::local_data` - The interface to local data.
* `core::gc` - The garbage collector.
* `core::unstable::lang` - Miscellaneous lang items, some of which rely on `core::rt`.
* `core::condition` - Uses local data.
* `core::cleanup` - Local heap destruction.
* `core::io` - In the future `core::io` will use an `rt` implementation.
* `core::logging`
* `core::pipes`
* `core::comm`
* `core::stackwalk`

*/

#[doc(hidden)];
#[deny(unused_imports)];
#[deny(unused_mut)];
#[deny(unused_variable)];

use cell::Cell;
use clone::Clone;
use container::Container;
use from_str::FromStr;
use iter::Times;
use iterator::IteratorUtil;
use option::{Some, None};
use os;
use ptr::RawPtr;
use rt::sched::{Scheduler, Coroutine, Shutdown};
use rt::sleeper_list::SleeperList;
use rt::task::Task;
use rt::thread::Thread;
use rt::work_queue::WorkQueue;
use rt::uv::uvio::UvEventLoop;
use unstable::atomics::{AtomicInt, SeqCst};
use unstable::sync::UnsafeAtomicRcBox;
use vec::{OwnedVector, MutableVector};

/// The global (exchange) heap.
pub mod global_heap;

/// Implementations of language-critical runtime features like @.
pub mod task;

/// The coroutine task scheduler, built on the `io` event loop.
mod sched;

/// Synchronous I/O.
#[path = "io/mod.rs"]
pub mod io;

/// The EventLoop and internal synchronous I/O interface.
mod rtio;

/// libuv and default rtio implementation.
#[path = "uv/mod.rs"]
pub mod uv;

/// The Local trait for types that are accessible via thread-local
/// or task-local storage.
pub mod local;

/// A parallel work-stealing deque.
mod work_queue;

/// A parallel queue.
mod message_queue;

/// A parallel data structure for tracking sleeping schedulers.
mod sleeper_list;

/// Stack segments and caching.
mod stack;

/// CPU context swapping.
mod context;

/// Bindings to system threading libraries.
mod thread;

/// The runtime configuration, read from environment variables
pub mod env;

/// The local, managed heap
mod local_heap;

/// The Logger trait and implementations
pub mod logging;

/// Tools for testing the runtime
pub mod test;

/// Reference counting
pub mod rc;

/// A simple single-threaded channel type for passing buffered data between
/// scheduler and task context
pub mod tube;

/// Simple reimplementation of core::comm
pub mod comm;

// FIXME #5248 shouldn't be pub
/// The runtime needs to be able to put a pointer into thread-local storage.
pub mod local_ptr;

// FIXME #5248: The import in `sched` doesn't resolve unless this is pub!
/// Bindings to pthread/windows thread-local storage.
pub mod thread_local_storage;

/// For waiting on child tasks.
pub mod join_latch;

pub mod metrics;

// FIXME #5248 shouldn't be pub
/// Just stuff
pub mod util;

/// Set up a default runtime configuration, given compiler-supplied arguments.
///
/// This is invoked by the `start` _language item_ (unstable::lang) to
/// run a Rust executable.
///
/// # Arguments
///
/// * `argc` & `argv` - The argument vector. On Unix this information is used
///   by os::args.
/// * `crate_map` - Runtime information about the executing crate, mostly for logging
///
/// # Return value
///
/// The return value is used as the process return code. 0 on success, 101 on error.
pub fn start(_argc: int, _argv: **u8, crate_map: *u8, main: ~fn()) -> int {

    init(crate_map);
    let exit_code = run(main);
    cleanup();

    return exit_code;
}

/// One-time runtime initialization. Currently all this does is set up logging
/// based on the RUST_LOG environment variable.
pub fn init(crate_map: *u8) {
    logging::init(crate_map);
}

/// One-time runtime cleanup.
pub fn cleanup() {
    global_heap::cleanup();
}

/// Execute the main function in a scheduler.
///
/// Configures the runtime according to the environment, by default
/// using a task scheduler with the same number of threads as cores.
/// Returns a process exit code.
pub fn run(main: ~fn()) -> int {

    static DEFAULT_ERROR_CODE: int = 101;

    let nthreads = match os::getenv("RUST_THREADS") {
        Some(nstr) => FromStr::from_str(nstr).get(),
        None => unsafe { util::num_cpus() }
    };

    // The shared list of sleeping schedulers. Schedulers wake each other
    // occassionally to do new work.
    let sleepers = SleeperList::new();
    // The shared work queue. Temporary until work stealing is implemented.
    let work_queue = WorkQueue::new();

    // The schedulers.
    let mut scheds = ~[];
    // Handles to the schedulers. When the main task ends these will be
    // sent the Shutdown message to terminate the schedulers.
    let mut handles = ~[];

    for nthreads.times {
        // Every scheduler is driven by an I/O event loop.
        let loop_ = ~UvEventLoop::new();
        let mut sched = ~Scheduler::new(loop_, work_queue.clone(), sleepers.clone());
        let handle = sched.make_handle();

        scheds.push(sched);
        handles.push(handle);
    }

    // Create a shared cell for transmitting the process exit
    // code from the main task to this function.
    let exit_code = UnsafeAtomicRcBox::new(AtomicInt::new(0));
    let exit_code_clone = exit_code.clone();

    // When the main task exits, after all the tasks in the main
    // task tree, shut down the schedulers and set the exit code.
    let handles = Cell::new(handles);
    let on_exit: ~fn(bool) = |exit_success| {

        let mut handles = handles.take();
        for handles.mut_iter().advance |handle| {
            handle.send(Shutdown);
        }

        unsafe {
            let exit_code = if exit_success { 0 } else { DEFAULT_ERROR_CODE };
            (*exit_code_clone.get()).store(exit_code, SeqCst);
        }
    };

    // Create and enqueue the main task.
    let main_cell = Cell::new(main);
    let mut new_task = ~Task::new_root();
    new_task.on_exit = Some(on_exit);
    let main_task = ~Coroutine::with_task(&mut scheds[0].stack_pool,
                                          new_task, main_cell.take());
    scheds[0].enqueue_task(main_task);

    // Run each scheduler in a thread.
    let mut threads = ~[];
    while !scheds.is_empty() {
        let sched = scheds.pop();
        let sched_cell = Cell::new(sched);
        let thread = do Thread::start {
            let sched = sched_cell.take();
            sched.run();
        };

        threads.push(thread);
    }

    // Wait for schedulers
    { let _threads = threads; }

    // Return the exit code
    unsafe {
        (*exit_code.get()).load(SeqCst)
    }
}

/// Possible contexts in which Rust code may be executing.
/// Different runtime services are available depending on context.
/// Mostly used for determining if we're using the new scheduler
/// or the old scheduler.
#[deriving(Eq)]
pub enum RuntimeContext {
    // Only the exchange heap is available
    GlobalContext,
    // The scheduler may be accessed
    SchedulerContext,
    // Full task services, e.g. local heap, unwinding
    TaskContext,
    // Running in an old-style task
    OldTaskContext
}

/// Determine the current RuntimeContext
pub fn context() -> RuntimeContext {

    use task::rt::rust_task;
    use self::local::Local;
    use self::sched::Scheduler;

    // XXX: Hitting TLS twice to check if the scheduler exists
    // then to check for the task is not good for perf
    if unsafe { rust_try_get_task().is_not_null() } {
        return OldTaskContext;
    } else {
        if Local::exists::<Scheduler>() {
            let context = Cell::new_empty();
            do Local::borrow::<Scheduler, ()> |sched| {
                if sched.in_task_context() {
                    context.put_back(TaskContext);
                } else {
                    context.put_back(SchedulerContext);
                }
            }
            return context.take();
        } else {
            return GlobalContext;
        }
    }

    pub extern {
        #[rust_stack]
        fn rust_try_get_task() -> *rust_task;
    }
}

#[test]
fn test_context() {
    use unstable::run_in_bare_thread;
    use self::sched::{Scheduler, Coroutine};
    use rt::local::Local;
    use rt::test::new_test_uv_sched;

    assert_eq!(context(), OldTaskContext);
    do run_in_bare_thread {
        assert_eq!(context(), GlobalContext);
        let mut sched = ~new_test_uv_sched();
        let task = ~do Coroutine::new_root(&mut sched.stack_pool) {
            assert_eq!(context(), TaskContext);
            let sched = Local::take::<Scheduler>();
            do sched.deschedule_running_task_and_then() |sched, task| {
                assert_eq!(context(), SchedulerContext);
                sched.enqueue_task(task);
            }
        };
        sched.enqueue_task(task);
        sched.run();
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! An owned, growable string that enforces that its contents are valid UTF-8.

use c_vec::CVec;
use char::Char;
use container::{Container, Mutable};
use fmt;
use io::Writer;
use iter::{Extendable, FromIterator, Iterator, range};
use mem;
use option::{None, Option, Some};
use ptr::RawPtr;
use slice::{OwnedVector, Vector, CloneableVector};
use str::{OwnedStr, Str, StrSlice, StrAllocating};
use str;
use vec::Vec;

/// A growable string stored as a UTF-8 encoded buffer.
#[deriving(Clone, Eq, Ord, TotalEq, TotalOrd)]
pub struct StrBuf {
    vec: Vec<u8>,
}

impl StrBuf {
    /// Creates a new string buffer initialized with the empty string.
    #[inline]
    pub fn new() -> StrBuf {
        StrBuf {
            vec: Vec::new(),
        }
    }

    /// Creates a new string buffer with the given capacity.
    #[inline]
    pub fn with_capacity(capacity: uint) -> StrBuf {
        StrBuf {
            vec: Vec::with_capacity(capacity),
        }
    }

    /// Creates a new string buffer from length, capacity, and a pointer.
    #[inline]
    pub unsafe fn from_raw_parts(length: uint, capacity: uint, ptr: *mut u8) -> StrBuf {
        StrBuf {
            vec: Vec::from_raw_parts(length, capacity, ptr),
        }
    }

    /// Creates a new string buffer from the given string.
    #[inline]
    pub fn from_str(string: &str) -> StrBuf {
        StrBuf {
            vec: Vec::from_slice(string.as_bytes())
        }
    }

    /// Creates a new string buffer from the given owned string, taking care not to copy it.
    #[inline]
    pub fn from_owned_str(string: ~str) -> StrBuf {
        StrBuf {
            vec: string.into_bytes().move_iter().collect(),
        }
    }

    /// Tries to create a new string buffer from the given byte
    /// vector, validating that the vector is UTF-8 encoded.
    #[inline]
    pub fn from_utf8(vec: Vec<u8>) -> Option<StrBuf> {
        if str::is_utf8(vec.as_slice()) {
            Some(StrBuf { vec: vec })
        } else {
            None
        }
    }

    /// Return the underlying byte buffer, encoded as UTF-8.
    #[inline]
    pub fn into_bytes(self) -> Vec<u8> {
        self.vec
    }

    /// Pushes the given string onto this buffer; then, returns `self` so that it can be used
    /// again.
    #[inline]
    pub fn append(mut self, second: &str) -> StrBuf {
        self.push_str(second);
        self
    }

    /// Creates a string buffer by repeating a character `length` times.
    #[inline]
    pub fn from_char(length: uint, ch: char) -> StrBuf {
        if length == 0 {
            return StrBuf::new()
        }

        let mut buf = StrBuf::new();
        buf.push_char(ch);
        let size = buf.len() * length;
        buf.reserve(size);
        for _ in range(1, length) {
            buf.push_char(ch)
        }
        buf
    }

    /// Pushes the given string onto this string buffer.
    #[inline]
    pub fn push_str(&mut self, string: &str) {
        self.vec.push_all(string.as_bytes())
    }

    /// Push `ch` onto the given string `count` times.
    #[inline]
    pub fn grow(&mut self, count: uint, ch: char) {
        for _ in range(0, count) {
            self.push_char(ch)
        }
    }

    /// Returns the number of bytes that this string buffer can hold without reallocating.
    #[inline]
    pub fn byte_capacity(&self) -> uint {
        self.vec.capacity()
    }

    /// Reserves capacity for at least `extra` additional bytes in this string buffer.
    #[inline]
    pub fn reserve_additional(&mut self, extra: uint) {
        self.vec.reserve_additional(extra)
    }

    /// Reserves capacity for at least `capacity` bytes in this string buffer.
    #[inline]
    pub fn reserve(&mut self, capacity: uint) {
        self.vec.reserve(capacity)
    }

    /// Reserves capacity for exactly `capacity` bytes in this string buffer.
    #[inline]
    pub fn reserve_exact(&mut self, capacity: uint) {
        self.vec.reserve_exact(capacity)
    }

    /// Shrinks the capacity of this string buffer to match its length.
    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.vec.shrink_to_fit()
    }

    /// Adds the given character to the end of the string.
    #[inline]
    pub fn push_char(&mut self, ch: char) {
        let cur_len = self.len();
        unsafe {
            // This may use up to 4 bytes.
            self.vec.reserve_additional(4);

            // Attempt to not use an intermediate buffer by just pushing bytes
            // directly onto this string.
            let mut c_vector = CVec::new(self.vec.as_mut_ptr().offset(cur_len as int), 4);
            let used = ch.encode_utf8(c_vector.as_mut_slice());
            self.vec.set_len(cur_len + used);
        }
    }

    /// Pushes the given bytes onto this string buffer. This is unsafe because it does not check
    /// to ensure that the resulting string will be valid UTF-8.
    #[inline]
    pub unsafe fn push_bytes(&mut self, bytes: &[u8]) {
        self.vec.push_all(bytes)
    }

    /// Works with the underlying buffer as a byte slice.
    #[inline]
    pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
        self.vec.as_slice()
    }

    /// Shorten a string to the specified length (which must be <= the current length)
    #[inline]
    pub fn truncate(&mut self, len: uint) {
        assert!(self.as_slice().is_char_boundary(len));
        self.vec.truncate(len)
    }

    /// Appends a byte to this string buffer. The caller must preserve the valid UTF-8 property.
    #[inline]
    pub unsafe fn push_byte(&mut self, byte: u8) {
        self.push_bytes([byte])
    }

    /// Removes the last byte from the string buffer and returns it. Returns `None` if this string
    /// buffer is empty.
    ///
    /// The caller must preserve the valid UTF-8 property.
    #[inline]
    pub unsafe fn pop_byte(&mut self) -> Option<u8> {
        let len = self.len();
        if len == 0 {
            return None
        }

        let byte = self.as_slice()[len - 1];
        self.vec.set_len(len - 1);
        Some(byte)
    }

    /// Removes the first byte from the string buffer and returns it. Returns `None` if this string
    /// buffer is empty.
    ///
    /// The caller must preserve the valid UTF-8 property.
    pub unsafe fn shift_byte(&mut self) -> Option<u8> {
        let len = self.len();
        if len == 0 {
            return None
        }

        let byte = self.as_slice()[0];
        *self = self.as_slice().slice(1, len).into_strbuf();
        Some(byte)
    }

    /// Views the string buffer as a mutable sequence of bytes.
    ///
    /// Callers must preserve the valid UTF-8 property.
    pub unsafe fn as_mut_vec<'a>(&'a mut self) -> &'a mut Vec<u8> {
        &mut self.vec
    }
}

impl Container for StrBuf {
    #[inline]
    fn len(&self) -> uint {
        self.vec.len()
    }
}

impl Mutable for StrBuf {
    #[inline]
    fn clear(&mut self) {
        self.vec.clear()
    }
}

impl FromIterator<char> for StrBuf {
    fn from_iter<I:Iterator<char>>(iterator: I) -> StrBuf {
        let mut buf = StrBuf::new();
        buf.extend(iterator);
        buf
    }
}

impl Extendable<char> for StrBuf {
    fn extend<I:Iterator<char>>(&mut self, mut iterator: I) {
        for ch in iterator {
            self.push_char(ch)
        }
    }
}

impl Str for StrBuf {
    #[inline]
    fn as_slice<'a>(&'a self) -> &'a str {
        unsafe {
            mem::transmute(self.vec.as_slice())
        }
    }
}

impl StrAllocating for StrBuf {
    #[inline]
    fn into_owned(self) -> ~str {
        unsafe {
            mem::transmute(self.vec.as_slice().to_owned())
        }
    }

    #[inline]
    fn into_strbuf(self) -> StrBuf { self }
}

impl fmt::Show for StrBuf {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }
}

impl<H:Writer> ::hash::Hash<H> for StrBuf {
    #[inline]
    fn hash(&self, hasher: &mut H) {
        self.as_slice().hash(hasher)
    }
}

#[cfg(test)]
mod tests {
    extern crate test;
    use container::{Container, Mutable};
    use self::test::Bencher;
    use str::{Str, StrSlice};
    use super::StrBuf;

    #[bench]
    fn bench_with_capacity(b: &mut Bencher) {
        b.iter(|| {
            StrBuf::with_capacity(100)
        });
    }

    #[bench]
    fn bench_push_str(b: &mut Bencher) {
        let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
        b.iter(|| {
            let mut r = StrBuf::new();
            r.push_str(s);
        });
    }

    #[test]
    fn test_push_bytes() {
        let mut s = StrBuf::from_str("ABC");
        unsafe {
            s.push_bytes([ 'D' as u8 ]);
        }
        assert_eq!(s.as_slice(), "ABCD");
    }

    #[test]
    fn test_push_str() {
        let mut s = StrBuf::new();
        s.push_str("");
        assert_eq!(s.as_slice().slice_from(0), "");
        s.push_str("abc");
        assert_eq!(s.as_slice().slice_from(0), "abc");
        s.push_str("ประเทศไทย中华Việt Nam");
        assert_eq!(s.as_slice().slice_from(0), "abcประเทศไทย中华Việt Nam");
    }

    #[test]
    fn test_push_char() {
        let mut data = StrBuf::from_str("ประเทศไทย中");
        data.push_char('华');
        data.push_char('b'); // 1 byte
        data.push_char('¢'); // 2 byte
        data.push_char('€'); // 3 byte
        data.push_char('𤭢'); // 4 byte
        assert_eq!(data.as_slice(), "ประเทศไทย中华b¢€𤭢");
    }

    #[test]
    fn test_str_truncate() {
        let mut s = StrBuf::from_str("12345");
        s.truncate(5);
        assert_eq!(s.as_slice(), "12345");
        s.truncate(3);
        assert_eq!(s.as_slice(), "123");
        s.truncate(0);
        assert_eq!(s.as_slice(), "");

        let mut s = StrBuf::from_str("12345");
        let p = s.as_slice().as_ptr();
        s.truncate(3);
        s.push_str("6");
        let p_ = s.as_slice().as_ptr();
        assert_eq!(p_, p);
    }

    #[test]
    #[should_fail]
    fn test_str_truncate_invalid_len() {
        let mut s = StrBuf::from_str("12345");
        s.truncate(6);
    }

    #[test]
    #[should_fail]
    fn test_str_truncate_split_codepoint() {
        let mut s = StrBuf::from_str("\u00FC"); // ü
        s.truncate(1);
    }

    #[test]
    fn test_str_clear() {
        let mut s = StrBuf::from_str("12345");
        s.clear();
        assert_eq!(s.len(), 0);
        assert_eq!(s.as_slice(), "");
    }
}
<commit_msg>auto merge of #14052 : dylanbraithwaite/rust/char-fns-for-strbuf, r=alexcrichton<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! An owned, growable string that enforces that its contents are valid UTF-8.

use c_vec::CVec;
use char::Char;
use container::{Container, Mutable};
use fmt;
use io::Writer;
use iter::{Extendable, FromIterator, Iterator, range};
use mem;
use option::{None, Option, Some};
use ptr::RawPtr;
use ptr;
use slice::{OwnedVector, Vector, CloneableVector};
use str::{CharRange, OwnedStr, Str, StrSlice, StrAllocating};
use str;
use vec::Vec;

/// A growable string stored as a UTF-8 encoded buffer.
#[deriving(Clone, Eq, Ord, TotalEq, TotalOrd)]
pub struct StrBuf {
    vec: Vec<u8>,
}

impl StrBuf {
    /// Creates a new string buffer initialized with the empty string.
    #[inline]
    pub fn new() -> StrBuf {
        StrBuf {
            vec: Vec::new(),
        }
    }

    /// Creates a new string buffer with the given capacity.
    #[inline]
    pub fn with_capacity(capacity: uint) -> StrBuf {
        StrBuf {
            vec: Vec::with_capacity(capacity),
        }
    }

    /// Creates a new string buffer from length, capacity, and a pointer.
    #[inline]
    pub unsafe fn from_raw_parts(length: uint, capacity: uint, ptr: *mut u8) -> StrBuf {
        StrBuf {
            vec: Vec::from_raw_parts(length, capacity, ptr),
        }
    }

    /// Creates a new string buffer from the given string.
    #[inline]
    pub fn from_str(string: &str) -> StrBuf {
        StrBuf {
            vec: Vec::from_slice(string.as_bytes())
        }
    }

    /// Creates a new string buffer from the given owned string, taking care not to copy it.
    #[inline]
    pub fn from_owned_str(string: ~str) -> StrBuf {
        StrBuf {
            vec: string.into_bytes().move_iter().collect(),
        }
    }

    /// Tries to create a new string buffer from the given byte
    /// vector, validating that the vector is UTF-8 encoded.
    #[inline]
    pub fn from_utf8(vec: Vec<u8>) -> Option<StrBuf> {
        if str::is_utf8(vec.as_slice()) {
            Some(StrBuf { vec: vec })
        } else {
            None
        }
    }

    /// Return the underlying byte buffer, encoded as UTF-8.
    #[inline]
    pub fn into_bytes(self) -> Vec<u8> {
        self.vec
    }

    /// Pushes the given string onto this buffer; then, returns `self` so that it can be used
    /// again.
    #[inline]
    pub fn append(mut self, second: &str) -> StrBuf {
        self.push_str(second);
        self
    }

    /// Creates a string buffer by repeating a character `length` times.
    #[inline]
    pub fn from_char(length: uint, ch: char) -> StrBuf {
        if length == 0 {
            return StrBuf::new()
        }

        let mut buf = StrBuf::new();
        buf.push_char(ch);
        let size = buf.len() * length;
        buf.reserve(size);
        for _ in range(1, length) {
            buf.push_char(ch)
        }
        buf
    }

    /// Pushes the given string onto this string buffer.
    #[inline]
    pub fn push_str(&mut self, string: &str) {
        self.vec.push_all(string.as_bytes())
    }

    /// Push `ch` onto the given string `count` times.
    #[inline]
    pub fn grow(&mut self, count: uint, ch: char) {
        for _ in range(0, count) {
            self.push_char(ch)
        }
    }

    /// Returns the number of bytes that this string buffer can hold without reallocating.
    #[inline]
    pub fn byte_capacity(&self) -> uint {
        self.vec.capacity()
    }

    /// Reserves capacity for at least `extra` additional bytes in this string buffer.
    #[inline]
    pub fn reserve_additional(&mut self, extra: uint) {
        self.vec.reserve_additional(extra)
    }

    /// Reserves capacity for at least `capacity` bytes in this string buffer.
    #[inline]
    pub fn reserve(&mut self, capacity: uint) {
        self.vec.reserve(capacity)
    }

    /// Reserves capacity for exactly `capacity` bytes in this string buffer.
    #[inline]
    pub fn reserve_exact(&mut self, capacity: uint) {
        self.vec.reserve_exact(capacity)
    }

    /// Shrinks the capacity of this string buffer to match its length.
    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.vec.shrink_to_fit()
    }

    /// Adds the given character to the end of the string.
    #[inline]
    pub fn push_char(&mut self, ch: char) {
        let cur_len = self.len();
        unsafe {
            // This may use up to 4 bytes.
            self.vec.reserve_additional(4);

            // Attempt to not use an intermediate buffer by just pushing bytes
            // directly onto this string.
            let mut c_vector = CVec::new(self.vec.as_mut_ptr().offset(cur_len as int), 4);
            let used = ch.encode_utf8(c_vector.as_mut_slice());
            self.vec.set_len(cur_len + used);
        }
    }

    /// Pushes the given bytes onto this string buffer. This is unsafe because it does not check
    /// to ensure that the resulting string will be valid UTF-8.
    #[inline]
    pub unsafe fn push_bytes(&mut self, bytes: &[u8]) {
        self.vec.push_all(bytes)
    }

    /// Works with the underlying buffer as a byte slice.
    #[inline]
    pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
        self.vec.as_slice()
    }

    /// Shorten a string to the specified length (which must be <= the current length)
    #[inline]
    pub fn truncate(&mut self, len: uint) {
        assert!(self.as_slice().is_char_boundary(len));
        self.vec.truncate(len)
    }

    /// Appends a byte to this string buffer. The caller must preserve the valid UTF-8 property.
    #[inline]
    pub unsafe fn push_byte(&mut self, byte: u8) {
        self.push_bytes([byte])
    }

    /// Removes the last byte from the string buffer and returns it. Returns `None` if this string
    /// buffer is empty.
    ///
    /// The caller must preserve the valid UTF-8 property.
    #[inline]
    pub unsafe fn pop_byte(&mut self) -> Option<u8> {
        let len = self.len();
        if len == 0 {
            return None
        }

        let byte = self.as_slice()[len - 1];
        self.vec.set_len(len - 1);
        Some(byte)
    }

    /// Removes the last character from the string buffer and returns it. Returns `None` if this
    /// string buffer is empty.
    #[inline]
    pub fn pop_char(&mut self) -> Option<char> {
        let len = self.len();
        if len == 0 {
            return None
        }

        let CharRange {ch, next} = self.as_slice().char_range_at_reverse(len);
        unsafe {
            self.vec.set_len(next);
        }
        Some(ch)
    }

    /// Removes the first byte from the string buffer and returns it. Returns `None` if this string
    /// buffer is empty.
    ///
    /// The caller must preserve the valid UTF-8 property.
    pub unsafe fn shift_byte(&mut self) -> Option<u8> {
        self.vec.shift()
    }

    /// Removes the first character from the string buffer and returns it. Returns `None` if this
    /// string buffer is empty.
    ///
    /// # Warning
    ///
    /// This is a O(n) operation as it requires copying every element in the buffer.
    pub fn shift_char (&mut self) -> Option<char> {
        let len = self.len();
        if len == 0 {
            return None
        }

        let CharRange {ch, next} = self.as_slice().char_range_at(0);
        let new_len = len - next;
        unsafe {
            ptr::copy_memory(self.vec.as_mut_ptr(), self.vec.as_ptr().offset(next as int), new_len);
            self.vec.set_len(new_len);
        }
        Some(ch)
    }

    /// Views the string buffer as a mutable sequence of bytes.
    ///
    /// Callers must preserve the valid UTF-8 property.
    pub unsafe fn as_mut_vec<'a>(&'a mut self) -> &'a mut Vec<u8> {
        &mut self.vec
    }
}

impl Container for StrBuf {
    #[inline]
    fn len(&self) -> uint {
        self.vec.len()
    }
}

impl Mutable for StrBuf {
    #[inline]
    fn clear(&mut self) {
        self.vec.clear()
    }
}

impl FromIterator<char> for StrBuf {
    fn from_iter<I:Iterator<char>>(iterator: I) -> StrBuf {
        let mut buf = StrBuf::new();
        buf.extend(iterator);
        buf
    }
}

impl Extendable<char> for StrBuf {
    fn extend<I:Iterator<char>>(&mut self, mut iterator: I) {
        for ch in iterator {
            self.push_char(ch)
        }
    }
}

impl Str for StrBuf {
    #[inline]
    fn as_slice<'a>(&'a self) -> &'a str {
        unsafe {
            mem::transmute(self.vec.as_slice())
        }
    }
}

impl StrAllocating for StrBuf {
    #[inline]
    fn into_owned(self) -> ~str {
        unsafe {
            mem::transmute(self.vec.as_slice().to_owned())
        }
    }

    #[inline]
    fn into_strbuf(self) -> StrBuf { self }
}

impl fmt::Show for StrBuf {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }
}

impl<H:Writer> ::hash::Hash<H> for StrBuf {
    #[inline]
    fn hash(&self, hasher: &mut H) {
        self.as_slice().hash(hasher)
    }
}

#[cfg(test)]
mod tests {
    extern crate test;
    use container::{Container, Mutable};
    use self::test::Bencher;
    use str::{Str, StrSlice};
    use super::StrBuf;

    #[bench]
    fn bench_with_capacity(b: &mut Bencher) {
        b.iter(|| {
            StrBuf::with_capacity(100)
        });
    }

    #[bench]
    fn bench_push_str(b: &mut Bencher) {
        let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
        b.iter(|| {
            let mut r = StrBuf::new();
            r.push_str(s);
        });
    }

    #[test]
    fn test_push_bytes() {
        let mut s = StrBuf::from_str("ABC");
        unsafe {
            s.push_bytes([ 'D' as u8 ]);
        }
        assert_eq!(s.as_slice(), "ABCD");
    }

    #[test]
    fn test_push_str() {
        let mut s = StrBuf::new();
        s.push_str("");
        assert_eq!(s.as_slice().slice_from(0), "");
        s.push_str("abc");
        assert_eq!(s.as_slice().slice_from(0), "abc");
        s.push_str("ประเทศไทย中华Việt Nam");
        assert_eq!(s.as_slice().slice_from(0), "abcประเทศไทย中华Việt Nam");
    }

    #[test]
    fn test_push_char() {
        let mut data = StrBuf::from_str("ประเทศไทย中");
        data.push_char('华');
        data.push_char('b'); // 1 byte
        data.push_char('¢'); // 2 byte
        data.push_char('€'); // 3 byte
        data.push_char('𤭢'); // 4 byte
        assert_eq!(data.as_slice(), "ประเทศไทย中华b¢€𤭢");
    }

    #[test]
    fn test_pop_char() {
        let mut data = StrBuf::from_str("ประเทศไทย中华b¢€𤭢");
        assert_eq!(data.pop_char().unwrap(), '𤭢'); // 4 bytes
        assert_eq!(data.pop_char().unwrap(), '€'); // 3 bytes
        assert_eq!(data.pop_char().unwrap(), '¢'); // 2 bytes
        assert_eq!(data.pop_char().unwrap(), 'b'); // 1 bytes
        assert_eq!(data.pop_char().unwrap(), '华');
        assert_eq!(data.as_slice(), "ประเทศไทย中");
    }

    #[test]
    fn test_shift_char() {
        let mut data = StrBuf::from_str("𤭢€¢b华ประเทศไทย中");
        assert_eq!(data.shift_char().unwrap(), '𤭢'); // 4 bytes
        assert_eq!(data.shift_char().unwrap(), '€'); // 3 bytes
        assert_eq!(data.shift_char().unwrap(), '¢'); // 2 bytes
        assert_eq!(data.shift_char().unwrap(), 'b'); // 1 bytes
        assert_eq!(data.shift_char().unwrap(), '华');
        assert_eq!(data.as_slice(), "ประเทศไทย中");
    }

    #[test]
    fn test_str_truncate() {
        let mut s = StrBuf::from_str("12345");
        s.truncate(5);
        assert_eq!(s.as_slice(), "12345");
        s.truncate(3);
        assert_eq!(s.as_slice(), "123");
        s.truncate(0);
        assert_eq!(s.as_slice(), "");

        let mut s = StrBuf::from_str("12345");
        let p = s.as_slice().as_ptr();
        s.truncate(3);
        s.push_str("6");
        let p_ = s.as_slice().as_ptr();
        assert_eq!(p_, p);
    }

    #[test]
    #[should_fail]
    fn test_str_truncate_invalid_len() {
        let mut s = StrBuf::from_str("12345");
        s.truncate(6);
    }

    #[test]
    #[should_fail]
    fn test_str_truncate_split_codepoint() {
        let mut s = StrBuf::from_str("\u00FC"); // ü
        s.truncate(1);
    }

    #[test]
    fn test_str_clear() {
        let mut s = StrBuf::from_str("12345");
        s.clear();
        assert_eq!(s.len(), 0);
        assert_eq!(s.as_slice(), "");
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

The `ToStr` trait for converting to strings

*/

use str::OwnedStr;
use hashmap::HashMap;
use hashmap::HashSet;
use iterator::IteratorUtil;
use container::Map;
use hash::Hash;
use cmp::Eq;
use old_iter::BaseIter;
use vec::ImmutableVector;

/// A generic trait for converting a value to a string
pub trait ToStr {
    /// Converts the value of `self` to an owned string
    fn to_str(&self) -> ~str;
}

/// Trait for converting a type to a string, consuming it in the process.
pub trait ToStrConsume {
    /// Cosume and convert to a string.
    fn into_str(self) -> ~str;
}

impl ToStr for () {
    #[inline]
    fn to_str(&self) -> ~str { ~"()" }
}

impl<A:ToStr> ToStr for (A,) {
    #[inline]
    fn to_str(&self) -> ~str {
        match *self {
            (ref a,) => {
                fmt!("(%s,)", (*a).to_str())
            }
        }
    }
}

impl<A:ToStr+Hash+Eq, B:ToStr+Hash+Eq> ToStr for HashMap<A, B> {
    #[inline]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"{", true);
        for self.each |key, value| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(key.to_str());
            acc.push_str(": ");
            acc.push_str(value.to_str());
        }
        acc.push_char('}');
        acc
    }
}

impl<A:ToStr+Hash+Eq> ToStr for HashSet<A> {
    #[inline]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"{", true);
        for self.each |element| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(element.to_str());
        }
        acc.push_char('}');
        acc
    }
}

impl<A:ToStr,B:ToStr> ToStr for (A, B) {
    #[inline]
    fn to_str(&self) -> ~str {
        // FIXME(#4653): this causes an llvm assertion
        //let &(ref a, ref b) = self;
        match *self {
            (ref a, ref b) => {
                fmt!("(%s, %s)", (*a).to_str(), (*b).to_str())
            }
        }
    }
}

impl<A:ToStr,B:ToStr,C:ToStr> ToStr for (A, B, C) {
    #[inline]
    fn to_str(&self) -> ~str {
        // FIXME(#4653): this causes an llvm assertion
        //let &(ref a, ref b, ref c) = self;
        match *self {
            (ref a, ref b, ref c) => {
                fmt!("(%s, %s, %s)",
                    (*a).to_str(),
                    (*b).to_str(),
                    (*c).to_str()
                )
            }
        }
    }
}

impl<'self,A:ToStr> ToStr for &'self [A] {
    #[inline]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"[", true);
        for self.iter().advance |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

impl<A:ToStr> ToStr for ~[A] {
    #[inline]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"[", true);
        for self.iter().advance |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

impl<A:ToStr> ToStr for @[A] {
    #[inline]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"[", true);
        for self.iter().advance |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

#[cfg(test)]
#[allow(non_implicitly_copyable_typarams)]
mod tests {
    use hashmap::HashMap;
    use hashmap::HashSet;
    use container::Set;
    #[test]
    fn test_simple_types() {
        assert_eq!(1i.to_str(), ~"1");
        assert_eq!((-1i).to_str(), ~"-1");
        assert_eq!(200u.to_str(), ~"200");
        assert_eq!(2u8.to_str(), ~"2");
        assert_eq!(true.to_str(), ~"true");
        assert_eq!(false.to_str(), ~"false");
        assert_eq!(().to_str(), ~"()");
        assert_eq!((~"hi").to_str(), ~"hi");
        assert_eq!((@"hi").to_str(), ~"hi");
    }

    #[test]
    fn test_tuple_types() {
        assert_eq!((1, 2).to_str(), ~"(1, 2)");
        assert_eq!((~"a", ~"b", false).to_str(), ~"(a, b, false)");
        assert_eq!(((), ((), 100)).to_str(), ~"((), ((), 100))");
    }

    #[test]
    fn test_vectors() {
        let x: ~[int] = ~[];
        assert_eq!(x.to_str(), ~"[]");
        assert_eq!((~[1]).to_str(), ~"[1]");
        assert_eq!((~[1, 2, 3]).to_str(), ~"[1, 2, 3]");
        assert!((~[~[], ~[1], ~[1, 1]]).to_str() ==
               ~"[[], [1], [1, 1]]");
    }

    #[test]
    fn test_hashmap() {
        let mut table: HashMap<int, int> = HashMap::new();
        let empty: HashMap<int, int> = HashMap::new();

        table.insert(3, 4);
        table.insert(1, 2);

        let table_str = table.to_str();

        assert!(table_str == ~"{1: 2, 3: 4}" || table_str == ~"{3: 4, 1: 2}");
        assert_eq!(empty.to_str(), ~"{}");
    }

    #[test]
    fn test_hashset() {
        let mut set: HashSet<int> = HashSet::new();
        let empty_set: HashSet<int> = HashSet::new();

        set.insert(1);
        set.insert(2);

        let set_str = set.to_str();

        assert!(set_str == ~"{1, 2}" || set_str == ~"{2, 1}");
        assert_eq!(empty_set.to_str(), ~"{}");
    }
}
<commit_msg>std::to_str: Use .iter() for HashMap and HashSet<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!

The `ToStr` trait for converting to strings

*/

use str::OwnedStr;
use hashmap::HashMap;
use hashmap::HashSet;
use iterator::IteratorUtil;
use container::Map;
use hash::Hash;
use cmp::Eq;
use old_iter::BaseIter;
use vec::ImmutableVector;
use iterator::IteratorUtil;

/// A generic trait for converting a value to a string
pub trait ToStr {
    /// Converts the value of `self` to an owned string
    fn to_str(&self) -> ~str;
}

/// Trait for converting a type to a string, consuming it in the process.
pub trait ToStrConsume {
    /// Cosume and convert to a string.
    fn into_str(self) -> ~str;
}

impl ToStr for () {
    #[inline]
    fn to_str(&self) -> ~str { ~"()" }
}

impl<A:ToStr> ToStr for (A,) {
    #[inline]
    fn to_str(&self) -> ~str {
        match *self {
            (ref a,) => {
                fmt!("(%s,)", (*a).to_str())
            }
        }
    }
}

impl<A:ToStr+Hash+Eq, B:ToStr+Hash+Eq> ToStr for HashMap<A, B> {
    #[inline]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"{", true);
        for self.iter().advance |(key, value)| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(key.to_str());
            acc.push_str(": ");
            acc.push_str(value.to_str());
        }
        acc.push_char('}');
        acc
    }
}

impl<A:ToStr+Hash+Eq> ToStr for HashSet<A> {
    #[inline]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"{", true);
        for self.iter().advance |element| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(element.to_str());
        }
        acc.push_char('}');
        acc
    }
}

impl<A:ToStr,B:ToStr> ToStr for (A, B) {
    #[inline]
    fn to_str(&self) -> ~str {
        // FIXME(#4653): this causes an llvm assertion
        //let &(ref a, ref b) = self;
        match *self {
            (ref a, ref b) => {
                fmt!("(%s, %s)", (*a).to_str(), (*b).to_str())
            }
        }
    }
}

impl<A:ToStr,B:ToStr,C:ToStr> ToStr for (A, B, C) {
    #[inline]
    fn to_str(&self) -> ~str {
        // FIXME(#4653): this causes an llvm assertion
        //let &(ref a, ref b, ref c) = self;
        match *self {
            (ref a, ref b, ref c) => {
                fmt!("(%s, %s, %s)",
                    (*a).to_str(),
                    (*b).to_str(),
                    (*c).to_str()
                )
            }
        }
    }
}

impl<'self,A:ToStr> ToStr for &'self [A] {
    #[inline]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"[", true);
        for self.iter().advance |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

impl<A:ToStr> ToStr for ~[A] {
    #[inline]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"[", true);
        for self.iter().advance |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

impl<A:ToStr> ToStr for @[A] {
    #[inline]
    fn to_str(&self) -> ~str {
        let mut (acc, first) = (~"[", true);
        for self.iter().advance |elt| {
            if first {
                first = false;
            }
            else {
                acc.push_str(", ");
            }
            acc.push_str(elt.to_str());
        }
        acc.push_char(']');
        acc
    }
}

#[cfg(test)]
#[allow(non_implicitly_copyable_typarams)]
mod tests {
    use hashmap::HashMap;
    use hashmap::HashSet;
    use container::Set;
    #[test]
    fn test_simple_types() {
        assert_eq!(1i.to_str(), ~"1");
        assert_eq!((-1i).to_str(), ~"-1");
        assert_eq!(200u.to_str(), ~"200");
        assert_eq!(2u8.to_str(), ~"2");
        assert_eq!(true.to_str(), ~"true");
        assert_eq!(false.to_str(), ~"false");
        assert_eq!(().to_str(), ~"()");
        assert_eq!((~"hi").to_str(), ~"hi");
        assert_eq!((@"hi").to_str(), ~"hi");
    }

    #[test]
    fn test_tuple_types() {
        assert_eq!((1, 2).to_str(), ~"(1, 2)");
        assert_eq!((~"a", ~"b", false).to_str(), ~"(a, b, false)");
        assert_eq!(((), ((), 100)).to_str(), ~"((), ((), 100))");
    }

    #[test]
    fn test_vectors() {
        let x: ~[int] = ~[];
        assert_eq!(x.to_str(), ~"[]");
        assert_eq!((~[1]).to_str(), ~"[1]");
        assert_eq!((~[1, 2, 3]).to_str(), ~"[1, 2, 3]");
        assert!((~[~[], ~[1], ~[1, 1]]).to_str() ==
               ~"[[], [1], [1, 1]]");
    }

    #[test]
    fn test_hashmap() {
        let mut table: HashMap<int, int> = HashMap::new();
        let empty: HashMap<int, int> = HashMap::new();

        table.insert(3, 4);
        table.insert(1, 2);

        let table_str = table.to_str();

        assert!(table_str == ~"{1: 2, 3: 4}" || table_str == ~"{3: 4, 1: 2}");
        assert_eq!(empty.to_str(), ~"{}");
    }

    #[test]
    fn test_hashset() {
        let mut set: HashSet<int> = HashSet::new();
        let empty_set: HashSet<int> = HashSet::new();

        set.insert(1);
        set.insert(2);

        let set_str = set.to_str();

        assert!(set_str == ~"{1, 2}" || set_str == ~"{2, 1}");
        assert_eq!(empty_set.to_str(), ~"{}");
    }
}
<|endoftext|>


<commit_before>use std::str::from_utf8;
use std::fmt::{self, Debug, Display};
use std::ops::Deref;

#[derive(PartialEq)]
pub struct MaybeStr([u8]);

impl MaybeStr {
    pub fn from_bytes(bytes: &[u8]) -> &MaybeStr {
        //TODO: can this be done without unsafe?
        // Deref cannot be implemented for [u8] as we don't own it
        // We can't construct unsized struct so we need to be able to create pointer stright away
        unsafe { &*((bytes as *const [u8]) as *const MaybeStr)}
    }

    fn as_bytes(&self) -> &[u8] {
        self
    }

    pub fn to_lossy_string(&self) -> String {
        String::from_utf8_lossy(self.as_bytes()).into_owned()
    }

    pub fn to_maybe_string(&self) -> MaybeString {
        MaybeString(self.as_bytes().to_owned())
    }
}

impl Debug for MaybeStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        if let Ok(string) = from_utf8(self.as_bytes()) {
            write!(f, "{:?}", string)
        } else {
            write!(f, "{:?}<non-UTF-8 data: {:?}>", String::from_utf8_lossy(&self.as_bytes()), &self.as_bytes())
        }
    }
}

impl Display for MaybeStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}", String::from_utf8_lossy(&self.as_bytes()))
    }
}

impl Deref for MaybeStr {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        &self.0
    }
}

#[derive(PartialEq)]
pub struct MaybeString(pub Vec<u8>);

impl MaybeString {
    pub fn to_lossy_string(self) -> String {
        match String::from_utf8(self.0) {
            Ok(string) => string,
            Err(err) => {
                String::from_utf8_lossy(err.into_bytes().as_slice()).into_owned()
            }
        }
    }

    pub fn as_maybe_str(&self) -> &MaybeStr {
        self
    }
}

impl Deref for MaybeString {
    type Target = MaybeStr;

    fn deref(&self) -> &MaybeStr {
        MaybeStr::from_bytes(self.0.as_slice())
    }
}

impl Debug for MaybeString {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{:?}", self.as_maybe_str())
    }
}

impl Display for MaybeString {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}", self.as_maybe_str())
    }
}
<commit_msg>cleanup<commit_after>use std::str::from_utf8;
use std::fmt::{self, Debug, Display};
use std::ops::Deref;

#[derive(PartialEq)]
pub struct MaybeStr([u8]);

impl MaybeStr {
    pub fn from_bytes(bytes: &[u8]) -> &MaybeStr {
        //TODO: can this be done without unsafe?
        // Deref cannot be implemented for [u8] as we don't own it
        // We can't construct unsized struct so we need to be able to create pointer stright away
        unsafe { &*((bytes as *const [u8]) as *const MaybeStr)}
    }

    pub fn as_bytes(&self) -> &[u8] {
        self
    }

    pub fn to_maybe_string(&self) -> MaybeString {
        MaybeString(self.as_bytes().to_owned())
    }

    pub fn to_lossy_string(&self) -> String {
        String::from_utf8_lossy(self.as_bytes()).into_owned()
    }
}

impl Debug for MaybeStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        if let Ok(string) = from_utf8(self.as_bytes()) {
            write!(f, "{:?}", string)
        } else {
            write!(f, "{:?}<non-UTF-8 data: {:?}>", String::from_utf8_lossy(&self.as_bytes()), &self.as_bytes())
        }
    }
}

impl Display for MaybeStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}", String::from_utf8_lossy(&self.as_bytes()))
    }
}

impl Deref for MaybeStr {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        &self.0
    }
}

#[derive(PartialEq)]
pub struct MaybeString(pub Vec<u8>);

impl MaybeString {
    #[allow(dead_code)]
    pub fn as_bytes(&self) -> &[u8] {
        self
    }

    pub fn as_maybe_str(&self) -> &MaybeStr {
        self
    }

    pub fn to_lossy_string(self) -> String {
        match String::from_utf8(self.0) {
            Ok(string) => string,
            Err(err) => {
                String::from_utf8_lossy(err.into_bytes().as_slice()).into_owned()
            }
        }
    }
}

impl Deref for MaybeString {
    type Target = MaybeStr;

    fn deref(&self) -> &MaybeStr {
        MaybeStr::from_bytes(self.0.as_slice())
    }
}

impl Debug for MaybeString {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{:?}", self.as_maybe_str())
    }
}

impl Display for MaybeString {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{}", self.as_maybe_str())
    }
}
<|endoftext|>