Initial release: mcufont 0.1.0
Faithful Rust port of Maurycy's mcufont.h — a 5x5 monospace pixel font (~350 bytes of bitmap data) covering A-Z, a-z, 0-9, and the punctuation set - + . , ? ! : = '. - no_std, forbid(unsafe_code), zero deps with default features. - Public glyph tables (UPPER / LOWER / DIGITS / SYMBOLS), SYM_* index constants, and a glyph(c: char) lookup. - Each glyph row is packed in bits 7..=3 MSB-first so the bytes are byte-for-byte compatible with embedded_graphics::ImageRaw. - Optional `embedded-graphics` feature exposes MCU_FONT (MonoFont<'static>), FONT_DATA, and McuGlyphMapping for drop-in use with MonoTextStyle / Text on any DrawTarget (SSD1306 over I²C, ST7735, etc.). - Per-category feature flags (upper / lower / numbers / symbols, all on by default) so users can drop unused glyphs from flash. Licensed CC BY-NC-SA 4.0, inherited from the upstream font data. An email is out to the upstream author asking for a permissive software license (MIT / Apache-2.0); if granted, the crate will be relicensed and a new version published. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
7 files changed
+1184
No files matched your search
@@ -0,0 +1,2 @@
|
||||
/target
|
||||
/Cargo.lock
|
||||
@@ -0,0 +1,44 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Pending
|
||||
|
||||
- **Relicense.** An email is out to the upstream author requesting a
|
||||
permissive software license (MIT / Apache-2.0) on the original C
|
||||
source. If granted, this crate will be relicensed and the next release
|
||||
will reflect the new terms. Until then, CC BY-NC-SA 4.0 applies.
|
||||
|
||||
## [0.1.0] - 2026-04-29
|
||||
|
||||
### Added
|
||||
|
||||
- Initial release. Faithful Rust port of Maurycy's `mcufont.h`
|
||||
(<https://maurycyz.com/projects/mcufont/>) — a 5×5 monospace pixel
|
||||
font, ~350 bytes of bitmap data, covering `A–Z`, `a–z`, `0–9`, and
|
||||
`- + . , ? ! : = '`.
|
||||
- `no_std`, `forbid(unsafe_code)`, zero dependencies with default
|
||||
features.
|
||||
- Public glyph tables: `UPPER`, `LOWER`, `DIGITS`, `SYMBOLS`.
|
||||
- `glyph(c: char) -> Option<&'static Glyph>` lookup function.
|
||||
- `SYM_*` index constants for direct symbol-table access.
|
||||
- Feature flags: `upper`, `lower`, `numbers`, `symbols` (all on by
|
||||
default) — disable individually to save flash.
|
||||
- Optional `embedded-graphics` feature exposing `eg::MCU_FONT`
|
||||
(`MonoFont<'static>`), `eg::FONT_DATA`, and `eg::McuGlyphMapping` for
|
||||
drop-in use with `MonoTextStyle` / `Text` on any `DrawTarget`
|
||||
(SSD1306 over I²C, ST7735, etc.).
|
||||
- Glyph bytes packed in bits 7..=3 (MSB-first), bits 2..=0 zero —
|
||||
layout matches `embedded_graphics::image::ImageRaw` so the same data
|
||||
serves both APIs.
|
||||
|
||||
### Licensed under
|
||||
|
||||
- CC BY-NC-SA 4.0 (inherited from the upstream font data; see
|
||||
`LICENSE`). Non-commercial use only, ShareAlike. See README for
|
||||
implications and the pending relicense note.
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "mcufont"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
rust-version = "1.85"
|
||||
description = "Tiny 5x5 monospace pixel font for microcontrollers — Rust port of Maurycy's mcufont, with optional embedded-graphics integration"
|
||||
license = "CC-BY-NC-SA-4.0"
|
||||
keywords = ["font", "embedded", "no-std", "pixel", "embedded-graphics"]
|
||||
categories = ["embedded", "no-std", "graphics"]
|
||||
readme = "README.md"
|
||||
include = ["src/**/*", "Cargo.toml", "README.md", "CHANGELOG.md", "LICENSE"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[features]
|
||||
default = ["upper", "lower", "numbers", "symbols"]
|
||||
upper = []
|
||||
lower = []
|
||||
numbers = []
|
||||
symbols = []
|
||||
embedded-graphics = ["dep:embedded-graphics"]
|
||||
|
||||
[dependencies]
|
||||
embedded-graphics = { version = "0.8", optional = true, default-features = false }
|
||||
@@ -0,0 +1,438 @@
|
||||
Attribution-NonCommercial-ShareAlike 4.0 International
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||
does not provide legal services or legal advice. Distribution of
|
||||
Creative Commons public licenses does not create a lawyer-client or
|
||||
other relationship. Creative Commons makes its licenses and related
|
||||
information available on an "as-is" basis. Creative Commons gives no
|
||||
warranties regarding its licenses, any material licensed under their
|
||||
terms and conditions, or any related information. Creative Commons
|
||||
disclaims all liability for damages resulting from their use to the
|
||||
fullest extent possible.
|
||||
|
||||
Using Creative Commons Public Licenses
|
||||
|
||||
Creative Commons public licenses provide a standard set of terms and
|
||||
conditions that creators and other rights holders may use to share
|
||||
original works of authorship and other material subject to copyright
|
||||
and certain other rights specified in the public license below. The
|
||||
following considerations are for informational purposes only, are not
|
||||
exhaustive, and do not form part of our licenses.
|
||||
|
||||
Considerations for licensors: Our public licenses are
|
||||
intended for use by those authorized to give the public
|
||||
permission to use material in ways otherwise restricted by
|
||||
copyright and certain other rights. Our licenses are
|
||||
irrevocable. Licensors should read and understand the terms
|
||||
and conditions of the license they choose before applying it.
|
||||
Licensors should also secure all rights necessary before
|
||||
applying our licenses so that the public can reuse the
|
||||
material as expected. Licensors should clearly mark any
|
||||
material not subject to the license. This includes other CC-
|
||||
licensed material, or material used under an exception or
|
||||
limitation to copyright. More considerations for licensors:
|
||||
wiki.creativecommons.org/Considerations_for_licensors
|
||||
|
||||
Considerations for the public: By using one of our public
|
||||
licenses, a licensor grants the public permission to use the
|
||||
licensed material under specified terms and conditions. If
|
||||
the licensor's permission is not necessary for any reason--for
|
||||
example, because of any applicable exception or limitation to
|
||||
copyright--then that use is not regulated by the license. Our
|
||||
licenses grant only permissions under copyright and certain
|
||||
other rights that a licensor has authority to grant. Use of
|
||||
the licensed material may still be restricted for other
|
||||
reasons, including because others have copyright or other
|
||||
rights in the material. A licensor may make special requests,
|
||||
such as asking that all changes be marked or described.
|
||||
Although not required by our licenses, you are encouraged to
|
||||
respect those requests where reasonable. More considerations
|
||||
for the public:
|
||||
wiki.creativecommons.org/Considerations_for_licensees
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
|
||||
Public License
|
||||
|
||||
By exercising the Licensed Rights (defined below), You accept and agree
|
||||
to be bound by the terms and conditions of this Creative Commons
|
||||
Attribution-NonCommercial-ShareAlike 4.0 International Public License
|
||||
("Public License"). To the extent this Public License may be
|
||||
interpreted as a contract, You are granted the Licensed Rights in
|
||||
consideration of Your acceptance of these terms and conditions, and the
|
||||
Licensor grants You such rights in consideration of benefits the
|
||||
Licensor receives from making the Licensed Material available under
|
||||
these terms and conditions.
|
||||
|
||||
|
||||
Section 1 -- Definitions.
|
||||
|
||||
a. Adapted Material means material subject to Copyright and Similar
|
||||
Rights that is derived from or based upon the Licensed Material
|
||||
and in which the Licensed Material is translated, altered,
|
||||
arranged, transformed, or otherwise modified in a manner requiring
|
||||
permission under the Copyright and Similar Rights held by the
|
||||
Licensor. For purposes of this Public License, where the Licensed
|
||||
Material is a musical work, performance, or sound recording,
|
||||
Adapted Material is always produced where the Licensed Material is
|
||||
synched in timed relation with a moving image.
|
||||
|
||||
b. Adapter's License means the license You apply to Your Copyright
|
||||
and Similar Rights in Your contributions to Adapted Material in
|
||||
accordance with the terms and conditions of this Public License.
|
||||
|
||||
c. BY-NC-SA Compatible License means a license listed at
|
||||
creativecommons.org/compatiblelicenses, approved by Creative
|
||||
Commons as essentially the equivalent of this Public License.
|
||||
|
||||
d. Copyright and Similar Rights means copyright and/or similar rights
|
||||
closely related to copyright including, without limitation,
|
||||
performance, broadcast, sound recording, and Sui Generis Database
|
||||
Rights, without regard to how the rights are labeled or
|
||||
categorized. For purposes of this Public License, the rights
|
||||
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||
Rights.
|
||||
|
||||
e. Effective Technological Measures means those measures that, in the
|
||||
absence of proper authority, may not be circumvented under laws
|
||||
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||
Treaty adopted on December 20, 1996, and/or similar international
|
||||
agreements.
|
||||
|
||||
f. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||
any other exception or limitation to Copyright and Similar Rights
|
||||
that applies to Your use of the Licensed Material.
|
||||
|
||||
g. License Elements means the license attributes listed in the name
|
||||
of a Creative Commons Public License. The License Elements of this
|
||||
Public License are Attribution, NonCommercial, and ShareAlike.
|
||||
|
||||
h. Licensed Material means the artistic or literary work, database,
|
||||
or other material to which the Licensor applied this Public
|
||||
License.
|
||||
|
||||
i. Licensed Rights means the rights granted to You subject to the
|
||||
terms and conditions of this Public License, which are limited to
|
||||
all Copyright and Similar Rights that apply to Your use of the
|
||||
Licensed Material and that the Licensor has authority to license.
|
||||
|
||||
j. Licensor means the individual(s) or entity(ies) granting rights
|
||||
under this Public License.
|
||||
|
||||
k. NonCommercial means not primarily intended for or directed towards
|
||||
commercial advantage or monetary compensation. For purposes of
|
||||
this Public License, the exchange of the Licensed Material for
|
||||
other material subject to Copyright and Similar Rights by digital
|
||||
file-sharing or similar means is NonCommercial provided there is
|
||||
no payment of monetary compensation in connection with the
|
||||
exchange.
|
||||
|
||||
l. Share means to provide material to the public by any means or
|
||||
process that requires permission under the Licensed Rights, such
|
||||
as reproduction, public display, public performance, distribution,
|
||||
dissemination, communication, or importation, and to make material
|
||||
available to the public including in ways that members of the
|
||||
public may access the material from a place and at a time
|
||||
individually chosen by them.
|
||||
|
||||
m. Sui Generis Database Rights means rights other than copyright
|
||||
resulting from Directive 96/9/EC of the European Parliament and of
|
||||
the Council of 11 March 1996 on the legal protection of databases,
|
||||
as amended and/or succeeded, as well as other essentially
|
||||
equivalent rights anywhere in the world.
|
||||
|
||||
n. You means the individual or entity exercising the Licensed Rights
|
||||
under this Public License. Your has a corresponding meaning.
|
||||
|
||||
|
||||
Section 2 -- Scope.
|
||||
|
||||
a. License grant.
|
||||
|
||||
1. Subject to the terms and conditions of this Public License,
|
||||
the Licensor hereby grants You a worldwide, royalty-free,
|
||||
non-sublicensable, non-exclusive, irrevocable license to
|
||||
exercise the Licensed Rights in the Licensed Material to:
|
||||
|
||||
a. reproduce and Share the Licensed Material, in whole or
|
||||
in part, for NonCommercial purposes only; and
|
||||
|
||||
b. produce, reproduce, and Share Adapted Material for
|
||||
NonCommercial purposes only.
|
||||
|
||||
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||
Exceptions and Limitations apply to Your use, this Public
|
||||
License does not apply, and You do not need to comply with
|
||||
its terms and conditions.
|
||||
|
||||
3. Term. The term of this Public License is specified in Section
|
||||
6(a).
|
||||
|
||||
4. Media and formats; technical modifications allowed. The
|
||||
Licensor authorizes You to exercise the Licensed Rights in
|
||||
all media and formats whether now known or hereafter created,
|
||||
and to make technical modifications necessary to do so. The
|
||||
Licensor waives and/or agrees not to assert any right or
|
||||
authority to forbid You from making technical modifications
|
||||
necessary to exercise the Licensed Rights, including
|
||||
technical modifications necessary to circumvent Effective
|
||||
Technological Measures. For purposes of this Public License,
|
||||
simply making modifications authorized by this Section 2(a)
|
||||
(4) never produces Adapted Material.
|
||||
|
||||
5. Downstream recipients.
|
||||
|
||||
a. Offer from the Licensor -- Licensed Material. Every
|
||||
recipient of the Licensed Material automatically
|
||||
receives an offer from the Licensor to exercise the
|
||||
Licensed Rights under the terms and conditions of this
|
||||
Public License.
|
||||
|
||||
b. Additional offer from the Licensor -- Adapted Material.
|
||||
Every recipient of Adapted Material from You
|
||||
automatically receives an offer from the Licensor to
|
||||
exercise the Licensed Rights in the Adapted Material
|
||||
under the conditions of the Adapter's License You apply.
|
||||
|
||||
c. No downstream restrictions. You may not offer or impose
|
||||
any additional or different terms or conditions on, or
|
||||
apply any Effective Technological Measures to, the
|
||||
Licensed Material if doing so restricts exercise of the
|
||||
Licensed Rights by any recipient of the Licensed
|
||||
Material.
|
||||
|
||||
6. No endorsement. Nothing in this Public License constitutes or
|
||||
may be construed as permission to assert or imply that You
|
||||
are, or that Your use of the Licensed Material is, connected
|
||||
with, or sponsored, endorsed, or granted official status by,
|
||||
the Licensor or others designated to receive attribution as
|
||||
provided in Section 3(a)(1)(A)(i).
|
||||
|
||||
b. Other rights.
|
||||
|
||||
1. Moral rights, such as the right of integrity, are not
|
||||
licensed under this Public License, nor are publicity,
|
||||
privacy, and/or other similar personality rights; however, to
|
||||
the extent possible, the Licensor waives and/or agrees not to
|
||||
assert any such rights held by the Licensor to the limited
|
||||
extent necessary to allow You to exercise the Licensed
|
||||
Rights, but not otherwise.
|
||||
|
||||
2. Patent and trademark rights are not licensed under this
|
||||
Public License.
|
||||
|
||||
3. To the extent possible, the Licensor waives any right to
|
||||
collect royalties from You for the exercise of the Licensed
|
||||
Rights, whether directly or through a collecting society
|
||||
under any voluntary or waivable statutory or compulsory
|
||||
licensing scheme. In all other cases the Licensor expressly
|
||||
reserves any right to collect such royalties, including when
|
||||
the Licensed Material is used other than for NonCommercial
|
||||
purposes.
|
||||
|
||||
|
||||
Section 3 -- License Conditions.
|
||||
|
||||
Your exercise of the Licensed Rights is expressly made subject to the
|
||||
following conditions.
|
||||
|
||||
a. Attribution.
|
||||
|
||||
1. If You Share the Licensed Material (including in modified
|
||||
form), You must:
|
||||
|
||||
a. retain the following if it is supplied by the Licensor
|
||||
with the Licensed Material:
|
||||
|
||||
i. identification of the creator(s) of the Licensed
|
||||
Material and any others designated to receive
|
||||
attribution, in any reasonable manner requested by
|
||||
the Licensor (including by pseudonym if
|
||||
designated);
|
||||
|
||||
ii. a copyright notice;
|
||||
|
||||
iii. a notice that refers to this Public License;
|
||||
|
||||
iv. a notice that refers to the disclaimer of
|
||||
warranties;
|
||||
|
||||
v. a URI or hyperlink to the Licensed Material to the
|
||||
extent reasonably practicable;
|
||||
|
||||
b. indicate if You modified the Licensed Material and
|
||||
retain an indication of any previous modifications; and
|
||||
|
||||
c. indicate the Licensed Material is licensed under this
|
||||
Public License, and include the text of, or the URI or
|
||||
hyperlink to, this Public License.
|
||||
|
||||
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||
reasonable manner based on the medium, means, and context in
|
||||
which You Share the Licensed Material. For example, it may be
|
||||
reasonable to satisfy the conditions by providing a URI or
|
||||
hyperlink to a resource that includes the required
|
||||
information.
|
||||
3. If requested by the Licensor, You must remove any of the
|
||||
information required by Section 3(a)(1)(A) to the extent
|
||||
reasonably practicable.
|
||||
|
||||
b. ShareAlike.
|
||||
|
||||
In addition to the conditions in Section 3(a), if You Share
|
||||
Adapted Material You produce, the following conditions also apply.
|
||||
|
||||
1. The Adapter's License You apply must be a Creative Commons
|
||||
license with the same License Elements, this version or
|
||||
later, or a BY-NC-SA Compatible License.
|
||||
|
||||
2. You must include the text of, or the URI or hyperlink to, the
|
||||
Adapter's License You apply. You may satisfy this condition
|
||||
in any reasonable manner based on the medium, means, and
|
||||
context in which You Share Adapted Material.
|
||||
|
||||
3. You may not offer or impose any additional or different terms
|
||||
or conditions on, or apply any Effective Technological
|
||||
Measures to, Adapted Material that restrict exercise of the
|
||||
rights granted under the Adapter's License You apply.
|
||||
|
||||
|
||||
Section 4 -- Sui Generis Database Rights.
|
||||
|
||||
Where the Licensed Rights include Sui Generis Database Rights that
|
||||
apply to Your use of the Licensed Material:
|
||||
|
||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||
to extract, reuse, reproduce, and Share all or a substantial
|
||||
portion of the contents of the database for NonCommercial purposes
|
||||
only;
|
||||
|
||||
b. if You include all or a substantial portion of the database
|
||||
contents in a database in which You have Sui Generis Database
|
||||
Rights, then the database in which You have Sui Generis Database
|
||||
Rights (but not its individual contents) is Adapted Material,
|
||||
including for purposes of Section 3(b); and
|
||||
|
||||
c. You must comply with the conditions in Section 3(a) if You Share
|
||||
all or a substantial portion of the contents of the database.
|
||||
|
||||
For the avoidance of doubt, this Section 4 supplements and does not
|
||||
replace Your obligations under this Public License where the Licensed
|
||||
Rights include other Copyright and Similar Rights.
|
||||
|
||||
|
||||
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||
|
||||
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||
|
||||
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||
|
||||
c. The disclaimer of warranties and limitation of liability provided
|
||||
above shall be interpreted in a manner that, to the extent
|
||||
possible, most closely approximates an absolute disclaimer and
|
||||
waiver of all liability.
|
||||
|
||||
|
||||
Section 6 -- Term and Termination.
|
||||
|
||||
a. This Public License applies for the term of the Copyright and
|
||||
Similar Rights licensed here. However, if You fail to comply with
|
||||
this Public License, then Your rights under this Public License
|
||||
terminate automatically.
|
||||
|
||||
b. Where Your right to use the Licensed Material has terminated under
|
||||
Section 6(a), it reinstates:
|
||||
|
||||
1. automatically as of the date the violation is cured, provided
|
||||
it is cured within 30 days of Your discovery of the
|
||||
violation; or
|
||||
|
||||
2. upon express reinstatement by the Licensor.
|
||||
|
||||
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||
right the Licensor may have to seek remedies for Your violations
|
||||
of this Public License.
|
||||
|
||||
c. For the avoidance of doubt, the Licensor may also offer the
|
||||
Licensed Material under separate terms or conditions or stop
|
||||
distributing the Licensed Material at any time; however, doing so
|
||||
will not terminate this Public License.
|
||||
|
||||
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||
License.
|
||||
|
||||
|
||||
Section 7 -- Other Terms and Conditions.
|
||||
|
||||
a. The Licensor shall not be bound by any additional or different
|
||||
terms or conditions communicated by You unless expressly agreed.
|
||||
|
||||
b. Any arrangements, understandings, or agreements regarding the
|
||||
Licensed Material not stated herein are separate from and
|
||||
independent of the terms and conditions of this Public License.
|
||||
|
||||
|
||||
Section 8 -- Interpretation.
|
||||
|
||||
a. For the avoidance of doubt, this Public License does not, and
|
||||
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||
conditions on any use of the Licensed Material that could lawfully
|
||||
be made without permission under this Public License.
|
||||
|
||||
b. To the extent possible, if any provision of this Public License is
|
||||
deemed unenforceable, it shall be automatically reformed to the
|
||||
minimum extent necessary to make it enforceable. If the provision
|
||||
cannot be reformed, it shall be severed from this Public License
|
||||
without affecting the enforceability of the remaining terms and
|
||||
conditions.
|
||||
|
||||
c. No term or condition of this Public License will be waived and no
|
||||
failure to comply consented to unless expressly agreed to by the
|
||||
Licensor.
|
||||
|
||||
d. Nothing in this Public License constitutes or may be interpreted
|
||||
as a limitation upon, or waiver of, any privileges and immunities
|
||||
that apply to the Licensor or You, including from the legal
|
||||
processes of any jurisdiction or authority.
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons is not a party to its public
|
||||
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
||||
its public licenses to material it publishes and in those instances
|
||||
will be considered the “Licensor.” The text of the Creative Commons
|
||||
public licenses is dedicated to the public domain under the CC0 Public
|
||||
Domain Dedication. Except for the limited purpose of indicating that
|
||||
material is shared under a Creative Commons public license or as
|
||||
otherwise permitted by the Creative Commons policies published at
|
||||
creativecommons.org/policies, Creative Commons does not authorize the
|
||||
use of the trademark "Creative Commons" or any other trademark or logo
|
||||
of Creative Commons without its prior written consent including,
|
||||
without limitation, in connection with any unauthorized modifications
|
||||
to any of its public licenses or any other arrangements,
|
||||
understandings, or agreements concerning use of licensed material. For
|
||||
the avoidance of doubt, this paragraph does not form part of the
|
||||
public licenses.
|
||||
|
||||
Creative Commons may be contacted at creativecommons.org.
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
# mcufont
|
||||
|
||||
Tiny 5×5 monospace pixel font for microcontrollers. `no_std`, zero dependencies (with default features), ~350 bytes of font data.
|
||||
|
||||
Faithful Rust port of [Maurycy's `mcufont`](https://maurycyz.com/projects/mcufont/) C header. Covers `A–Z`, `a–z`, `0–9`, and the punctuation set `- + . , ? ! : = '`.
|
||||
|
||||
## Usage — raw
|
||||
|
||||
```rust
|
||||
use mcufont::{glyph, GLYPH_WIDTH, GLYPH_HEIGHT};
|
||||
|
||||
if let Some(g) = glyph('A') {
|
||||
for row in g {
|
||||
// bit 7 = leftmost pixel, bit 3 = rightmost; bits 2..=0 are zero.
|
||||
for x in 0..GLYPH_WIDTH {
|
||||
let on = (row >> (7 - x)) & 1 == 1;
|
||||
// ... blit to your framebuffer
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The static tables `UPPER`, `LOWER`, `DIGITS`, `SYMBOLS` are also public — index them directly if you don't need the lookup function.
|
||||
|
||||
## Usage — `embedded-graphics`
|
||||
|
||||
Enable the `embedded-graphics` feature in `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
mcufont = { version = "0.1", features = ["embedded-graphics"] }
|
||||
```
|
||||
|
||||
Then drop `MCU_FONT` into a `MonoTextStyle`:
|
||||
|
||||
```rust
|
||||
use embedded_graphics::{
|
||||
mono_font::MonoTextStyle, pixelcolor::BinaryColor,
|
||||
prelude::*, text::Text,
|
||||
};
|
||||
use mcufont::eg::MCU_FONT;
|
||||
|
||||
let style = MonoTextStyle::new(&MCU_FONT, BinaryColor::On);
|
||||
Text::new("Hello", Point::new(0, 5), style).draw(&mut display)?;
|
||||
```
|
||||
|
||||
Works with any `embedded-graphics` `DrawTarget` — SSD1306 over I²C, SH1106, ST7735, fbink, etc.
|
||||
|
||||
## Features
|
||||
|
||||
| Feature | Default | What it adds |
|
||||
| ------------------- | ------- | ---------------------------------------------------------------- |
|
||||
| `upper` | yes | `A–Z` (130 bytes) |
|
||||
| `lower` | yes | `a–z` (130 bytes) |
|
||||
| `numbers` | yes | `0–9` (50 bytes) |
|
||||
| `symbols` | yes | `- + . , ? ! : = '` (45 bytes) |
|
||||
| `embedded-graphics` | no | `MonoFont` integration + concatenated strip (~2× the flash cost) |
|
||||
|
||||
Disable any category you don't need to save flash. With all four enabled the raw tables sum to ~355 bytes.
|
||||
|
||||
## Glyph format
|
||||
|
||||
Each glyph is `[u8; 5]` — one byte per row. Pixels are packed in **bits 7..=3 MSB-first** (bit 7 = leftmost pixel); bits 2..=0 are always zero. This layout matches `embedded_graphics::image::ImageRaw` byte ordering for a 5-pixel-wide row, so the same bytes drive both the raw API and the `embedded-graphics` integration with no transformation.
|
||||
|
||||
```text
|
||||
byte = 0b A B C D E _ _ _ → row pixels = A B C D E
|
||||
```
|
||||
|
||||
## Embedded targets
|
||||
|
||||
Plain `static` arrays land in `.rodata`, which is mapped to flash on the common embedded Rust targets — Cortex-M, RISC-V, ESP32, etc. The crate is `no_std` and uses no allocator. AVR's Harvard architecture (`PROGMEM`) is **not** addressed; AVR Rust support is nightly-only and out of scope for this crate.
|
||||
|
||||
## License — read this
|
||||
|
||||
This crate is currently licensed **CC BY-NC-SA 4.0** — the only license offered for the upstream font data on the source page. That means:
|
||||
|
||||
- **Non-commercial use only.** You cannot ship this crate (or work derived from its font data) in a product you sell.
|
||||
- **ShareAlike.** Any derivative work that incorporates the font data must also be licensed under CC BY-NC-SA 4.0.
|
||||
- This is **not** an OSI-approved open-source license. It is incompatible with most permissive and copyleft software licenses.
|
||||
|
||||
If those terms don't fit your project, this crate is not for you.
|
||||
|
||||
Full license text: [`LICENSE`](./LICENSE) — see also <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
|
||||
|
||||
### Pending relicense
|
||||
|
||||
We've reached out to the upstream author asking for a permissive software license (MIT or Apache-2.0) on the original C source. If granted, this crate will be relicensed accordingly and a new version published. Until then the inherited CC BY-NC-SA 4.0 license stands.
|
||||
|
||||
Watch the [CHANGELOG](./CHANGELOG.md) for the relicense, if and when it lands.
|
||||
|
||||
## Attribution
|
||||
|
||||
- 5×5 font data and original C implementation: <https://maurycyz.com/projects/mcufont/>
|
||||
- Original 5×6 `font-inline.h` it was based on: lcamtuf, <https://lcamtuf.coredump.cx/soft/embedded/font-inline.h>
|
||||
- Lineage further traces to the ZX Spectrum 8×8 system font.
|
||||
|
||||
This Rust crate (scaffolding, `embedded-graphics` integration, tests) is itself a derivative work and is therefore also CC BY-NC-SA 4.0.
|
||||
@@ -0,0 +1,258 @@
|
||||
//! `embedded-graphics` integration. Enable the `embedded-graphics` feature.
|
||||
//!
|
||||
//! ```ignore
|
||||
//! use embedded_graphics::{
|
||||
//! mono_font::MonoTextStyle, pixelcolor::BinaryColor,
|
||||
//! prelude::*, text::Text,
|
||||
//! };
|
||||
//! use mcufont::eg::MCU_FONT;
|
||||
//!
|
||||
//! let style = MonoTextStyle::new(&MCU_FONT, BinaryColor::On);
|
||||
//! Text::new("Hello", Point::new(0, 5), style).draw(&mut display)?;
|
||||
//! ```
|
||||
|
||||
use embedded_graphics::{
|
||||
geometry::Size,
|
||||
image::ImageRaw,
|
||||
mono_font::{DecorationDimensions, MonoFont, mapping::GlyphMapping},
|
||||
pixelcolor::BinaryColor,
|
||||
};
|
||||
|
||||
#[cfg(not(any(
|
||||
feature = "upper",
|
||||
feature = "lower",
|
||||
feature = "numbers",
|
||||
feature = "symbols",
|
||||
)))]
|
||||
compile_error!(
|
||||
"the `embedded-graphics` feature requires at least one of `upper`, `lower`, `numbers`, `symbols`"
|
||||
);
|
||||
|
||||
const fn upper_count() -> usize {
|
||||
#[cfg(feature = "upper")]
|
||||
{
|
||||
26
|
||||
}
|
||||
#[cfg(not(feature = "upper"))]
|
||||
{
|
||||
0
|
||||
}
|
||||
}
|
||||
const fn lower_count() -> usize {
|
||||
#[cfg(feature = "lower")]
|
||||
{
|
||||
26
|
||||
}
|
||||
#[cfg(not(feature = "lower"))]
|
||||
{
|
||||
0
|
||||
}
|
||||
}
|
||||
const fn digits_count() -> usize {
|
||||
#[cfg(feature = "numbers")]
|
||||
{
|
||||
10
|
||||
}
|
||||
#[cfg(not(feature = "numbers"))]
|
||||
{
|
||||
0
|
||||
}
|
||||
}
|
||||
const fn symbols_count() -> usize {
|
||||
#[cfg(feature = "symbols")]
|
||||
{
|
||||
9
|
||||
}
|
||||
#[cfg(not(feature = "symbols"))]
|
||||
{
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
const UPPER_OFFSET: usize = 0;
|
||||
const LOWER_OFFSET: usize = UPPER_OFFSET + upper_count();
|
||||
const DIGITS_OFFSET: usize = LOWER_OFFSET + lower_count();
|
||||
const SYMBOLS_OFFSET: usize = DIGITS_OFFSET + digits_count();
|
||||
const TOTAL_GLYPHS: usize = SYMBOLS_OFFSET + symbols_count();
|
||||
const STRIP_BYTES: usize = TOTAL_GLYPHS * crate::GLYPH_HEIGHT;
|
||||
|
||||
const fn build_strip() -> [u8; STRIP_BYTES] {
|
||||
let mut out = [0u8; STRIP_BYTES];
|
||||
let mut i: usize = 0;
|
||||
|
||||
#[cfg(feature = "upper")]
|
||||
{
|
||||
let mut g = 0;
|
||||
while g < 26 {
|
||||
let mut r = 0;
|
||||
while r < crate::GLYPH_HEIGHT {
|
||||
out[i] = crate::UPPER[g][r];
|
||||
i += 1;
|
||||
r += 1;
|
||||
}
|
||||
g += 1;
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "lower")]
|
||||
{
|
||||
let mut g = 0;
|
||||
while g < 26 {
|
||||
let mut r = 0;
|
||||
while r < crate::GLYPH_HEIGHT {
|
||||
out[i] = crate::LOWER[g][r];
|
||||
i += 1;
|
||||
r += 1;
|
||||
}
|
||||
g += 1;
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "numbers")]
|
||||
{
|
||||
let mut g = 0;
|
||||
while g < 10 {
|
||||
let mut r = 0;
|
||||
while r < crate::GLYPH_HEIGHT {
|
||||
out[i] = crate::DIGITS[g][r];
|
||||
i += 1;
|
||||
r += 1;
|
||||
}
|
||||
g += 1;
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "symbols")]
|
||||
{
|
||||
let mut g = 0;
|
||||
while g < 9 {
|
||||
let mut r = 0;
|
||||
while r < crate::GLYPH_HEIGHT {
|
||||
out[i] = crate::SYMBOLS[g][r];
|
||||
i += 1;
|
||||
r += 1;
|
||||
}
|
||||
g += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let _ = i;
|
||||
out
|
||||
}
|
||||
|
||||
/// All enabled glyphs concatenated as a 5-pixel-wide vertical strip,
|
||||
/// in feature order: upper, lower, digits, symbols.
|
||||
pub static FONT_DATA: [u8; STRIP_BYTES] = build_strip();
|
||||
|
||||
/// Maps ASCII chars to glyph indices in [`FONT_DATA`]. Unknown characters
|
||||
/// fall back to `'?'` if the `symbols` feature is enabled, otherwise to
|
||||
/// glyph 0.
|
||||
pub struct McuGlyphMapping;
|
||||
|
||||
impl GlyphMapping for McuGlyphMapping {
|
||||
fn index(&self, c: char) -> usize {
|
||||
#[cfg(feature = "upper")]
|
||||
if c.is_ascii_uppercase() {
|
||||
return UPPER_OFFSET + (c as usize - 'A' as usize);
|
||||
}
|
||||
#[cfg(feature = "lower")]
|
||||
if c.is_ascii_lowercase() {
|
||||
return LOWER_OFFSET + (c as usize - 'a' as usize);
|
||||
}
|
||||
#[cfg(feature = "numbers")]
|
||||
if c.is_ascii_digit() {
|
||||
return DIGITS_OFFSET + (c as usize - '0' as usize);
|
||||
}
|
||||
#[cfg(feature = "symbols")]
|
||||
match c {
|
||||
'-' => return SYMBOLS_OFFSET + crate::SYM_MINUS,
|
||||
'+' => return SYMBOLS_OFFSET + crate::SYM_PLUS,
|
||||
'.' => return SYMBOLS_OFFSET + crate::SYM_DOT,
|
||||
',' => return SYMBOLS_OFFSET + crate::SYM_COMMA,
|
||||
'?' => return SYMBOLS_OFFSET + crate::SYM_QMARK,
|
||||
'!' => return SYMBOLS_OFFSET + crate::SYM_EXMARK,
|
||||
':' => return SYMBOLS_OFFSET + crate::SYM_COLON,
|
||||
'=' => return SYMBOLS_OFFSET + crate::SYM_EQ,
|
||||
'\'' => return SYMBOLS_OFFSET + crate::SYM_TICK,
|
||||
_ => {}
|
||||
}
|
||||
let _ = c;
|
||||
#[cfg(feature = "symbols")]
|
||||
{
|
||||
SYMBOLS_OFFSET + crate::SYM_QMARK
|
||||
}
|
||||
#[cfg(not(feature = "symbols"))]
|
||||
{
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static MAPPING: McuGlyphMapping = McuGlyphMapping;
|
||||
|
||||
/// Drop-in `MonoFont` for use with `MonoTextStyle`, `Text`, etc.
|
||||
pub static MCU_FONT: MonoFont<'static> = MonoFont {
|
||||
image: ImageRaw::<BinaryColor>::new(&FONT_DATA, crate::GLYPH_WIDTH as u32),
|
||||
character_size: Size::new(crate::GLYPH_WIDTH as u32, crate::GLYPH_HEIGHT as u32),
|
||||
character_spacing: 1,
|
||||
baseline: (crate::GLYPH_HEIGHT - 1) as u32,
|
||||
strikethrough: DecorationDimensions::default_strikethrough(crate::GLYPH_HEIGHT as u32),
|
||||
underline: DecorationDimensions::default_underline(crate::GLYPH_HEIGHT as u32),
|
||||
glyph_mapping: &MAPPING,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn strip_size_is_consistent() {
|
||||
assert_eq!(FONT_DATA.len(), STRIP_BYTES);
|
||||
assert_eq!(STRIP_BYTES, TOTAL_GLYPHS * 5);
|
||||
}
|
||||
|
||||
#[cfg(feature = "upper")]
|
||||
#[test]
|
||||
fn mapping_upper() {
|
||||
assert_eq!(MAPPING.index('A'), 0);
|
||||
assert_eq!(MAPPING.index('Z'), 25);
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "upper", feature = "lower"))]
|
||||
#[test]
|
||||
fn mapping_lower_offset() {
|
||||
assert_eq!(MAPPING.index('a'), 26);
|
||||
assert_eq!(MAPPING.index('z'), 51);
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "upper", feature = "lower", feature = "numbers"))]
|
||||
#[test]
|
||||
fn mapping_digit_offset() {
|
||||
assert_eq!(MAPPING.index('0'), 52);
|
||||
assert_eq!(MAPPING.index('9'), 61);
|
||||
}
|
||||
|
||||
#[cfg(all(
|
||||
feature = "upper",
|
||||
feature = "lower",
|
||||
feature = "numbers",
|
||||
feature = "symbols"
|
||||
))]
|
||||
#[test]
|
||||
fn mapping_symbol_offset() {
|
||||
assert_eq!(MAPPING.index('-'), 62);
|
||||
assert_eq!(MAPPING.index('\''), 70);
|
||||
}
|
||||
|
||||
#[cfg(feature = "symbols")]
|
||||
#[test]
|
||||
fn mapping_unknown_falls_back_to_qmark() {
|
||||
let qmark = MAPPING.index('?');
|
||||
assert_eq!(MAPPING.index(' '), qmark);
|
||||
assert_eq!(MAPPING.index('@'), qmark);
|
||||
assert_eq!(MAPPING.index('é'), qmark);
|
||||
}
|
||||
|
||||
#[cfg(feature = "upper")]
|
||||
#[test]
|
||||
fn strip_starts_with_upper_a() {
|
||||
assert_eq!(&FONT_DATA[0..5], &crate::UPPER[0]);
|
||||
}
|
||||
}
|
||||
+320
@@ -0,0 +1,320 @@
|
||||
//! Tiny 5×5 monospace pixel font for microcontrollers.
|
||||
//!
|
||||
//! Faithful Rust port of Maurycy's `mcufont`
|
||||
//! (<https://maurycyz.com/projects/mcufont/>), itself based on lcamtuf's
|
||||
//! `font-inline.h` (<https://lcamtuf.coredump.cx/soft/embedded/font-inline.h>).
|
||||
//! Covers `A–Z`, `a–z`, `0–9`, and the punctuation set `- + . , ? ! : = '`.
|
||||
//!
|
||||
//! # Glyph format
|
||||
//!
|
||||
//! Each [`Glyph`] is 5 bytes — one byte per row. Pixels are packed in
|
||||
//! bits 7..=3 MSB-first (bit 7 = leftmost pixel), bits 2..=0 are zero.
|
||||
//! This layout matches `embedded_graphics::image::ImageRaw` byte ordering
|
||||
//! for a 5-pixel-wide row, so the same bytes serve both the raw API and
|
||||
//! the `embedded-graphics` integration with no transformation.
|
||||
//!
|
||||
//! ```text
|
||||
//! byte = 0b A B C D E _ _ _ → row pixels = A B C D E
|
||||
//! ```
|
||||
//!
|
||||
//! # Features
|
||||
//!
|
||||
//! - `upper`, `lower`, `numbers`, `symbols` (default) — include each
|
||||
//! character category. Drop any you don't need to save flash.
|
||||
//! - `embedded-graphics` (off by default) — exposes [`eg::MCU_FONT`], a
|
||||
//! drop-in `MonoFont` for the embedded-graphics ecosystem.
|
||||
//!
|
||||
//! # License
|
||||
//!
|
||||
//! Currently **CC BY-NC-SA 4.0** — inherited from the upstream font data,
|
||||
//! which is the only license the source page offers. That means
|
||||
//! non-commercial use only and share-alike derivatives. See `LICENSE` and
|
||||
//! the README for the full text and implications.
|
||||
//!
|
||||
//! **Pending relicense:** an email is out to the upstream author asking
|
||||
//! for a permissive software license (MIT / Apache-2.0). If granted, this
|
||||
//! crate will be relicensed and a new version published. Until then, CC
|
||||
//! BY-NC-SA 4.0 applies.
|
||||
|
||||
#![no_std]
|
||||
#![forbid(unsafe_code)]
|
||||
// `0b01110_000` separates the 5 pixel bits from the 3 padding bits — that
|
||||
// asymmetric grouping is the whole point of this layout.
|
||||
#![allow(clippy::unusual_byte_groupings)]
|
||||
|
||||
#[cfg(feature = "embedded-graphics")]
|
||||
pub mod eg;
|
||||
|
||||
/// Visible glyph width in pixels.
|
||||
pub const GLYPH_WIDTH: usize = 5;
|
||||
|
||||
/// Glyph height in rows.
|
||||
pub const GLYPH_HEIGHT: usize = 5;
|
||||
|
||||
/// Recommended on-screen cell size: 5 px glyph + 1 px gap.
|
||||
pub const CELL: usize = 6;
|
||||
|
||||
/// One glyph: 5 rows, each row one byte. Pixels in bits 7..=3 MSB-first;
|
||||
/// bits 2..=0 zero.
|
||||
pub type Glyph = [u8; GLYPH_HEIGHT];
|
||||
|
||||
#[cfg(feature = "upper")]
|
||||
pub static UPPER: [Glyph; 26] = [
|
||||
[0b01110_000, 0b10001_000, 0b11111_000, 0b10001_000, 0b10001_000], // A
|
||||
[0b11110_000, 0b10001_000, 0b11110_000, 0b10001_000, 0b11110_000], // B
|
||||
[0b01111_000, 0b10000_000, 0b10000_000, 0b10000_000, 0b01111_000], // C
|
||||
[0b11110_000, 0b10001_000, 0b10001_000, 0b10001_000, 0b11110_000], // D
|
||||
[0b11111_000, 0b10000_000, 0b11100_000, 0b10000_000, 0b11111_000], // E
|
||||
[0b11111_000, 0b10000_000, 0b11100_000, 0b10000_000, 0b10000_000], // F
|
||||
[0b01111_000, 0b10000_000, 0b10011_000, 0b10001_000, 0b01111_000], // G
|
||||
[0b10001_000, 0b10001_000, 0b11111_000, 0b10001_000, 0b10001_000], // H
|
||||
[0b11111_000, 0b00100_000, 0b00100_000, 0b00100_000, 0b11111_000], // I
|
||||
[0b11111_000, 0b00010_000, 0b00010_000, 0b10010_000, 0b01100_000], // J
|
||||
[0b10010_000, 0b10100_000, 0b11000_000, 0b10100_000, 0b10010_000], // K
|
||||
[0b10000_000, 0b10000_000, 0b10000_000, 0b10000_000, 0b11111_000], // L
|
||||
[0b11111_000, 0b10101_000, 0b10101_000, 0b10001_000, 0b10001_000], // M
|
||||
[0b10001_000, 0b11001_000, 0b10101_000, 0b10011_000, 0b10001_000], // N
|
||||
[0b01110_000, 0b10001_000, 0b10001_000, 0b10001_000, 0b01110_000], // O
|
||||
[0b11110_000, 0b10001_000, 0b11110_000, 0b10000_000, 0b10000_000], // P
|
||||
[0b01110_000, 0b10001_000, 0b10001_000, 0b10010_000, 0b01101_000], // Q
|
||||
[0b11110_000, 0b10001_000, 0b11110_000, 0b10010_000, 0b10001_000], // R
|
||||
[0b01111_000, 0b10000_000, 0b01110_000, 0b00001_000, 0b11110_000], // S
|
||||
[0b11111_000, 0b00100_000, 0b00100_000, 0b00100_000, 0b00100_000], // T
|
||||
[0b10001_000, 0b10001_000, 0b10001_000, 0b10001_000, 0b01110_000], // U
|
||||
[0b10001_000, 0b10001_000, 0b01010_000, 0b01010_000, 0b00100_000], // V
|
||||
[0b10001_000, 0b10001_000, 0b10101_000, 0b10101_000, 0b11011_000], // W
|
||||
[0b10001_000, 0b01010_000, 0b00100_000, 0b01010_000, 0b10001_000], // X
|
||||
[0b10001_000, 0b01010_000, 0b00100_000, 0b00100_000, 0b00100_000], // Y
|
||||
[0b11111_000, 0b00010_000, 0b00100_000, 0b01000_000, 0b11111_000], // Z
|
||||
];
|
||||
|
||||
#[cfg(feature = "lower")]
|
||||
pub static LOWER: [Glyph; 26] = [
|
||||
[0b00000_000, 0b01111_000, 0b10001_000, 0b10001_000, 0b01111_000], // a
|
||||
[0b10000_000, 0b11110_000, 0b10001_000, 0b10001_000, 0b11110_000], // b
|
||||
[0b00000_000, 0b01111_000, 0b10000_000, 0b10000_000, 0b01111_000], // c
|
||||
[0b00001_000, 0b01111_000, 0b10001_000, 0b10001_000, 0b01111_000], // d
|
||||
[0b00000_000, 0b01110_000, 0b11111_000, 0b10000_000, 0b01111_000], // e
|
||||
[0b00000_000, 0b01111_000, 0b10000_000, 0b11110_000, 0b10000_000], // f
|
||||
[0b00000_000, 0b01110_000, 0b11111_000, 0b00001_000, 0b11110_000], // g
|
||||
[0b10000_000, 0b10000_000, 0b11110_000, 0b10001_000, 0b10001_000], // h
|
||||
[0b00100_000, 0b00000_000, 0b01100_000, 0b00100_000, 0b01110_000], // i
|
||||
[0b00010_000, 0b00000_000, 0b00010_000, 0b10010_000, 0b01100_000], // j
|
||||
[0b10000_000, 0b10000_000, 0b10110_000, 0b11000_000, 0b10110_000], // k
|
||||
[0b00000_000, 0b10000_000, 0b10000_000, 0b10000_000, 0b01111_000], // l
|
||||
[0b00000_000, 0b11110_000, 0b10101_000, 0b10101_000, 0b10001_000], // m
|
||||
[0b00000_000, 0b11110_000, 0b10001_000, 0b10001_000, 0b10001_000], // n
|
||||
[0b00000_000, 0b01110_000, 0b10001_000, 0b10001_000, 0b01110_000], // o
|
||||
[0b00000_000, 0b11110_000, 0b10001_000, 0b11110_000, 0b10000_000], // p
|
||||
[0b00000_000, 0b01111_000, 0b10001_000, 0b01111_000, 0b00001_000], // q
|
||||
[0b00000_000, 0b01110_000, 0b10000_000, 0b10000_000, 0b10000_000], // r
|
||||
[0b00000_000, 0b01110_000, 0b11000_000, 0b00110_000, 0b11100_000], // s
|
||||
[0b00000_000, 0b11111_000, 0b00100_000, 0b00100_000, 0b00100_000], // t
|
||||
[0b00000_000, 0b10001_000, 0b10001_000, 0b10001_000, 0b01110_000], // u
|
||||
[0b00000_000, 0b10001_000, 0b10001_000, 0b01010_000, 0b00100_000], // v
|
||||
[0b00000_000, 0b10001_000, 0b10101_000, 0b10101_000, 0b01110_000], // w
|
||||
[0b00000_000, 0b10010_000, 0b01100_000, 0b01100_000, 0b10010_000], // x
|
||||
[0b00000_000, 0b10010_000, 0b01110_000, 0b00010_000, 0b01100_000], // y
|
||||
[0b00000_000, 0b11110_000, 0b00100_000, 0b01000_000, 0b11110_000], // z
|
||||
];
|
||||
|
||||
#[cfg(feature = "numbers")]
|
||||
pub static DIGITS: [Glyph; 10] = [
|
||||
[0b01110_000, 0b10001_000, 0b10101_000, 0b10001_000, 0b01110_000], // 0
|
||||
[0b01100_000, 0b10100_000, 0b00100_000, 0b00100_000, 0b11111_000], // 1
|
||||
[0b01110_000, 0b10001_000, 0b00110_000, 0b01000_000, 0b11111_000], // 2
|
||||
[0b11111_000, 0b00001_000, 0b01110_000, 0b00001_000, 0b11110_000], // 3
|
||||
[0b10010_000, 0b10010_000, 0b11111_000, 0b00010_000, 0b00010_000], // 4
|
||||
[0b11111_000, 0b10000_000, 0b01110_000, 0b00001_000, 0b11110_000], // 5
|
||||
[0b01110_000, 0b10000_000, 0b11110_000, 0b10001_000, 0b01110_000], // 6
|
||||
[0b11111_000, 0b00010_000, 0b00100_000, 0b01000_000, 0b01000_000], // 7
|
||||
[0b01110_000, 0b10001_000, 0b01110_000, 0b10001_000, 0b01110_000], // 8
|
||||
[0b11111_000, 0b10001_000, 0b11111_000, 0b00001_000, 0b00001_000], // 9
|
||||
];
|
||||
|
||||
/// Index of `'-'` (minus) in [`SYMBOLS`].
|
||||
#[cfg(feature = "symbols")]
|
||||
pub const SYM_MINUS: usize = 0;
|
||||
/// Index of `'+'` (plus) in [`SYMBOLS`].
|
||||
#[cfg(feature = "symbols")]
|
||||
pub const SYM_PLUS: usize = 1;
|
||||
/// Index of `'.'` (dot) in [`SYMBOLS`].
|
||||
#[cfg(feature = "symbols")]
|
||||
pub const SYM_DOT: usize = 2;
|
||||
/// Index of `','` (comma) in [`SYMBOLS`].
|
||||
#[cfg(feature = "symbols")]
|
||||
pub const SYM_COMMA: usize = 3;
|
||||
/// Index of `'?'` (question mark) in [`SYMBOLS`].
|
||||
#[cfg(feature = "symbols")]
|
||||
pub const SYM_QMARK: usize = 4;
|
||||
/// Index of `'!'` (exclamation mark) in [`SYMBOLS`].
|
||||
#[cfg(feature = "symbols")]
|
||||
pub const SYM_EXMARK: usize = 5;
|
||||
/// Index of `':'` (colon) in [`SYMBOLS`].
|
||||
#[cfg(feature = "symbols")]
|
||||
pub const SYM_COLON: usize = 6;
|
||||
/// Index of `'='` (equals) in [`SYMBOLS`].
|
||||
#[cfg(feature = "symbols")]
|
||||
pub const SYM_EQ: usize = 7;
|
||||
/// Index of `'\''` (apostrophe) in [`SYMBOLS`].
|
||||
#[cfg(feature = "symbols")]
|
||||
pub const SYM_TICK: usize = 8;
|
||||
|
||||
#[cfg(feature = "symbols")]
|
||||
pub static SYMBOLS: [Glyph; 9] = [
|
||||
[0b00000_000, 0b00000_000, 0b01110_000, 0b00000_000, 0b00000_000], // -
|
||||
[0b00000_000, 0b00100_000, 0b01110_000, 0b00100_000, 0b00000_000], // +
|
||||
[0b00000_000, 0b00000_000, 0b00000_000, 0b00000_000, 0b01000_000], // .
|
||||
[0b00000_000, 0b00000_000, 0b00000_000, 0b00100_000, 0b01000_000], // ,
|
||||
[0b01110_000, 0b10001_000, 0b00110_000, 0b00000_000, 0b00100_000], // ?
|
||||
[0b00100_000, 0b00100_000, 0b00100_000, 0b00000_000, 0b00100_000], // !
|
||||
[0b00000_000, 0b01000_000, 0b00000_000, 0b01000_000, 0b00000_000], // :
|
||||
[0b00000_000, 0b01110_000, 0b00000_000, 0b01110_000, 0b00000_000], // =
|
||||
[0b00100_000, 0b00100_000, 0b00000_000, 0b00000_000, 0b00000_000], // '
|
||||
];
|
||||
|
||||
/// Look up the glyph for an ASCII character. Returns `None` if the
|
||||
/// character isn't in the supported set (or if its category feature
|
||||
/// is disabled).
|
||||
pub fn glyph(c: char) -> Option<&'static Glyph> {
|
||||
#[cfg(feature = "upper")]
|
||||
if c.is_ascii_uppercase() {
|
||||
return Some(&UPPER[c as usize - 'A' as usize]);
|
||||
}
|
||||
#[cfg(feature = "lower")]
|
||||
if c.is_ascii_lowercase() {
|
||||
return Some(&LOWER[c as usize - 'a' as usize]);
|
||||
}
|
||||
#[cfg(feature = "numbers")]
|
||||
if c.is_ascii_digit() {
|
||||
return Some(&DIGITS[c as usize - '0' as usize]);
|
||||
}
|
||||
#[cfg(feature = "symbols")]
|
||||
match c {
|
||||
'-' => return Some(&SYMBOLS[SYM_MINUS]),
|
||||
'+' => return Some(&SYMBOLS[SYM_PLUS]),
|
||||
'.' => return Some(&SYMBOLS[SYM_DOT]),
|
||||
',' => return Some(&SYMBOLS[SYM_COMMA]),
|
||||
'?' => return Some(&SYMBOLS[SYM_QMARK]),
|
||||
'!' => return Some(&SYMBOLS[SYM_EXMARK]),
|
||||
':' => return Some(&SYMBOLS[SYM_COLON]),
|
||||
'=' => return Some(&SYMBOLS[SYM_EQ]),
|
||||
'\'' => return Some(&SYMBOLS[SYM_TICK]),
|
||||
_ => {}
|
||||
}
|
||||
let _ = c;
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[cfg(feature = "upper")]
|
||||
#[test]
|
||||
fn upper_lookup() {
|
||||
assert_eq!(glyph('A'), Some(&UPPER[0]));
|
||||
assert_eq!(glyph('M'), Some(&UPPER[12]));
|
||||
assert_eq!(glyph('Z'), Some(&UPPER[25]));
|
||||
}
|
||||
|
||||
#[cfg(feature = "lower")]
|
||||
#[test]
|
||||
fn lower_lookup() {
|
||||
assert_eq!(glyph('a'), Some(&LOWER[0]));
|
||||
assert_eq!(glyph('m'), Some(&LOWER[12]));
|
||||
assert_eq!(glyph('z'), Some(&LOWER[25]));
|
||||
}
|
||||
|
||||
#[cfg(feature = "numbers")]
|
||||
#[test]
|
||||
fn digit_lookup() {
|
||||
assert_eq!(glyph('0'), Some(&DIGITS[0]));
|
||||
assert_eq!(glyph('5'), Some(&DIGITS[5]));
|
||||
assert_eq!(glyph('9'), Some(&DIGITS[9]));
|
||||
}
|
||||
|
||||
#[cfg(feature = "symbols")]
|
||||
#[test]
|
||||
fn symbol_lookup() {
|
||||
assert_eq!(glyph('-'), Some(&SYMBOLS[SYM_MINUS]));
|
||||
assert_eq!(glyph('+'), Some(&SYMBOLS[SYM_PLUS]));
|
||||
assert_eq!(glyph('.'), Some(&SYMBOLS[SYM_DOT]));
|
||||
assert_eq!(glyph(','), Some(&SYMBOLS[SYM_COMMA]));
|
||||
assert_eq!(glyph('?'), Some(&SYMBOLS[SYM_QMARK]));
|
||||
assert_eq!(glyph('!'), Some(&SYMBOLS[SYM_EXMARK]));
|
||||
assert_eq!(glyph(':'), Some(&SYMBOLS[SYM_COLON]));
|
||||
assert_eq!(glyph('='), Some(&SYMBOLS[SYM_EQ]));
|
||||
assert_eq!(glyph('\''), Some(&SYMBOLS[SYM_TICK]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsupported_returns_none() {
|
||||
assert_eq!(glyph(' '), None);
|
||||
assert_eq!(glyph('@'), None);
|
||||
assert_eq!(glyph('é'), None);
|
||||
assert_eq!(glyph('~'), None);
|
||||
assert_eq!(glyph('/'), None);
|
||||
assert_eq!(glyph('['), None);
|
||||
}
|
||||
|
||||
/// Every byte in every table must have its low 3 bits clear; the
|
||||
/// pixel data lives in bits 7..=3.
|
||||
#[test]
|
||||
fn padding_bits_are_zero() {
|
||||
let check = |g: &Glyph| g.iter().all(|b| b & 0b0000_0111 == 0);
|
||||
#[cfg(feature = "upper")]
|
||||
assert!(UPPER.iter().all(check));
|
||||
#[cfg(feature = "lower")]
|
||||
assert!(LOWER.iter().all(check));
|
||||
#[cfg(feature = "numbers")]
|
||||
assert!(DIGITS.iter().all(check));
|
||||
#[cfg(feature = "symbols")]
|
||||
assert!(SYMBOLS.iter().all(check));
|
||||
}
|
||||
|
||||
/// Spot-check transcription against the C source: each row in C is
|
||||
/// in bits 4..=0; ours is in bits 7..=3. Verify a handful of glyphs.
|
||||
#[cfg(feature = "upper")]
|
||||
#[test]
|
||||
fn matches_c_source_upper() {
|
||||
// 'A': 0b01110, 0b10001, 0b11111, 0b10001, 0b10001
|
||||
assert_eq!(
|
||||
UPPER[0],
|
||||
[
|
||||
0b01110 << 3,
|
||||
0b10001 << 3,
|
||||
0b11111 << 3,
|
||||
0b10001 << 3,
|
||||
0b10001 << 3,
|
||||
]
|
||||
);
|
||||
// 'M': 0b11111, 0b10101, 0b10101, 0b10001, 0b10001
|
||||
assert_eq!(
|
||||
UPPER[12],
|
||||
[
|
||||
0b11111 << 3,
|
||||
0b10101 << 3,
|
||||
0b10101 << 3,
|
||||
0b10001 << 3,
|
||||
0b10001 << 3,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "numbers")]
|
||||
#[test]
|
||||
fn matches_c_source_zero() {
|
||||
// '0': 0b01110, 0b10001, 0b10101, 0b10001, 0b01110
|
||||
assert_eq!(
|
||||
DIGITS[0],
|
||||
[
|
||||
0b01110 << 3,
|
||||
0b10001 << 3,
|
||||
0b10101 << 3,
|
||||
0b10001 << 3,
|
||||
0b01110 << 3,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user