Add more comments

This commit is contained in:
Nicolas 2022-04-15 07:42:01 +02:00
parent b6a2ae85f4
commit 35b555a04b
16 changed files with 60 additions and 1 deletions

View File

@ -4,6 +4,7 @@ use crate::vec::Vector;
const THICKNESS: f32 = 0.2; const THICKNESS: f32 = 0.2;
const FINAL_RADIUS: f32 = 1.0 + THICKNESS * 2.0; const FINAL_RADIUS: f32 = 1.0 + THICKNESS * 2.0;
/// An animation of an expanding circle.
pub struct CircleAnimation { pub struct CircleAnimation {
center: Vector, center: Vector,
thickness: f32, thickness: f32,

View File

@ -7,7 +7,17 @@ use crate::vec::Vector;
#[cfg(test)] #[cfg(test)]
use mockall::automock; use mockall::automock;
/// A sampler for an animation.
#[cfg_attr(test, automock)] #[cfg_attr(test, automock)]
pub trait Animation { pub trait Animation {
/// Returns the level (of brightness) for the
/// given step of the animation an position on screen.
/// # Arguments
/// * `step`: `0 <= step` and `step <= 1`
///
/// # Return values
/// * `1 < n` => Keep current character
/// * `0 <= n` and `n < 1` => Draw some character
/// * `n < 0` => Clear character
fn sample(&self, step: f32, pos: Vector) -> f32; fn sample(&self, step: f32, pos: Vector) -> f32;
} }

View File

@ -4,6 +4,7 @@ use crate::vec::Vector;
const THICKNESS: f32 = 0.2; const THICKNESS: f32 = 0.2;
const FINAL_DISTANCE: f32 = 1.0 + THICKNESS * 2.0; const FINAL_DISTANCE: f32 = 1.0 + THICKNESS * 2.0;
/// An animation of an expanding rhombus.
pub struct RhombusAnimation { pub struct RhombusAnimation {
center: Vector, center: Vector,
thickness: f32, thickness: f32,

View File

@ -1,10 +1,13 @@
use rand::prelude::IteratorRandom; use rand::prelude::IteratorRandom;
use rand::Rng; use rand::Rng;
/// A trait to get all values of an enum.
pub trait Collection { pub trait Collection {
/// Returns a list of all enum values.
fn all() -> Vec<Self> where Self: Sized; fn all() -> Vec<Self> where Self: Sized;
} }
/// Choose a enum from a list of options.
pub struct Chooser<TRng> { pub struct Chooser<TRng> {
rng: TRng rng: TRng
} }
@ -14,6 +17,8 @@ impl<TRng: Rng> Chooser<TRng> {
Self { rng } Self { rng }
} }
/// Choose an enum item from the provided [Vec].
/// If none are provided, a random one of all enum values is chosen.
pub fn choose<TValue: Collection>(&mut self, selection: Vec<TValue>) -> TValue { pub fn choose<TValue: Collection>(&mut self, selection: Vec<TValue>) -> TValue {
let options = if selection.is_empty() { let options = if selection.is_empty() {
TValue::all() TValue::all()

View File

@ -12,6 +12,7 @@ pub trait ColorSampler {
fn sample(&self, fill: f32) -> Color; fn sample(&self, fill: f32) -> Color;
} }
/// A simple color sampler which interpolates the color from a [Vec].
pub struct SimpleColorSampler { pub struct SimpleColorSampler {
values: Vec<Color> values: Vec<Color>
} }

View File

@ -3,6 +3,7 @@ use crate::vec::Vector;
const INTERVAL: f32 = 4.0; const INTERVAL: f32 = 4.0;
/// Fill based on rings of a circle.
pub struct CircleFillMode { pub struct CircleFillMode {
center: Vector, center: Vector,
interval: f32 interval: f32

View File

@ -1,6 +1,7 @@
use crate::fill::FillMode; use crate::fill::FillMode;
use crate::vec::Vector; use crate::vec::Vector;
/// Fill based on the level of brightness.
pub struct LevelFillMode; pub struct LevelFillMode;
impl LevelFillMode { impl LevelFillMode {

View File

@ -11,5 +11,7 @@ use mockall::automock;
#[cfg_attr(test, automock)] #[cfg_attr(test, automock)]
pub trait FillMode { pub trait FillMode {
/// Gets the color for this character. /// Gets the color for this character.
/// # Arguments
/// * `step`: `0 <= step` and `step <= 1`
fn sample(&self, level: f32, pos: Vector) -> f32; fn sample(&self, level: f32, pos: Vector) -> f32;
} }

View File

@ -3,6 +3,7 @@ use crate::vec::Vector;
const INTERVAL: f32 = 4.0; const INTERVAL: f32 = 4.0;
/// Fill based on diagonal stripes.
pub struct StripesFillMode { pub struct StripesFillMode {
interval: f32 interval: f32
} }

View File

@ -35,6 +35,7 @@ mod timer;
mod runner; mod runner;
mod choose; mod choose;
/// Defines an enum and implements the [Collection] trait.
macro_rules! options { macro_rules! options {
($name:ident { $($opt:ident,)* }) => { ($name:ident { $($opt:ident,)* }) => {
#[derive(Copy, Clone, ArgEnum)] #[derive(Copy, Clone, ArgEnum)]
@ -74,6 +75,7 @@ options!(FillModeType {
const MAX_FPS: u64 = 480; const MAX_FPS: u64 = 480;
/// The program arguments.
#[derive(Parser)] #[derive(Parser)]
#[clap(author = env ! ("CARGO_PKG_AUTHORS"), version = env ! ("CARGO_PKG_VERSION"), about = env ! ("CARGO_PKG_DESCRIPTION"))] #[clap(author = env ! ("CARGO_PKG_AUTHORS"), version = env ! ("CARGO_PKG_VERSION"), about = env ! ("CARGO_PKG_DESCRIPTION"))]
struct Args { struct Args {
@ -119,6 +121,7 @@ fn main() -> Result<(), Error> {
runner.run() runner.run()
} }
/// Validates the chars argument.
fn validate_chars(text: &str) -> Result<String, Error> { fn validate_chars(text: &str) -> Result<String, Error> {
if text.is_empty() { if text.is_empty() {
Err(anyhow!("can't be empty.")) Err(anyhow!("can't be empty."))
@ -127,6 +130,7 @@ fn validate_chars(text: &str) -> Result<String, Error> {
} }
} }
/// Validates the fps argument.
fn validate_fps(text: &str) -> Result<u64, Error> { fn validate_fps(text: &str) -> Result<u64, Error> {
let value = text.parse()?; let value = text.parse()?;
@ -139,6 +143,7 @@ fn validate_fps(text: &str) -> Result<u64, Error> {
} }
} }
/// Validates the duration argument.
fn validate_duration(text: &str) -> Result<u64, Error> { fn validate_duration(text: &str) -> Result<u64, Error> {
let value = text.parse()?; let value = text.parse()?;
@ -149,12 +154,14 @@ fn validate_duration(text: &str) -> Result<u64, Error> {
} }
} }
/// Returns the size to use based on the terminal size and width and height arguments.
fn size(terminal: (u16, u16), width: Option<usize>, height: Option<usize>) -> (usize, usize) { fn size(terminal: (u16, u16), width: Option<usize>, height: Option<usize>) -> (usize, usize) {
let width = width.unwrap_or(terminal.0 as usize); let width = width.unwrap_or(terminal.0 as usize);
let height = height.unwrap_or(terminal.1 as usize); let height = height.unwrap_or(terminal.1 as usize);
(width, height) (width, height)
} }
/// Calculates the delay between frames based on the fps.
fn delay_of_fps(fps: u64) -> Duration { fn delay_of_fps(fps: u64) -> Duration {
Duration::from_nanos(1_000_000_000 / fps) Duration::from_nanos(1_000_000_000 / fps)
} }

View File

@ -6,12 +6,17 @@ use crate::Vector;
#[cfg(test)] #[cfg(test)]
use mockall::automock; use mockall::automock;
/// A trait for anything which performs some rendering.
#[cfg_attr(test, automock)] #[cfg_attr(test, automock)]
pub trait Renderer { pub trait Renderer {
/// Render the frame.
fn render(&mut self, step: f32); fn render(&mut self, step: f32);
/// Present the finished frame.
fn present(&mut self) -> Result<(), Error>; fn present(&mut self) -> Result<(), Error>;
} }
/// Fills its [Surface] with the values received from a [Sampler].
pub struct SamplerRenderer<TSurface, TSampler> { pub struct SamplerRenderer<TSurface, TSampler> {
surface: TSurface, surface: TSurface,
sampler: TSampler, sampler: TSampler,

View File

@ -3,6 +3,7 @@ use anyhow::Error;
use crate::Renderer; use crate::Renderer;
use crate::timer::Timer; use crate::timer::Timer;
/// Periodically calls [Renderer::render] and [Renderer::present].
pub struct Runner<TTimer, TRenderer> { pub struct Runner<TTimer, TRenderer> {
timer: TTimer, timer: TTimer,
ticks: u128, ticks: u128,

View File

@ -8,17 +8,23 @@ use crate::vec::Vector;
#[cfg(test)] #[cfg(test)]
use mockall::automock; use mockall::automock;
/// The action to perform for the given values.
pub enum Sample { pub enum Sample {
Keep, Keep,
Draw { char: char, color: Color }, Draw { char: char, color: Color },
Clear, Clear,
} }
/// Provides a [Sample] for some values.
#[cfg_attr(test, automock)] #[cfg_attr(test, automock)]
pub trait Sampler { pub trait Sampler {
/// Get a [Sample] for the step of the animation and position on screen.
/// # Arguments
/// * `step`: `0 <= step` and `step <= 1`
fn sample(&self, step: f32, pos: Vector) -> Sample; fn sample(&self, step: f32, pos: Vector) -> Sample;
} }
/// Links primitive samplers into a full [Sampler].
pub struct ComposedSampler { pub struct ComposedSampler {
animation: Box<dyn Animation>, animation: Box<dyn Animation>,
fill: Box<dyn FillMode>, fill: Box<dyn FillMode>,

View File

@ -9,21 +9,28 @@ use crate::array::Array2D;
#[cfg(test)] #[cfg(test)]
use mockall::automock; use mockall::automock;
/// A surface to draw characters on.
#[cfg_attr(test, automock)] #[cfg_attr(test, automock)]
pub trait Surface { pub trait Surface {
fn width(&self) -> usize; fn width(&self) -> usize;
fn height(&self) -> usize; fn height(&self) -> usize;
/// Overwrite the character on screen with this value.
fn draw(&mut self, x: usize, y: usize, char: char, color: Color); fn draw(&mut self, x: usize, y: usize, char: char, color: Color);
/// Clear the character on screen.
fn clear(&mut self, x: usize, y: usize); fn clear(&mut self, x: usize, y: usize);
/// Present the finished frame.
fn present(&mut self) -> Result<(), Error>; fn present(&mut self) -> Result<(), Error>;
} }
/// Renders the frames into a [Write] struct.
pub struct WriteSurface<T: Write> { pub struct WriteSurface<T: Write> {
out: T, out: T,
array: Array2D<Cell>, array: Array2D<Cell>,
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
enum Cell { enum Cell {
Keep, Keep,

View File

@ -4,13 +4,17 @@ use std::time::{Duration, Instant};
#[cfg(test)] #[cfg(test)]
use mockall::automock; use mockall::automock;
/// Allows for periodic execution of code.
#[cfg_attr(test, automock)] #[cfg_attr(test, automock)]
pub trait Timer { pub trait Timer {
/// Sleep until the next tick starts.
fn sleep(&mut self); fn sleep(&mut self);
/// Get the delay between ticks.
fn delay(&self) -> Duration; fn delay(&self) -> Duration;
} }
/// A simple [Timer] based on the system clock.
pub struct SimpleTimer { pub struct SimpleTimer {
delay: Duration, delay: Duration,
last: Instant last: Instant

View File

@ -12,26 +12,32 @@ impl Vector {
Self { x, y } Self { x, y }
} }
/// Returns the halfway point.
pub fn center(self) -> Self { pub fn center(self) -> Self {
Self::new(self.x / 2.0, self.y / 2.0) Self::new(self.x / 2.0, self.y / 2.0)
} }
/// Returns the length.
pub fn length(self) -> f32 { pub fn length(self) -> f32 {
(self.x * self.x + self.y * self.y).sqrt() (self.x * self.x + self.y * self.y).sqrt()
} }
/// Returns the angle.
pub fn angle(self) -> f32 { pub fn angle(self) -> f32 {
self.x.atan2(self.y) self.x.atan2(self.y)
} }
/// Returns the value of the smaller axis.
pub fn smaller(self) -> f32 { pub fn smaller(self) -> f32 {
self.x.min(self.y) self.x.min(self.y)
} }
/// Converts all axis into positive 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
} }