Как правильно внедрить Deref + DerefMut? - PullRequest
0 голосов
/ 01 августа 2020

Привет, у меня есть следующий этот учебник для более глубокого изучения того, что я могу сделать с ржавчиной, поэтому я знаю, что теперь это может быть правильный способ сделать это. Вот репозиторий, который содержит весь код для более подробного изучения. У меня есть глобальный экземпляр записи vga, который должен быть безопасным для гонок данных, поэтому, используя lazy_static, я инициализирую его. Что я хочу сделать, так это иметь возможность получить блокировку только тогда, когда я на самом деле печатаю строку, чтобы я реализовал fmt::Write на WrappedWriter вместо Writer, чтобы не получать блокировку над spin::Mutex, когда Я хочу напечатать строку, а хочу получить блокировку после форматирования параметров. Но когда я вызываю это функцией записи:

crate::vga_buffer::WRITER.write_fmt(args).unwrap();

, я получаю следующую ошибку:

   Compiling rust_os v0.1.0 (D:\Workspace\Organiztions\home\rust\rust_os)
error[E0055]: reached the recursion limit while auto-dereferencing `vga_buffer::writer::WrappedWriter`
  --> src\lib.rs:19:31
   |
19 |     crate::vga_buffer::WRITER.write_fmt(args).unwrap();
   |                               ^^^^^^^^^ deref recursion limit reached
   |
   = help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`rust_os`)

error: aborting due to previous error

For more information about this error, try `rustc --explain E0055`.
error: could not compile `rust_os`.

Вот реализация Writer + WrappedWriter

use core::fmt;

use lazy_static::lazy_static;
use volatile::Volatile;

use super::color::*;
use super::screen_character;
use core::ops::{DerefMut, Deref};

// #[allow(dead_code)]
// use crate::serial_print;
// use crate::serial_println;

pub const BUFFER_HEIGHT: usize = 25;
pub const BUFFER_WIDTH: usize = 80;

#[repr(transparent)]
struct Buffer {
    chars: [[Volatile<screen_character::ScreenCharacter>; BUFFER_WIDTH]; BUFFER_HEIGHT],
}

pub struct Writer {
    column_position: usize,
    color_code: ColorCode,
    buffer: &'static mut Buffer,
}

impl Writer {
    pub fn new(column_position: usize,
               color_code: ColorCode) -> Writer {
        return Writer {
            column_position,
            color_code,
            buffer: unsafe { &mut *(0xb8000 as *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 = BUFFER_HEIGHT - 1;
                let col = self.column_position;

                let color_code = self.color_code;
                self.buffer.chars[row][col].write(screen_character::ScreenCharacter::new(byte, color_code));
                self.column_position += 1;
            }
        }
    }

    pub fn write_string(&mut self, s: &str) {
        for byte in s.bytes() {
            match byte {
                // printable ASCII byte or newline
                0x20..=0x7e | b'\n' => self.write_byte(byte),
                // not part of printable ASCII range
                _ => self.write_byte(0xfe),
            }
        }
    }

    fn new_line(&mut self) {
        for row in 1..BUFFER_HEIGHT {
            for col in 0..BUFFER_WIDTH {
                let current_character = self.buffer.chars[row][col].read();
                self.buffer.chars[row - 1][col].write(current_character);
            }
        }
        self.clear_row(BUFFER_HEIGHT - 1);
        self.column_position = 0;
    }

    fn clear_row(&mut self, row_index: usize) {
        let blank = screen_character::ScreenCharacter::new(b' ', self.color_code);
        for col in 0..BUFFER_WIDTH {
            self.buffer.chars[row_index][col].write(blank);
        }
    }
}

// impl fmt::Write for Writer {
//     fn write_str(&mut self, s: &str) -> fmt::Result {
//         self.write_string(s);
//         Ok(())
//     }
// }

struct WrappedWriter {
    value: spin::Mutex<Writer>
}

impl fmt::Write for WrappedWriter {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        self.value.lock().write_string(s);
        Ok(())
    }
}

impl Deref for WrappedWriter {
    type Target = WrappedWriter;

    fn deref(&self) -> &Self::Target {
        return self;
    }
}

impl DerefMut for WrappedWriter {
    fn deref_mut(&mut self) -> &mut Self::Target {
        return self;
    }
}

lazy_static! {
    pub static ref WRITER: WrappedWriter = {
        let writerInstance = WrappedWriter {
            value: spin::Mutex::new(
                Writer::new(0, ColorCode::new(Color::Yellow, Color::Black))
            )
        };
        writerInstance
    };
}

#[test_case]
fn test_println_output() {
    let test_str = "Some test string that fits on a single line";
    println!("{}", test_str);
    for (char_index, char) in test_str.chars().enumerate() {
        let screen_char = WRITER.value.lock().buffer.chars[BUFFER_HEIGHT - 2][char_index].read();
        assert_eq!(char::from(screen_char.ascii_character), char);
    }
}

Deref + DerefMut Были реализованы, потому что без них я получаю следующую ошибку, но опять же, я не знал, что мне следует deref, потому что мне на самом деле не нужно deref с моей точки зрения необходимы, потому что write_fmt получает само себя

error[E0596]: cannot borrow data in a dereference of `vga_buffer::writer::WRITER` as mutable
  --> src\lib.rs:19:5
   |
19 |     crate::vga_buffer::WRITER.write_fmt(args).unwrap();
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
   |
   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `vga_buffer::writer::WRITER`

1 Ответ

1 голос
/ 01 августа 2020

WrappedWriter в настоящее время ссылается на себя, которая переключает на себя, которая переключает на себя и т. Д., Поэтому вы достигаете предела рекурсии. Вы, вероятно, захотите сделать его ссылкой на Writer внутри, получив блокировку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...