+use core::ops::{AddAssign, Shl};
+
+#[allow(dead_code)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[repr(u8)]
+pub enum Color {
+ Black = 0,
+ Blue = 1,
+ Green = 2,
+ Cyan = 3,
+ Red = 4,
+ Magenta = 5,
+ Brown = 6,
+ LightGray = 7,
+ DarkGray = 8,
+ LightBlue = 9,
+ LightGreen = 10,
+ LightCyan = 11,
+ LightRed = 12,
+ Pink = 13,
+ Yellow = 14,
+ White = 15,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[repr(transparent)]
+pub struct ColorCode(u8);
+
+impl ColorCode {
+ pub fn new(foreground: Color, background: Color) -> ColorCode {
+ ColorCode((background as u8).shl(4) | (foreground as u8))
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[repr(C)]
+struct ScreenChar {
+ ascii_character: u8,
+ color_code: ColorCode,
+}
+
+const BUFFER_WIDTH: usize = 80;
+const BUFFER_HEIGHT: usize = 25;
+
+#[repr(transparent)]
+struct Buffer {
+ chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT],
+}
+
+pub struct Writer {
+ row_position: usize,
+ column_position: usize,
+ color_code: ColorCode,
+ buffer: &'static mut Buffer,
+}
+
+impl Writer {
+ pub fn write_byte(&mut self, byte: u8) {
+ match byte {
+ b'\n' => self.new_line(),
+ byte => {
+ if self.column_position >= BUFFER_WIDTH {
+ self.new_line();
+ }
+
+ let row = self.row_position;
+ let col = self.column_position;
+
+ let color_code = self.color_code;
+ self.buffer.chars[row][col] = ScreenChar {
+ ascii_character: byte,
+ color_code,
+ };
+
+ self.column_position.add_assign(1);
+ },
+ }
+ }
+
+ pub fn write_string(&mut self, s: &str) {
+ for byte in s.bytes() {
+ match byte {
+ // Printable ASCII character or \n
+ 0x20..=0x7e | b'\n' => self.write_byte(byte),
+ // Not printable, write error char instead
+ _ => self.write_byte(0xfe),
+ }
+ }
+ }
+
+ fn new_line(&mut self) {
+
+ }
+}
+
+pub fn test_print() {
+ let mut writer = Writer {
+ row_position: 1,
+ column_position: 0,
+ color_code: ColorCode::new(Color::Yellow, Color::Black),
+ buffer: unsafe { &mut *(0xb8000 as *mut Buffer) },
+ };
+
+ writer.write_string("Hello Stage2!");
+}