punch_card/
lib.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2#![expect(incomplete_features, reason = "whoops")]
3#![feature(generic_const_exprs, test)]
4// needed for a test
5#![recursion_limit = "512"]
6#![no_std]
7//! # punch-card
8//!
9//! [![Repository](https://img.shields.io/badge/repository-GitHub-brightgreen.svg)](https://github.com/1e1001/rsutil/tree/main/punch-card)
10//! [![Crates.io](https://img.shields.io/crates/v/punch-card)](https://crates.io/crates/punch-card)
11//! [![docs.rs](https://img.shields.io/docsrs/punch-card)](https://docs.rs/punch-card)
12//! [![MIT OR Apache-2.0](https://img.shields.io/crates/l/punch-card)](https://github.com/1e1001/rsutil/blob/main/punch-card/README.md#License)
13//!
14//! A library for making punched cards like this:
15//!
16//! ```rust
17//! use punch_card::PunchCard;
18//!
19//! #[rustfmt::skip]
20//! println!("{}", std::str::from_utf8(&(
21//!     .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..,
22//!     ..=..=..=..=..=.. .. .. ..=..=..=..=..=..=.. ..=..=.. ..=..=..=..=..=..=.. ..=..=..=..=..=.. ..=..=..=..=..,
23//!     ..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..=..,
24//!     .. ..=..=..=..=..=.. .. .. ..=.. ..=.. ..=.. .. .. .. .. ..=.. ..=.. ..=.. ..=..=.. .. .. .. .. .. ..=.. ..,
25//!     ..=.. .. .. .. ..=..=..=.. .. .. .. .. .. ..=..=..=..=.. .. .. .. .. .. ..=.. .. ..=.. ..=..=.. .. .. .. ..,
26//!     .. ..=..=.. .. .. ..=..=.. .. .. ..=..=.. ..=.. ..=..=.. .. .. ..=..=.. ..=.. ..=..=.. .. ..=.. .. .. ..=..,
27//!     .. .. .. .. ..=..=..=..=..=..=.. .. .. ..=..=.. ..=..=..=..=.. .. .. ..=..=.. .. ..=..=.. .. ..=.. ..=.. ..,
28//!     .. .. .. .. ..=.. ..=..=..=.. ..=.. ..=..=.. ..=..=..=..=.. ..=.. ..=..=..=.. ..=.. ..=.. ..=..=..=.. .. ..,
29//! ).punch_card()).unwrap());
30//! ```
31//!
32//! ## Why?
33//!
34//! I saw the `punch_card` example in [`weird-exprs.rs`] and (inspired by
35//! [`analog_literals`]) thought "what if that was useful?" and then created
36//! this.
37//!
38//! ## Usage
39//!
40//! Run [`.punch_card()`](PunchCard::punch_card) on a card tuple to convert it
41//! into an array of values
42//!
43//! By default, punch-card supports the following sizes of card:
44//!
45//! - *n* × 1 → array of [`bool`]
46//! - *n* × 8 → array of [`u8`] (probably the one you'll be using the
47//!   most)
48//! - *n* × 16 → array of [`u16`]
49//! - *n* × 32 → array of [`u32`]
50//! - *n* × 64 → array of [`u64`]
51//! - *n* × 128 → array of [`u128`]
52//!
53//! A card is simply a tuple of some amount of rows, where each row is a chain
54//! of `..`'s or `..=`'s terminated by a `..`, as shown in the above example.
55//!
56//! *Note: this uses the [`generic_const_exprs`](https://github.com/rust-lang/rust/issues/76560) feature, it should be safe to use though.*
57//!
58//! [`analog_literals`]: <https://crates.io/crates/analog_literals>
59//! [`weird-exprs.rs`]: <https://github.com/rust-lang/rust/blob/bdcb6a99e853732f8ec050ae4986aa3af51d44c5/src/test/ui/weird-exprs.rs#L123-L131>
60
61use internal::PunchCardInner;
62
63mod internal;
64#[cfg(test)]
65mod tests;
66
67/// Represents a value that is a punch card, formatted like this:
68/// ```rust
69/// # use punch_card::PunchCard;
70/// #
71/// # #[rustfmt::skip]
72/// # println!("{}", std::str::from_utf8(&
73/// (
74///     .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..,
75///     ..=..=..=..=..=.. .. ..=..=..=..=..=.. .. ..,
76///     .. ..=..=..=..=..=..=.. ..=..=..=..=..=.. ..,
77///     .. .. .. .. .. .. .. ..=.. ..=.. .. .. .. ..,
78///     ..=.. ..=..=..=..=.. .. ..=.. ..=.. .. ..=..,
79///     .. ..=..=..=..=..=.. ..=..=.. ..=..=.. .. ..,
80///     .. .. .. .. ..=.. .. ..=..=..=.. .. .. ..=..,
81///     .. ..=.. .. ..=.. .. ..=..=.. .. .. ..=.. ..,
82/// ).punch_card()
83/// # ).unwrap());
84/// ```
85/// An `=` indicates a one bit and a space indicates a zero bit.
86///
87/// Automatically implemented for punched cards of heights
88/// 1, 8, 16, 32, 64, and 128.
89pub trait PunchCard {
90	#[doc(hidden)]
91	const LENGTH: usize;
92	/// Type for each column of the tape
93	type Output;
94	/// Parses the punch card into your output format of choice.
95	fn punch_card(&self) -> [Self::Output; Self::LENGTH];
96}
97
98impl<T: PunchCardInner> PunchCard for T {
99	const LENGTH: usize = T::LENGTH;
100	type Output = T::Output;
101	fn punch_card(&self) -> [Self::Output; <Self as PunchCard>::LENGTH] {
102		let mut out = [Default::default(); <Self as PunchCard>::LENGTH];
103		Self::eval_part(&mut out, 0);
104		out
105	}
106}