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)]
pub enum CharSample {
/// Keep the char.
Keep,
/// Override the char.
Draw(char),
/// Clear the char.
Clear,
}
/// A trait to convert a sample to a [CharSample].
#[cfg_attr(test, mockall::automock)]
pub trait CharConverter {
fn convert(&self, level: f32) -> CharSample;
}
/// The implementation of [CharConverter].
pub struct CharConverterImpl {
chars: Vec<char>,
}
impl CharConverterImpl {
/// The chars used for mapping.
pub fn new(chars: String) -> Self {
let chars = chars.chars().collect();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,18 +4,32 @@ use crossterm::cursor::*;
use crossterm::style::*;
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)]
pub trait Printer {
/// Shows the cursor if it isn't visible.
fn show_cursor(&mut self) -> Result<(), Error>;
/// Hides the cursor if it is visible.
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>;
/// Moves the cursor to the specified position if it isn't there already.
fn move_to(&mut self, x: u16, y: u16) -> Result<(), Error>;
/// Returns the size of the terminal.
fn size(&self) -> Result<(u16, u16), Error>;
/// Sets the foreground color of the terminal.
fn set_foreground(&mut self, color: Color) -> Result<(), Error>;
/// Clears the terminal content.
fn clear(&mut self) -> Result<(), Error>;
/// Flushes all queue commands.
fn flush(&mut self) -> Result<(), Error>;
}
/// The implementation of [Printer].
pub struct PrinterImpl<T> {
term: T,
position: (u16, u16),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,11 +1,15 @@
use crate::pattern::*;
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)]
pub struct SwapFactory {
child: Box<dyn PatternFactory>,
}
/// Swaps the x-axis and y-axis.
#[derive(derive_more::Constructor)]
pub struct Swap {
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)]
pub struct Vector {
pub x: f32,
@ -5,34 +6,42 @@ pub struct Vector {
}
impl Vector {
/// Creates a new vector.
pub fn new(x: f32, y: f32) -> Self {
Self { x, y }
}
/// Creates a new vector from terminal coordinates.
pub fn from_terminal(x: u16, y: u16) -> Self {
Vector::new(x as f32, y as f32 * 2.0)
}
/// Returns the length.
pub fn len(&self) -> f32 {
(self.x * self.x + self.y * self.y).sqrt()
}
/// Returns a vector with absolute values.
pub fn abs(&self) -> Vector {
Self::new(self.x.abs(), self.y.abs())
}
/// Returns the sum of all axis.
pub fn sum(&self) -> f32 {
self.x + self.y
}
/// Returns the center.
pub fn center(&self) -> Vector {
Self::new(self.x / 2.0, self.y / 2.0)
}
/// Returns the angle.
pub fn angle(&self) -> f32 {
self.y.atan2(self.x)
}
/// Returns a vector with x and y swapped.
pub fn swap(&self) -> Vector {
Self::new(self.y, self.x)
}