1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
/***********************************************************************************************************************
 * Copyright (c) 2019 by the authors
 *
 * Author: André Borrmann
 * License: MIT / Appache License 2.0
 **********************************************************************************************************************/
#![doc(html_root_url = "https://docs.rs/ruspiro-console/0.4.1")]
#![cfg_attr(not(any(test, doctest)), no_std)]

//! # Console abstraction
//!
//! This crate provides a console abstraction to enable string output to a configurable output channel.
//! It also provides the convinient macros (``print!`` and ``println!``) to output text that are usually not
//! available in ``[no_std]`` environments. However this crate also provide macros to indicate the severity of the
//! message that shall be printed. Those are ``info!``, ``warn!`` and ``error!``.
//!
//! # Dependencies
//! This crate uses macros to provide formatted strings. This formatting requires a memory allocator to
//! be present (as part of the ``alloc`` crate). So when using this crate provide an allocator such as
//! ``ruspiro_allocator``.
//!
//! # Example
//! To actually set an active output channel you need to provide a structure that implements the ``core::fmt::Write``
//! trait.
//!
//! If this trait has been implemented this structure can be used as actual console. To use it there should be the
//! following code written at the earliest possible point in the main crate of the binary (e.g. the kernel)
//!
//! ```ignore
//! use ruspiro_console::*;
//! use ruspiro_uart::*; // as we demonstrate with the Uart as output device/channel.
//!
//! fn main() {
//!     let mut uart = Uart1::new(); // create a new uart struct
//!     if uart.initialize(250_000_000, 115_200).is_ok() { // initialize the Uart with fixed core rate and baud rate
//!         CONSOLE.with_mut(|cons| cons.replace(uart)); // from this point CONSOLE takes ownership of uart
//!     }
//!
//!     // if everything went fine uart should be assigned to the console for generic output
//!     println!("Console is ready and display's through uart");
//! }
//! ```

pub extern crate alloc;

#[macro_use]
pub mod macros;
pub use macros::*;

use alloc::boxed::Box;
use core::fmt;
use ruspiro_singleton::Singleton;

/// The Console singleton used by print! and println! macros
pub static CONSOLE: Singleton<Console> = Singleton::new(Console {
    current: None,
    default: DefaultConsole {},
});

#[doc(hidden)]
/// The base printing function hidden behind the print! and println! macro. This function forwards all calls to the
/// generic console which writes the string to the assigned output channel.
pub fn _print(args: fmt::Arguments) {
    // pass the string to the actual configured console to be printed
    CONSOLE.with_mut(|console| {
        if let Some(ref mut writer) = console.current {
            writer
                .write_fmt(args)
                .expect("writing to console should never fail");
        }
    });
}

/// The representation of the abstract console
#[allow(dead_code)]
pub struct Console {
    current: Option<Box<dyn fmt::Write + Send + Sync>>,
    default: DefaultConsole,
}

impl Console {
    /// Replacing the current active console. Once the new has been set the [drop] function of the previous one is
    /// called. The Console takes ownership of the active once. Access to the active console outside the abstraction
    /// is not possible and should not be.
    pub fn replace<T>(&mut self, console: T)
    where
        T: fmt::Write + Send + Sync,
        T: 'static,
    {
        self.current.replace(Box::from(console));
    }
}

/// The default console is a kind of fall back that prints nothing...
struct DefaultConsole;

impl fmt::Write for DefaultConsole {
    fn write_str(&mut self, _s: &str) -> fmt::Result {
        Ok(())
    }
}