Add comments

This commit is contained in:
Rico Riedel 2022-08-06 18:43:47 +02:00
parent e07d5bfb3e
commit 4286d7055d
No known key found for this signature in database
GPG Key ID: 75AC868575DE7B18
21 changed files with 124 additions and 2 deletions

View File

@ -1,20 +1,27 @@
/// A sample for a terminal cell.
#[derive(Copy, Clone, PartialEq, Debug)] #[derive(Copy, Clone, PartialEq, Debug)]
pub enum CharSample { pub enum CharSample {
/// Keep the char.
Keep, Keep,
/// Override the char.
Draw(char), Draw(char),
/// Clear the char.
Clear, Clear,
} }
/// A trait to convert a sample to a [CharSample].
#[cfg_attr(test, mockall::automock)] #[cfg_attr(test, mockall::automock)]
pub trait CharConverter { pub trait CharConverter {
fn convert(&self, level: f32) -> CharSample; fn convert(&self, level: f32) -> CharSample;
} }
/// The implementation of [CharConverter].
pub struct CharConverterImpl { pub struct CharConverterImpl {
chars: Vec<char>, chars: Vec<char>,
} }
impl CharConverterImpl { impl CharConverterImpl {
/// The chars used for mapping.
pub fn new(chars: String) -> Self { pub fn new(chars: String) -> Self {
let chars = chars.chars().collect(); let chars = chars.chars().collect();

View File

@ -1,15 +1,18 @@
use crossterm::style::Color; use crossterm::style::Color;
/// A trait to convert a sample to a [Color].
#[cfg_attr(test, mockall::automock)] #[cfg_attr(test, mockall::automock)]
pub trait ColorConverter { pub trait ColorConverter {
fn convert(&self, level: f32) -> Color; fn convert(&self, level: f32) -> Color;
} }
/// The implementation of [ColorConverter].
pub struct ColorConverterImpl { pub struct ColorConverterImpl {
colors: Vec<Color>, colors: Vec<Color>,
} }
impl ColorConverterImpl { impl ColorConverterImpl {
/// The colors used for mapping.
pub fn new(colors: Vec<Color>) -> Self { pub fn new(colors: Vec<Color>) -> Self {
Self { colors } Self { colors }
} }

View File

@ -1,3 +1,5 @@
//! Contains structs for converting samples to concrete types.
mod char; mod char;
mod color; mod color;
@ -6,12 +8,16 @@ pub use crate::convert::color::*;
use crossterm::style::Color; use crossterm::style::Color;
/// A trait to convert samples to concrete types.
#[cfg_attr(test, mockall::automock)] #[cfg_attr(test, mockall::automock)]
pub trait Converter { pub trait Converter {
/// Converts a sample to a [CharSample].
fn char(&self, level: f32) -> CharSample; fn char(&self, level: f32) -> CharSample;
/// Converts a sample to a [Color].
fn color(&self, level: f32) -> Color; fn color(&self, level: f32) -> Color;
} }
/// The implementation of [Converter].
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct ConverterImpl<T1, T2> { pub struct ConverterImpl<T1, T2> {
char: T1, char: T1,

View File

@ -1,5 +1,6 @@
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
/// The error type.
pub struct Error(String); pub struct Error(String);
impl Debug for Error { impl Debug for Error {

View File

@ -27,6 +27,7 @@ use rand::prelude::*;
use std::io::stdout; use std::io::stdout;
use std::time::Duration; use std::time::Duration;
/// The command line arguments.
#[derive(Parser, Default)] #[derive(Parser, Default)]
#[clap( #[clap(
author = env!("CARGO_PKG_AUTHORS"), author = env!("CARGO_PKG_AUTHORS"),
@ -34,8 +35,13 @@ use std::time::Duration;
about = env!("CARGO_PKG_DESCRIPTION"), about = env!("CARGO_PKG_DESCRIPTION"),
)] )]
struct Args { struct Args {
/// Set the animation duration [milliseconds] /// Set the duration as milliseconds
#[clap(long, default_value_t = 2000, value_parser = value_parser!(u64).range(0..=60_000))] #[clap(
long,
default_value_t = 2000,
value_parser = value_parser!(u64).range(0..=60_000),
help = "Set the animation duration [milliseconds]"
)]
duration: u64, duration: u64,
/// Set the frames per second /// Set the frames per second
#[clap(long, default_value_t = 60, value_parser = value_parser!(u64).range(1..=480))] #[clap(long, default_value_t = 60, value_parser = value_parser!(u64).range(1..=480))]
@ -78,6 +84,7 @@ struct Args {
color_slices: Option<u8>, color_slices: Option<u8>,
} }
/// All color pallets.
#[derive(ValueEnum, Copy, Clone)] #[derive(ValueEnum, Copy, Clone)]
enum PalletEnum { enum PalletEnum {
Red, Red,
@ -106,6 +113,7 @@ enum PalletEnum {
Gray, Gray,
} }
/// All possible [Pattern]s.
#[derive(ValueEnum, Copy, Clone, PartialEq, Debug)] #[derive(ValueEnum, Copy, Clone, PartialEq, Debug)]
enum PatternEnum { enum PatternEnum {
Circle, Circle,
@ -114,6 +122,7 @@ enum PatternEnum {
Wheel, Wheel,
} }
/// A configuration for a composed [Pattern].
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
struct PatternConfig { struct PatternConfig {
pattern: PatternEnum, pattern: PatternEnum,
@ -125,6 +134,7 @@ struct PatternConfig {
} }
impl Args { impl Args {
/// Returns the configuration for the char [Pattern].
fn char_config(&self, rng: &mut impl Rng) -> PatternConfig { fn char_config(&self, rng: &mut impl Rng) -> PatternConfig {
PatternConfig::new( PatternConfig::new(
choose(self.char_pattern, rng), choose(self.char_pattern, rng),
@ -136,6 +146,7 @@ impl Args {
) )
} }
/// Returns the configuration for the color [Pattern].
fn color_config(&self, rng: &mut impl Rng) -> PatternConfig { fn color_config(&self, rng: &mut impl Rng) -> PatternConfig {
PatternConfig::new( PatternConfig::new(
choose(self.color_pattern, rng), choose(self.color_pattern, rng),
@ -147,6 +158,7 @@ impl Args {
) )
} }
/// Returns the colors for the [ColorConverter].
fn pallet(&self, rng: &mut impl Rng) -> Vec<Color> { fn pallet(&self, rng: &mut impl Rng) -> Vec<Color> {
match choose(self.colors, rng) { match choose(self.colors, rng) {
PalletEnum::Red => vec![DarkRed, Red, White], PalletEnum::Red => vec![DarkRed, Red, White],
@ -183,16 +195,19 @@ impl Args {
} }
} }
/// Returns the duration for the [Timer].
fn duration(&self) -> Duration { fn duration(&self) -> Duration {
Duration::from_millis(self.duration) Duration::from_millis(self.duration)
} }
/// Returns the delay for the [Timer].
fn delay(&self) -> Duration { fn delay(&self) -> Duration {
Duration::from_nanos(1_000_000_000 / self.fps) Duration::from_nanos(1_000_000_000 / self.fps)
} }
} }
impl PatternConfig { impl PatternConfig {
/// Creates a new base [Pattern].
fn create_base(&self) -> Box<dyn PatternFactory> { fn create_base(&self) -> Box<dyn PatternFactory> {
match self.pattern { match self.pattern {
PatternEnum::Circle => Box::new(CircleFactory::new()), PatternEnum::Circle => Box::new(CircleFactory::new()),
@ -202,6 +217,7 @@ impl PatternConfig {
} }
} }
/// Creates a new composed [Pattern].
fn create(&self) -> Box<dyn PatternFactory> { fn create(&self) -> Box<dyn PatternFactory> {
let mut pattern = self.create_base(); let mut pattern = self.create_base();
@ -224,6 +240,7 @@ impl PatternConfig {
} }
} }
/// Returns the value of the [Option] or a random enum variant.
fn choose<TValue: ValueEnum, TRand: Rng>(opt: Option<TValue>, rng: &mut TRand) -> TValue { fn choose<TValue: ValueEnum, TRand: Rng>(opt: Option<TValue>, rng: &mut TRand) -> TValue {
match opt { match opt {
Some(value) => value.clone(), Some(value) => value.clone(),

View File

@ -1,8 +1,10 @@
use crate::pattern::*; use crate::pattern::*;
use crate::Vector; use crate::Vector;
/// A factory for [Circle].
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct CircleFactory; pub struct CircleFactory;
/// A circular [Pattern].
pub struct Circle { pub struct Circle {
center: Vector, center: Vector,
radius: f32, radius: f32,

View File

@ -1,8 +1,10 @@
use crate::pattern::*; use crate::pattern::*;
use crate::Vector; use crate::Vector;
/// A factory for [Line].
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct LineFactory; pub struct LineFactory;
/// A horizontal line [Pattern].
pub struct Line { pub struct Line {
width: f32, width: f32,
} }

View File

@ -1,3 +1,5 @@
//! Contains all pattern traits and base patterns.
mod circle; mod circle;
mod line; mod line;
mod rhombus; mod rhombus;
@ -10,42 +12,59 @@ pub use wheel::*;
use crate::Vector; use crate::Vector;
/// A configuration for a [Pattern].
#[derive(Copy, Clone, Default, PartialEq, Debug)] #[derive(Copy, Clone, Default, PartialEq, Debug)]
pub struct Config { pub struct Config {
/// The size of the terminal.
pub size: Vector, pub size: Vector,
/// The current state of the animation.
pub step: f32, pub step: f32,
} }
/// A factory to create a [Pattern].
#[cfg_attr(test, mockall::automock)] #[cfg_attr(test, mockall::automock)]
pub trait PatternFactory { pub trait PatternFactory {
/// Creates a new [Pattern] with the given configuration.
fn create(&self, config: &Config) -> Box<dyn Pattern>; fn create(&self, config: &Config) -> Box<dyn Pattern>;
} }
/// A pattern for an animation.
#[cfg_attr(test, mockall::automock)] #[cfg_attr(test, mockall::automock)]
pub trait Pattern { pub trait Pattern {
/// Returns the level for a given coordinate.
/// If it is a base pattern, the start position of the
/// animation should by zero and the end position should be one.
fn sample(&self, pos: Vector) -> f32; fn sample(&self, pos: Vector) -> f32;
} }
/// A factor for a [Sampler].
#[cfg_attr(test, mockall::automock(type Sampler = MockSampler;))] #[cfg_attr(test, mockall::automock(type Sampler = MockSampler;))]
pub trait SamplerFactory { pub trait SamplerFactory {
/// The type of the [Sampler].
type Sampler: Sampler; type Sampler: Sampler;
/// Creates a new [Sampler].
fn create(&self, config: &Config) -> Self::Sampler; fn create(&self, config: &Config) -> Self::Sampler;
} }
/// A sampler for multiple values.
#[cfg_attr(test, mockall::automock)] #[cfg_attr(test, mockall::automock)]
pub trait Sampler { pub trait Sampler {
/// Returns the char level for a given position.
fn char(&self, pos: Vector) -> f32; fn char(&self, pos: Vector) -> f32;
/// Returns the color level for a given position.
fn color(&self, pos: Vector) -> f32; fn color(&self, pos: Vector) -> f32;
} }
/// The implementation of [SamplerFactory].
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct SamplerFactoryImpl { pub struct SamplerFactoryImpl {
char: Box<dyn PatternFactory>, char: Box<dyn PatternFactory>,
color: Box<dyn PatternFactory>, color: Box<dyn PatternFactory>,
} }
/// The implementation of [Sampler].
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct SamplerImpl { pub struct SamplerImpl {
char: Box<dyn Pattern>, char: Box<dyn Pattern>,

View File

@ -1,8 +1,10 @@
use crate::pattern::*; use crate::pattern::*;
use crate::Vector; use crate::Vector;
/// A factory for [Rhombus].
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct RhombusFactory; pub struct RhombusFactory;
/// A rhombus shaped [Pattern].
pub struct Rhombus { pub struct Rhombus {
center: Vector, center: Vector,
distance: f32, distance: f32,

View File

@ -2,8 +2,10 @@ use crate::pattern::*;
use crate::Vector; use crate::Vector;
use std::f32::consts::PI; use std::f32::consts::PI;
/// A factory for [Wheel].
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct WheelFactory; pub struct WheelFactory;
/// A fortune wheel [Pattern].
pub struct Wheel { pub struct Wheel {
center: Vector, center: Vector,
} }

View File

@ -4,18 +4,32 @@ use crossterm::cursor::*;
use crossterm::style::*; use crossterm::style::*;
use crossterm::terminal::*; use crossterm::terminal::*;
/// A trait for performance optimized terminal output.
///
/// All commands are queue and have to be executed using [Printer::flush].
#[cfg_attr(test, mockall::automock)] #[cfg_attr(test, mockall::automock)]
pub trait Printer { pub trait Printer {
/// Shows the cursor if it isn't visible.
fn show_cursor(&mut self) -> Result<(), Error>; fn show_cursor(&mut self) -> Result<(), Error>;
/// Hides the cursor if it is visible.
fn hide_cursor(&mut self) -> Result<(), Error>; fn hide_cursor(&mut self) -> Result<(), Error>;
/// Prints a character.
/// # Panics
/// Panics if the character is a special character like `ESC`, `DEL` or `NEWLINE`.
fn print(&mut self, char: char) -> Result<(), Error>; fn print(&mut self, char: char) -> Result<(), Error>;
/// Moves the cursor to the specified position if it isn't there already.
fn move_to(&mut self, x: u16, y: u16) -> Result<(), Error>; fn move_to(&mut self, x: u16, y: u16) -> Result<(), Error>;
/// Returns the size of the terminal.
fn size(&self) -> Result<(u16, u16), Error>; fn size(&self) -> Result<(u16, u16), Error>;
/// Sets the foreground color of the terminal.
fn set_foreground(&mut self, color: Color) -> Result<(), Error>; fn set_foreground(&mut self, color: Color) -> Result<(), Error>;
/// Clears the terminal content.
fn clear(&mut self) -> Result<(), Error>; fn clear(&mut self) -> Result<(), Error>;
/// Flushes all queue commands.
fn flush(&mut self) -> Result<(), Error>; fn flush(&mut self) -> Result<(), Error>;
} }
/// The implementation of [Printer].
pub struct PrinterImpl<T> { pub struct PrinterImpl<T> {
term: T, term: T,
position: (u16, u16), position: (u16, u16),

View File

@ -4,13 +4,20 @@ use crate::Error;
use crate::Printer; use crate::Printer;
use crate::Vector; use crate::Vector;
/// A renderer for an animation.
#[cfg_attr(test, mockall::automock)] #[cfg_attr(test, mockall::automock)]
pub trait Renderer { pub trait Renderer {
/// Prepares the terminal for the animation.
/// Call once before rendering frames.
fn begin(&mut self) -> Result<(), Error>; fn begin(&mut self) -> Result<(), Error>;
/// Renders the current frame and flushes.
fn render(&mut self, step: f32) -> Result<(), Error>; fn render(&mut self, step: f32) -> Result<(), Error>;
/// Cleans up and resets the terminal.
/// Call once after rendering frames.
fn end(&mut self) -> Result<(), Error>; fn end(&mut self) -> Result<(), Error>;
} }
/// The implementation of [Renderer].
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct RendererImpl<T1, T2, T3> { pub struct RendererImpl<T1, T2, T3> {
sampler: T1, sampler: T1,

View File

@ -2,14 +2,20 @@ use crate::Error;
use crossterm::{Command, QueueableCommand}; use crossterm::{Command, QueueableCommand};
use std::io::Write; use std::io::Write;
/// A stub for OS calls and crossterm functions.
#[cfg_attr(test, mockall::automock)] #[cfg_attr(test, mockall::automock)]
pub trait Terminal { pub trait Terminal {
/// Queues a command for execution.
fn queue<T: 'static + Command>(&mut self, cmd: T) -> Result<(), Error>; fn queue<T: 'static + Command>(&mut self, cmd: T) -> Result<(), Error>;
/// Flushes all queued commands.
fn flush(&mut self) -> Result<(), Error>; fn flush(&mut self) -> Result<(), Error>;
/// Returns the current size of the terminal.
fn size(&self) -> Result<(u16, u16), Error>; fn size(&self) -> Result<(u16, u16), Error>;
/// Returns the current cursor position.
fn position(&self) -> Result<(u16, u16), Error>; fn position(&self) -> Result<(u16, u16), Error>;
} }
/// The implementation of [Terminal].
pub struct TerminalImpl<T> { pub struct TerminalImpl<T> {
out: T, out: T,
} }

View File

@ -3,12 +3,17 @@ use crate::Renderer;
use std::thread; use std::thread;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
/// A stub for the system clock.
#[cfg_attr(test, mockall::automock)] #[cfg_attr(test, mockall::automock)]
pub trait Clock { pub trait Clock {
/// Returns the current time.
fn now(&self) -> Instant; fn now(&self) -> Instant;
/// Sleep for the given duration.
fn sleep(&self, duration: Duration); fn sleep(&self, duration: Duration);
} }
/// The implementation of [Clock].
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct ClockImpl; pub struct ClockImpl;
@ -22,6 +27,7 @@ impl Clock for ClockImpl {
} }
} }
/// A timer for rendering.
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct Timer<T> { pub struct Timer<T> {
clock: T, clock: T,
@ -30,6 +36,7 @@ pub struct Timer<T> {
} }
impl<T: Clock> Timer<T> { impl<T: Clock> Timer<T> {
/// Runs the animation main loop.
pub fn run(&self, mut renderer: impl Renderer) -> Result<(), Error> { pub fn run(&self, mut renderer: impl Renderer) -> Result<(), Error> {
let start = self.clock.now(); let start = self.clock.now();
let mut now = start; let mut now = start;
@ -45,6 +52,8 @@ impl<T: Clock> Timer<T> {
renderer.end() renderer.end()
} }
/// Sleeps until the next frame starts.
/// Returns the current time.
fn delay(&self, begin: Instant) -> Instant { fn delay(&self, begin: Instant) -> Instant {
let end = self.clock.now(); let end = self.clock.now();

View File

@ -1,11 +1,15 @@
use crate::pattern::*; use crate::pattern::*;
use crate::Vector; use crate::Vector;
/// A factory for [Invert].
///
/// Inverts the time of the [Config] for the child [Pattern].
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct InvertFactory { pub struct InvertFactory {
child: Box<dyn PatternFactory>, child: Box<dyn PatternFactory>,
} }
/// Inverts the level of the [Pattern].
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct Invert { pub struct Invert {
child: Box<dyn Pattern>, child: Box<dyn Pattern>,

View File

@ -1,3 +1,5 @@
//! Contains transformations to apply on top of patterns.
mod invert; mod invert;
mod segment; mod segment;
mod shift; mod shift;

View File

@ -1,12 +1,14 @@
use crate::pattern::*; use crate::pattern::*;
use crate::Vector; use crate::Vector;
/// A factory for [Segments].
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct SegmentsFactory { pub struct SegmentsFactory {
child: Box<dyn PatternFactory>, child: Box<dyn PatternFactory>,
segments: f32, segments: f32,
} }
/// Converts a pattern to `n` segments each starting with zero and ending with one.
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct Segments { pub struct Segments {
child: Box<dyn Pattern>, child: Box<dyn Pattern>,

View File

@ -1,11 +1,13 @@
use crate::pattern::*; use crate::pattern::*;
use crate::Vector; use crate::Vector;
/// A factory for [Shift].
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct ShiftFactory { pub struct ShiftFactory {
child: Box<dyn PatternFactory>, child: Box<dyn PatternFactory>,
} }
/// Offsets the [Pattern] out of screen, then moves it inside and finally outside the visible area.
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct Shift { pub struct Shift {
child: Box<dyn Pattern>, child: Box<dyn Pattern>,

View File

@ -1,12 +1,14 @@
use crate::pattern::*; use crate::pattern::*;
use crate::Vector; use crate::Vector;
/// A factory for [Slice].
pub struct SliceFactory { pub struct SliceFactory {
child: Box<dyn PatternFactory>, child: Box<dyn PatternFactory>,
width: f32, width: f32,
rest: f32, rest: f32,
} }
/// Reduces the width of the child [Pattern] to one over `n`.
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct Slice { pub struct Slice {
child: Box<dyn Pattern>, child: Box<dyn Pattern>,

View File

@ -1,11 +1,15 @@
use crate::pattern::*; use crate::pattern::*;
use crate::Vector; use crate::Vector;
/// A factory for [Swap].
///
/// Swaps the x-axis and y-axis of terminal size for the contained [Pattern].
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct SwapFactory { pub struct SwapFactory {
child: Box<dyn PatternFactory>, child: Box<dyn PatternFactory>,
} }
/// Swaps the x-axis and y-axis.
#[derive(derive_more::Constructor)] #[derive(derive_more::Constructor)]
pub struct Swap { pub struct Swap {
child: Box<dyn Pattern>, child: Box<dyn Pattern>,

View File

@ -1,3 +1,4 @@
/// A vector with a x-axis and y-axis.
#[derive(Copy, Clone, PartialEq, Debug, Default, derive_more::Sub)] #[derive(Copy, Clone, PartialEq, Debug, Default, derive_more::Sub)]
pub struct Vector { pub struct Vector {
pub x: f32, pub x: f32,
@ -5,34 +6,42 @@ pub struct Vector {
} }
impl Vector { impl Vector {
/// Creates a new vector.
pub fn new(x: f32, y: f32) -> Self { pub fn new(x: f32, y: f32) -> Self {
Self { x, y } Self { x, y }
} }
/// Creates a new vector from terminal coordinates.
pub fn from_terminal(x: u16, y: u16) -> Self { pub fn from_terminal(x: u16, y: u16) -> Self {
Vector::new(x as f32, y as f32 * 2.0) Vector::new(x as f32, y as f32 * 2.0)
} }
/// Returns the length.
pub fn len(&self) -> f32 { pub fn len(&self) -> f32 {
(self.x * self.x + self.y * self.y).sqrt() (self.x * self.x + self.y * self.y).sqrt()
} }
/// Returns a vector with absolute values.
pub fn abs(&self) -> Vector { pub fn abs(&self) -> Vector {
Self::new(self.x.abs(), self.y.abs()) Self::new(self.x.abs(), self.y.abs())
} }
/// Returns the sum of all axis.
pub fn sum(&self) -> f32 { pub fn sum(&self) -> f32 {
self.x + self.y self.x + self.y
} }
/// Returns the center.
pub fn center(&self) -> Vector { pub fn center(&self) -> Vector {
Self::new(self.x / 2.0, self.y / 2.0) Self::new(self.x / 2.0, self.y / 2.0)
} }
/// Returns the angle.
pub fn angle(&self) -> f32 { pub fn angle(&self) -> f32 {
self.y.atan2(self.x) self.y.atan2(self.x)
} }
/// Returns a vector with x and y swapped.
pub fn swap(&self) -> Vector { pub fn swap(&self) -> Vector {
Self::new(self.y, self.x) Self::new(self.y, self.x)
} }