Решение на Logging от Николай Данаилов

Обратно към всички решения

Към профила на Николай Данаилов

Резултати

  • 19 точки от тестове
  • 0 бонус точки
  • 19 точки общо
  • 14 успешни тест(а)
  • 1 неуспешни тест(а)

Код

use std::time::Instant;
use std::io;
use std::io::Write;
use std::rc::Rc;
use std::cell::RefCell;
pub trait Logger {
fn push(&mut self, time: Instant, text: &str);
fn log(&mut self, text: &str) {
self.push(Instant::now(), text);
}
fn try_flush(&mut self) -> io::Result<()>;
fn flush(&mut self);
}
pub struct BufferedLogger<W: Write> {
buffer: Rc<RefCell<Vec<(Instant, String)>>>,
capacity: usize,
out: Rc<RefCell<W>>
}
impl<W: Write> BufferedLogger<W> {
pub fn new(out: W, buffer_size: usize) -> Self {
BufferedLogger {
out: Rc::new(RefCell::new(out)),
capacity: buffer_size,
buffer: Rc::new(RefCell::new(vec![]))
}
}
pub fn buffered_entries(&self) -> Vec<String> {
// Can't figure out how to copy the buffer without
// iterating through it manually
let mut res = vec![];
for (_time, text) in self.buffer.borrow_mut().iter() {
res.push(text.clone());
}
res

Ако викнеш self.buffer.clone() ще се клонира rc-то, което не е каквото искаш. Но (*self.buffer).borrow().clone() ще излезе от rc-то, ще викне borrow(), за да вземе Ref от refcell-а, и ще извика clone на вектора, в крайна сметка. А тъй като викането на методи прави deref coercion, просто това би трябвало да сработи: self.buffer.borrow().clone().

}
}
impl<W: Write> Clone for BufferedLogger<W> {
fn clone(&self) -> Self {
BufferedLogger {
out: self.out.clone(),
buffer: self.buffer.clone(),
capacity: self.capacity.clone()
}
}
}
impl<W: Write> Logger for BufferedLogger<W> {
fn push(&mut self, time: Instant, text: &str) {
self.buffer.borrow_mut().push((time, text.to_string()));
self.buffer.borrow_mut().sort_unstable();
if self.buffer.borrow().len() == self.capacity {
self.flush();
}
}
fn try_flush(&mut self) -> io::Result<()> {
for (_time, string) in self.buffer.borrow().iter() {
let string = format!("{}\n", string);
self.out.borrow_mut().write(string.as_bytes())?;
}
self.buffer.borrow_mut().clear();
Ok(())
}
fn flush(&mut self) {
match self.try_flush() {
Ok(_) => (),
Err(e) => eprintln!("{}", e)
}
}
}
pub struct MultiLogger {
loggers: Vec<Box<dyn Logger>>
}
impl MultiLogger {
pub fn new() -> Self {
MultiLogger {
loggers: vec![]
}
}
pub fn log_to<L: Logger + 'static>(&mut self, logger: L) {
self.loggers.push(Box::new(logger));
}
}
impl Logger for MultiLogger {
fn push(&mut self, time: Instant, text: &str) {
for logger in &mut self.loggers {
logger.push(time, text);
}
}
fn try_flush(&mut self) -> io::Result<()> {
for logger in &mut self.loggers {
logger.try_flush()?;
}
Ok(())
}
fn flush(&mut self) {
for logger in &mut self.loggers {
logger.flush();
}
}
}
pub struct ScopedLogger<L: Logger> {
tag: String,
logger: L
}
impl<L: Logger> ScopedLogger<L> {
pub fn new(tag: &str, base_logger: L) -> Self {
ScopedLogger {
tag: tag.to_string(),
logger: base_logger
}
}
}
impl<L: Logger> Logger for ScopedLogger<L> {
fn push(&mut self, time: Instant, text: &str) {
let string = format!("[{}] {}", self.tag, text);
self.logger.push(time, &string);
}
fn try_flush(&mut self) -> io::Result<()> {
self.logger.try_flush()
}
fn flush(&mut self) {
self.logger.flush();
}
}

Лог от изпълнението

Compiling solution v0.1.0 (/tmp/d20190123-22631-fq8mye/solution)
    Finished dev [unoptimized + debuginfo] target(s) in 5.09s
     Running target/debug/deps/solution-2e785d603b538f71

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running target/debug/deps/solution_test-29808948fb50ed3a

running 15 tests
test solution_test::test_automatic_flushing_when_buffer_limit_is_reached ... ok
test solution_test::test_automatic_flushing_when_zero_buffer_limit ... FAILED
test solution_test::test_basic_log ... ok
test solution_test::test_basic_push ... ok
test solution_test::test_cloning_a_logger_shares_a_buffer ... ok
test solution_test::test_cloning_a_logger_shares_their_io ... ok
test solution_test::test_erroring_io ... ok
test solution_test::test_flushing_the_buffer ... ok
test solution_test::test_logger_combinations ... ok
test solution_test::test_multilogger_logs_and_flushes_when_needed ... ok
test solution_test::test_multilogger_logs_to_several_ios ... ok
test solution_test::test_reordering_logs_in_buffer ... ok
test solution_test::test_reordering_logs_in_io ... ok
test solution_test::test_scoped_logger ... ok
test solution_test::test_scoped_logger_with_a_string_tag ... ok

failures:

---- solution_test::test_automatic_flushing_when_zero_buffer_limit stdout ----
thread 'solution_test::test_automatic_flushing_when_zero_buffer_limit' panicked at 'assertion failed: `(left == right)`
  left: `1`,
 right: `0`', tests/solution_test.rs:210:9
note: Run with `RUST_BACKTRACE=1` for a backtrace.


failures:
    solution_test::test_automatic_flushing_when_zero_buffer_limit

test result: FAILED. 14 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out

error: test failed, to rerun pass '--test solution_test'

История (2 версии и 4 коментара)

Николай обнови решението на 17.12.2018 12:01 (преди почти 2 години)

+use std::time::Instant;
+use std::io;
+use std::io::Write;
+use std::rc::Rc;
+use std::cell::RefCell;
+
+pub trait Logger {
+ fn push(&mut self, time: Instant, text: &str);
+
+ fn log(&mut self, text: &str) {
+ self.push(Instant::now(), text);
+ }
+
+ fn try_flush(&mut self) -> io::Result<()>;
+ fn flush(&mut self);
+}
+
+#[derive(Default)]
+pub struct BufferedLogger<W: Write> {
+ buffer: Rc<RefCell<Vec<(Instant, String)>>>,
+ capacity: usize,
+ out: Rc<RefCell<W>>
+}
+
+impl<W: Write> BufferedLogger<W> {
+ /// Конструира структура, която ще пази записи в буфер с размер `buffer_size`, и ще ги записва
+ /// в подадената структура от тип, който имплементира `Write`;
+ ///
+ pub fn new(out: W, buffer_size: usize) -> Self {
+ BufferedLogger {
+ out: Rc::new(RefCell::new(out)),
+ capacity: buffer_size,
+ buffer: Rc::new(RefCell::new(vec![]))
+ }
+ }
+
+ /// Връща списък от записите, които са буферирани в момента. Записите се очаква да бъдат
+ /// подредени по времето, в което са log-нати, от най-ранни до най-късни.
+ ///
+ pub fn buffered_entries(&self) -> Vec<String> {
+ // Can't figure out how to copy the buffer without
+ // iterating through it manually
+ let mut res = vec![];
+
+ for (time, text) in self.buffer.borrow_mut().iter() {
+ res.push(text.clone());
+ }
+
+ res
+ }
+}
+
+/// Вижте по-долу за бележки за клонирането
+impl<W: Write> Clone for BufferedLogger<W> {
+ fn clone(&self) -> Self {
+ BufferedLogger {
+ out: self.out.clone(),
+ buffer: self.buffer.clone(),
+ capacity: self.capacity.clone()
+ }
+ }
+}
+
+impl<W: Write> Logger for BufferedLogger<W> {
+ /// Подходящи имплементации на Logger методите
+ fn push(&mut self, time: Instant, text: &str) {
+ self.buffer.borrow_mut().push((time, text.to_string()));
+ self.buffer.borrow_mut().sort_unstable();
+
+ if self.buffer.borrow().len() == self.capacity {
+ self.flush();
+ }
+ }
+
+ fn try_flush(&mut self) -> io::Result<()> {
+ for (time, string) in self.buffer.borrow().iter() {
+ // Create a new string and add a new line to it
+ // before writing it
+ let mut string = string.clone();
+ string.push('\n');
+
+ self.out.borrow_mut().write(string.as_bytes());
+ }
+
+ self.buffer.borrow_mut().clear();
+ Ok(())
+ }
+
+ fn flush(&mut self) {
+ match self.try_flush() {
+ Ok(_) => (),
+ Err(e) => eprintln!("{}", e)
+ }
+ }
+}
+
+pub struct MultiLogger {
+ loggers: Vec<Box<dyn Logger>>
+}
+
+impl MultiLogger {
+ pub fn new() -> Self {
+ MultiLogger {
+ loggers: vec![]
+ }
+ }
+
+ pub fn log_to<L: Logger + 'static>(&mut self, logger: L) {
+ self.loggers.push(Box::new(logger));
+ }
+}
+
+impl Logger for MultiLogger {
+ fn push(&mut self, time: Instant, text: &str) {
+ for logger in &mut self.loggers {
+ logger.push(time, text);
+ }
+ }
+
+ fn try_flush(&mut self) -> io::Result<()> {
+ for logger in &mut self.loggers {
+ logger.try_flush()?;
+ }
+
+ Ok(())
+ }
+
+ fn flush(&mut self) {
+ for logger in &mut self.loggers {
+ logger.flush();
+ }
+ }
+}
+
+pub struct ScopedLogger<L: Logger> {
+ tag: String,
+ logger: L
+}
+
+impl<L: Logger> ScopedLogger<L> {
+ pub fn new(tag: &str, base_logger: L) -> Self {
+ ScopedLogger {
+ tag: tag.to_string(),
+ logger: base_logger
+ }
+ }
+}
+
+impl<L: Logger> Logger for ScopedLogger<L> {
+ fn push(&mut self, time: Instant, text: &str) {
+ let string = format!("[{}] {}", self.tag, text);
+ self.logger.push(time, &string);
+ }
+
+ fn try_flush(&mut self) -> io::Result<()> {
+ self.logger.try_flush()
+ }
+
+ fn flush(&mut self) {
+ self.logger.flush();
+ }
+}

Николай обнови решението на 17.12.2018 12:11 (преди почти 2 години)

use std::time::Instant;
use std::io;
use std::io::Write;
use std::rc::Rc;
use std::cell::RefCell;
pub trait Logger {
fn push(&mut self, time: Instant, text: &str);
fn log(&mut self, text: &str) {
self.push(Instant::now(), text);
}
fn try_flush(&mut self) -> io::Result<()>;
fn flush(&mut self);
}
-#[derive(Default)]
pub struct BufferedLogger<W: Write> {
buffer: Rc<RefCell<Vec<(Instant, String)>>>,
capacity: usize,
out: Rc<RefCell<W>>
}
impl<W: Write> BufferedLogger<W> {
- /// Конструира структура, която ще пази записи в буфер с размер `buffer_size`, и ще ги записва
- /// в подадената структура от тип, който имплементира `Write`;
- ///
pub fn new(out: W, buffer_size: usize) -> Self {
BufferedLogger {
out: Rc::new(RefCell::new(out)),
capacity: buffer_size,
buffer: Rc::new(RefCell::new(vec![]))
}
}
- /// Връща списък от записите, които са буферирани в момента. Записите се очаква да бъдат
- /// подредени по времето, в което са log-нати, от най-ранни до най-късни.
- ///
pub fn buffered_entries(&self) -> Vec<String> {
// Can't figure out how to copy the buffer without
// iterating through it manually
let mut res = vec![];
- for (time, text) in self.buffer.borrow_mut().iter() {
+ for (_time, text) in self.buffer.borrow_mut().iter() {
res.push(text.clone());
}
res

Ако викнеш self.buffer.clone() ще се клонира rc-то, което не е каквото искаш. Но (*self.buffer).borrow().clone() ще излезе от rc-то, ще викне borrow(), за да вземе Ref от refcell-а, и ще извика clone на вектора, в крайна сметка. А тъй като викането на методи прави deref coercion, просто това би трябвало да сработи: self.buffer.borrow().clone().

}
}
-/// Вижте по-долу за бележки за клонирането
impl<W: Write> Clone for BufferedLogger<W> {
fn clone(&self) -> Self {
BufferedLogger {
out: self.out.clone(),
buffer: self.buffer.clone(),
capacity: self.capacity.clone()
}
}
}
impl<W: Write> Logger for BufferedLogger<W> {
- /// Подходящи имплементации на Logger методите
fn push(&mut self, time: Instant, text: &str) {
self.buffer.borrow_mut().push((time, text.to_string()));
self.buffer.borrow_mut().sort_unstable();
if self.buffer.borrow().len() == self.capacity {
self.flush();
}
}
fn try_flush(&mut self) -> io::Result<()> {
- for (time, string) in self.buffer.borrow().iter() {
- // Create a new string and add a new line to it
- // before writing it
- let mut string = string.clone();
- string.push('\n');
-
- self.out.borrow_mut().write(string.as_bytes());
+ for (_time, string) in self.buffer.borrow().iter() {
+ let string = format!("{}\n", string);
+ self.out.borrow_mut().write(string.as_bytes())?;
}
self.buffer.borrow_mut().clear();
Ok(())
}
fn flush(&mut self) {
match self.try_flush() {
Ok(_) => (),
Err(e) => eprintln!("{}", e)
}
}
}
pub struct MultiLogger {
loggers: Vec<Box<dyn Logger>>
}
impl MultiLogger {
pub fn new() -> Self {
MultiLogger {
loggers: vec![]
}
}
pub fn log_to<L: Logger + 'static>(&mut self, logger: L) {
self.loggers.push(Box::new(logger));
}
}
impl Logger for MultiLogger {
fn push(&mut self, time: Instant, text: &str) {
for logger in &mut self.loggers {
logger.push(time, text);
}
}
fn try_flush(&mut self) -> io::Result<()> {
for logger in &mut self.loggers {
logger.try_flush()?;
}
Ok(())
}
fn flush(&mut self) {
for logger in &mut self.loggers {
logger.flush();
}
}
}
pub struct ScopedLogger<L: Logger> {
tag: String,
logger: L
}
impl<L: Logger> ScopedLogger<L> {
pub fn new(tag: &str, base_logger: L) -> Self {
ScopedLogger {
tag: tag.to_string(),
logger: base_logger
}
}
}
impl<L: Logger> Logger for ScopedLogger<L> {
fn push(&mut self, time: Instant, text: &str) {
let string = format!("[{}] {}", self.tag, text);
self.logger.push(time, &string);
}
fn try_flush(&mut self) -> io::Result<()> {
self.logger.try_flush()
}
fn flush(&mut self) {
self.logger.flush();
}
}