completed basic functions
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
72
Cargo.lock
generated
Normal file
72
Cargo.lock
generated
Normal file
@@ -0,0 +1,72 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "bdf-tools"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"strum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd"
|
||||
dependencies = [
|
||||
"strum_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
7
Cargo.toml
Normal file
7
Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "bdf-tools"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
strum = { version = "0.28.0", features = ["derive", "strum_macros"] }
|
||||
1
links.txt
Normal file
1
links.txt
Normal file
@@ -0,0 +1 @@
|
||||
https://www.x.org/releases/X11R7.6/doc/xorg-docs/specs/XLFD/xlfd.html
|
||||
42
src/glyph.rs
Normal file
42
src/glyph.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
use crate::Point;
|
||||
|
||||
pub struct Glyph {
|
||||
pub(crate) startchar: String,
|
||||
pub(crate) encoding: GlyphEncoding,
|
||||
pub(crate) swidth: Point,
|
||||
pub(crate) dwidth: Point,
|
||||
pub(crate) swidth1: Option<Point>,
|
||||
pub(crate) dwidth1: Option<Point>,
|
||||
pub(crate) vvector: Option<Point>,
|
||||
pub(crate) bbx: GlyphBBX,
|
||||
pub(crate) attributes: Option<[char;4]>,
|
||||
pub(crate) bitmap: Vec<u8>,
|
||||
}
|
||||
|
||||
pub enum GlyphEncoding {
|
||||
Standard(i32),
|
||||
NonStandard(Option<i32>),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for GlyphEncoding {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Standard(i) => write!(f, "{}", i),
|
||||
Self::NonStandard(i) => match i {
|
||||
Some(v) => write!(f, "-1 {}", v),
|
||||
None => write!(f, "-1"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GlyphBBX {
|
||||
pub(crate) x_width: i32,
|
||||
pub(crate) y_width: i32,
|
||||
pub(crate) x_offset: i32,
|
||||
pub(crate) y_offset: i32,
|
||||
}
|
||||
|
||||
pub struct GlyphBitmap {
|
||||
raw_bitmap: Vec<u8>,
|
||||
}
|
||||
239
src/lib.rs
Normal file
239
src/lib.rs
Normal file
@@ -0,0 +1,239 @@
|
||||
use crate::properties::Properties;
|
||||
|
||||
mod glyph;
|
||||
mod properties;
|
||||
mod parser;
|
||||
|
||||
pub struct Font {
|
||||
start_font: f32,
|
||||
content_version: Option<i32>,
|
||||
font: String,
|
||||
size: Size,
|
||||
font_bounding_box: BoundBox,
|
||||
metrics_set: Option<i32>,
|
||||
scalable_width: Option<Point>,
|
||||
device_width: Option<Point>,
|
||||
scalable_width_1: Option<Point>,
|
||||
device_width_1: Option<Point>,
|
||||
v_vector: Option<Point>,
|
||||
properties: properties::Properties,
|
||||
chars: u32,
|
||||
glyphs: Vec<glyph::Glyph>
|
||||
}
|
||||
|
||||
impl Font {
|
||||
pub fn to_string(&self) -> String {
|
||||
let mut output = String::new();
|
||||
output.push_str(&format!("STARTFONT {}\n", self.start_font));
|
||||
|
||||
match self.content_version {
|
||||
Some(cv) => output.push_str(&format!("CONTENTVERSION {}\n", cv)),
|
||||
None => (),
|
||||
}
|
||||
|
||||
output.push_str(&format!("FONT {}\n", self.font));
|
||||
output.push_str(&format!("SIZE {} {} {}\n", self.size.point_size, self.size.resolution.x, self.size.resolution.y));
|
||||
output.push_str(&format!("FONTBOUNDINGBOX {} {} {} {}\n", self.font_bounding_box.size.x, self.font_bounding_box.size.y, self.font_bounding_box.offset.x, self.font_bounding_box.offset.y));
|
||||
|
||||
match self.metrics_set {
|
||||
Some(ms) => output.push_str(&format!("METRICSSET {}\n", ms)),
|
||||
None => (),
|
||||
}
|
||||
match &self.scalable_width {
|
||||
Some(sw) => output.push_str(&format!("SWIDTH {} {}", sw.x, sw.y)),
|
||||
None => (),
|
||||
}
|
||||
match &self.device_width {
|
||||
Some(dw) => output.push_str(&format!("DWIDTH {} {}", dw.x, dw.y)),
|
||||
None => (),
|
||||
}
|
||||
match &self.scalable_width_1 {
|
||||
Some(sw) => output.push_str(&format!("SWIDTH1 {} {}", sw.x, sw.y)),
|
||||
None => (),
|
||||
}
|
||||
match &self.device_width_1 {
|
||||
Some(dw) => output.push_str(&format!("SWIDTH1 {} {}", dw.x, dw.y)),
|
||||
None => (),
|
||||
}
|
||||
match &self.v_vector {
|
||||
Some(vv) => output.push_str(&format!("SWIDTH1 {} {}", vv.x, vv.y)),
|
||||
None => (),
|
||||
}
|
||||
|
||||
output.push_str(&format!("STARTPROPERTIES {}\n", self.properties.properties.len()));
|
||||
for i in self.properties.properties.iter() {
|
||||
output.push_str(&format!("{} {}\n", i.0, i.1));
|
||||
}
|
||||
output.push_str("ENDROPERTIES\n");
|
||||
output.push_str(&format!("CHARS {}\n", self.chars));
|
||||
|
||||
for i in self.glyphs.iter() {
|
||||
output.push_str(&format!("STARTCHAR {}\n", i.startchar));
|
||||
output.push_str(&format!("ENCODING {}\n", i.encoding));
|
||||
output.push_str(&format!("SWIDTH {} {}\n", i.swidth.x, i.swidth.y));
|
||||
output.push_str(&format!("DWIDTH {} {}\n", i.dwidth.x, i.dwidth.y));
|
||||
|
||||
match &i.swidth1 {
|
||||
Some(sw) => output.push_str(&format!("SWIDTH1 {} {}\n", sw.x, sw.y)),
|
||||
None => (),
|
||||
}
|
||||
match &i.dwidth1 {
|
||||
Some(dw) => output.push_str(&format!("DWIDTH1 {} {}\n", dw.x, dw.y)),
|
||||
None => (),
|
||||
}
|
||||
match &i.vvector {
|
||||
Some(vv) => output.push_str(&format!("VVECTOR {} {}\n", vv.x, vv.y)),
|
||||
None => (),
|
||||
}
|
||||
output.push_str(&format!("BBX {} {} {} {}\n", i.bbx.x_width, i.bbx.y_width, i.bbx.x_offset, i.bbx.y_offset));
|
||||
|
||||
match &i.attributes {
|
||||
Some(at) => {
|
||||
output.push_str("ATTRIBUTES");
|
||||
|
||||
for j in at {
|
||||
output.push_str(&format!(" {}", j))
|
||||
}
|
||||
output.push('\n');
|
||||
},
|
||||
None => (),
|
||||
}
|
||||
|
||||
output.push_str("BITMAP\n");
|
||||
|
||||
for row in i.bitmap.chunks(i.bbx.x_width as usize) {
|
||||
let mut formatted = String::new();
|
||||
for item in row {
|
||||
formatted.push_str(&format!("{:02x}", item));
|
||||
}
|
||||
output.push_str(&format!("{}\n", formatted));
|
||||
}
|
||||
output.push_str("ENDCHAR");
|
||||
}
|
||||
|
||||
output.push_str("ENDFONT");
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FontBuilder {
|
||||
start_font: Option<f32>,
|
||||
content_version: Option<i32>,
|
||||
font: Option<String>,
|
||||
size: Option<Size>,
|
||||
font_bounding_box: Option<BoundBox>,
|
||||
metrics_set: Option<i32>,
|
||||
scalable_width: Option<Point>,
|
||||
device_width: Option<Point>,
|
||||
scalable_width_1: Option<Point>,
|
||||
device_width_1: Option<Point>,
|
||||
v_vector: Option<Point>,
|
||||
properties: properties::Properties,
|
||||
chars: Option<u32>,
|
||||
glyphs: Vec<glyph::Glyph>
|
||||
}
|
||||
|
||||
impl FontBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
start_font: None,
|
||||
content_version: None,
|
||||
font: None,
|
||||
size: None,
|
||||
font_bounding_box: None,
|
||||
metrics_set: None,
|
||||
scalable_width: None,
|
||||
device_width: None,
|
||||
scalable_width_1: None,
|
||||
device_width_1: None,
|
||||
v_vector: None,
|
||||
properties: Properties::new(),
|
||||
chars: None,
|
||||
glyphs: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<Font, FontError> {
|
||||
Ok(Font {
|
||||
start_font: self.start_font.ok_or(FontError{})?,
|
||||
content_version: self.content_version,
|
||||
font: self.font.ok_or(FontError{})?,
|
||||
size: self.size.ok_or(FontError{})?,
|
||||
font_bounding_box: self.font_bounding_box.ok_or(FontError{})?,
|
||||
metrics_set: self.metrics_set,
|
||||
scalable_width: self.scalable_width,
|
||||
device_width: self.device_width,
|
||||
scalable_width_1: self.scalable_width_1,
|
||||
device_width_1: self.device_width_1,
|
||||
v_vector: self.v_vector,
|
||||
properties: self.properties,
|
||||
chars: self.chars.ok_or(FontError{})?,
|
||||
glyphs: self.glyphs,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn start_font(mut self, font_version: f32) -> Self {
|
||||
self.start_font = Some(font_version);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn content_version(mut self, content_version: i32) -> Self {
|
||||
self.content_version = Some(content_version);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn font(mut self, font: String) -> Self {
|
||||
self.font = Some(font);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn size(mut self, size: Size) -> Self {
|
||||
self.size = Some(size);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn bounding_box(mut self, bounding_box: BoundBox) -> Self {
|
||||
self.font_bounding_box = Some(bounding_box);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn metrics_set(mut self, metrics_set: i32) -> Self {
|
||||
self.metrics_set = Some(metrics_set);
|
||||
self
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub struct FontError {
|
||||
|
||||
}
|
||||
|
||||
pub struct Size {
|
||||
point_size: i32,
|
||||
resolution: Point,
|
||||
}
|
||||
|
||||
pub struct BoundBox {
|
||||
size: Point,
|
||||
offset: Point,
|
||||
}
|
||||
|
||||
pub struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
pub fn parse_font(input: &str ) -> Font {
|
||||
let mut parser = parser::Parser::new();
|
||||
|
||||
parser.parse(input).unwrap()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
//use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
}
|
||||
}
|
||||
222
src/parser.rs
Normal file
222
src/parser.rs
Normal file
@@ -0,0 +1,222 @@
|
||||
use crate::properties::Property;
|
||||
|
||||
pub(crate) struct Parser {
|
||||
state: ParserState,
|
||||
parsed_font: crate::FontBuilder,
|
||||
}
|
||||
|
||||
impl Parser {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
state: ParserState::Font,
|
||||
parsed_font: crate::FontBuilder::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parse(&mut self, input: &str) -> Result<crate::Font, ParseError> {
|
||||
for line in input.lines() {
|
||||
let keyword = line.split_once(' ').unwrap();
|
||||
match self.state {
|
||||
ParserState::Font => {
|
||||
match keyword.0.to_ascii_uppercase().as_str() {
|
||||
"STARTFONT" => {
|
||||
if self.parsed_font.start_font.is_some() {
|
||||
return Err(ParseError::MultipleStartFont)
|
||||
}
|
||||
self.parsed_font.start_font = match keyword.1.parse::<f32>() {
|
||||
Ok(val) => Some(val),
|
||||
Err(_) => return Err(ParseError::BDFVersionInvalid)
|
||||
}
|
||||
},
|
||||
"COMMENT" => {
|
||||
|
||||
},
|
||||
"CONTENTVERSION" => {
|
||||
if self.parsed_font.content_version.is_some() {
|
||||
return Err(ParseError::MultipleContentVersion)
|
||||
}
|
||||
self.parsed_font.content_version = match keyword.1.parse::<i32>() {
|
||||
Ok(val) => Some(val),
|
||||
Err(_) => return Err(ParseError::ContentVersionInvalid)
|
||||
}
|
||||
},
|
||||
"FONT" => {
|
||||
if self.parsed_font.font.is_some() {
|
||||
return Err(ParseError::MultipleFont)
|
||||
}
|
||||
self.parsed_font.font = Some(keyword.1.to_string());
|
||||
},
|
||||
"SIZE" => {
|
||||
let mut elements = keyword.1.split_ascii_whitespace();
|
||||
|
||||
let point_size = elements.next().ok_or(ParseError::SizeInvalid)?.parse::<i32>().map_err(|_| ParseError::SizeInvalid)?;
|
||||
let x_res = elements.next().ok_or(ParseError::SizeInvalid)?.parse::<i32>().map_err(|_| ParseError::SizeInvalid)?;
|
||||
let y_res = elements.next().ok_or(ParseError::SizeInvalid)?.parse::<i32>().map_err(|_| ParseError::SizeInvalid)?;
|
||||
|
||||
let size = crate::Size{
|
||||
point_size,
|
||||
resolution: crate::Point {
|
||||
x: x_res,
|
||||
y: y_res
|
||||
}
|
||||
};
|
||||
|
||||
self.parsed_font.size = Some(size);
|
||||
},
|
||||
"FONTBOUNDINGBOX" => {
|
||||
let mut elements = keyword.1.split_ascii_whitespace();
|
||||
|
||||
let x_size = elements.next().ok_or(ParseError::SizeInvalid)?.parse::<i32>().map_err(|_| ParseError::SizeInvalid)?;
|
||||
let y_size = elements.next().ok_or(ParseError::SizeInvalid)?.parse::<i32>().map_err(|_| ParseError::SizeInvalid)?;
|
||||
let x_offset = elements.next().ok_or(ParseError::SizeInvalid)?.parse::<i32>().map_err(|_| ParseError::SizeInvalid)?;
|
||||
let y_offset = elements.next().ok_or(ParseError::SizeInvalid)?.parse::<i32>().map_err(|_| ParseError::SizeInvalid)?;
|
||||
|
||||
let bounding_box = crate::BoundBox{
|
||||
size: crate::Point {
|
||||
x: x_size,
|
||||
y: y_size,
|
||||
},
|
||||
offset: crate::Point {
|
||||
x: x_offset,
|
||||
y: y_offset,
|
||||
}
|
||||
};
|
||||
|
||||
self.parsed_font.font_bounding_box = Some(bounding_box);
|
||||
},
|
||||
"METRICSSET" => {
|
||||
self.parsed_font.metrics_set = Some(keyword.1.parse::<i32>().map_err(|_| ParseError::MetricsSetInvalid)?);
|
||||
},
|
||||
"SWIDTH" => {
|
||||
let mut elements = keyword.1.split_ascii_whitespace();
|
||||
|
||||
let x_res = elements.next().ok_or(ParseError::SWidthInvalid)?.parse::<i32>().map_err(|_| ParseError::SWidthInvalid)?;
|
||||
let y_res = elements.next().ok_or(ParseError::SWidthInvalid)?.parse::<i32>().map_err(|_| ParseError::SWidthInvalid)?;
|
||||
|
||||
let swidth = crate::Point {
|
||||
x: x_res,
|
||||
y: y_res
|
||||
};
|
||||
|
||||
self.parsed_font.scalable_width = Some(swidth);
|
||||
},
|
||||
"DWIDTH" => {
|
||||
let mut elements = keyword.1.split_ascii_whitespace();
|
||||
|
||||
let x_res = elements.next().ok_or(ParseError::DWidthInvalid)?.parse::<i32>().map_err(|_| ParseError::DWidthInvalid)?;
|
||||
let y_res = elements.next().ok_or(ParseError::DWidthInvalid)?.parse::<i32>().map_err(|_| ParseError::DWidthInvalid)?;
|
||||
|
||||
let dwidth = crate::Point {
|
||||
x: x_res,
|
||||
y: y_res
|
||||
};
|
||||
|
||||
self.parsed_font.device_width = Some(dwidth);
|
||||
},
|
||||
"SWIDTH1" => {
|
||||
let mut elements = keyword.1.split_ascii_whitespace();
|
||||
|
||||
let x_res = elements.next().ok_or(ParseError::SWidth1Invalid)?.parse::<i32>().map_err(|_| ParseError::SWidth1Invalid)?;
|
||||
let y_res = elements.next().ok_or(ParseError::SWidth1Invalid)?.parse::<i32>().map_err(|_| ParseError::SWidth1Invalid)?;
|
||||
|
||||
let swidth = crate::Point {
|
||||
x: x_res,
|
||||
y: y_res
|
||||
};
|
||||
|
||||
self.parsed_font.scalable_width = Some(swidth);
|
||||
},
|
||||
"DWIDTH1" => {
|
||||
let mut elements = keyword.1.split_ascii_whitespace();
|
||||
|
||||
let x_res = elements.next().ok_or(ParseError::DWidth1Invalid)?.parse::<i32>().map_err(|_| ParseError::DWidth1Invalid)?;
|
||||
let y_res = elements.next().ok_or(ParseError::DWidth1Invalid)?.parse::<i32>().map_err(|_| ParseError::DWidth1Invalid)?;
|
||||
|
||||
let dwidth = crate::Point {
|
||||
x: x_res,
|
||||
y: y_res
|
||||
};
|
||||
|
||||
self.parsed_font.device_width = Some(dwidth);
|
||||
},
|
||||
"VVECTOR" => {
|
||||
let mut elements = keyword.1.split_ascii_whitespace();
|
||||
|
||||
let x_res = elements.next().ok_or(ParseError::VVEctorInvalid)?.parse::<i32>().map_err(|_| ParseError::VVEctorInvalid)?;
|
||||
let y_res = elements.next().ok_or(ParseError::VVEctorInvalid)?.parse::<i32>().map_err(|_| ParseError::VVEctorInvalid)?;
|
||||
|
||||
let vv = crate::Point {
|
||||
x: x_res,
|
||||
y: y_res
|
||||
};
|
||||
|
||||
self.parsed_font.device_width = Some(vv);
|
||||
},
|
||||
"STARTPROPERTIES" => {
|
||||
self.state = ParserState::Properties
|
||||
},
|
||||
"CHARS" => {
|
||||
self.state = ParserState::Glyph;
|
||||
let chars = keyword.1.parse::<u32>().map_err(|_| ParseError::CharsInvalid)?;
|
||||
self.parsed_font.chars = Some(chars);
|
||||
},
|
||||
_ => {
|
||||
return Err(ParseError::InvalidKeyword)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ParserState::Properties => {
|
||||
if keyword.0.to_ascii_uppercase().as_str() == "ENDPROPERTIES" {
|
||||
self.state = ParserState::Font;
|
||||
} else {
|
||||
let property = match keyword.1.parse::<i32>() {
|
||||
Ok(val) => Property::Integer(val),
|
||||
Err(_) => Property::Text(keyword.1.to_owned()),
|
||||
};
|
||||
|
||||
self.parsed_font.properties.properties.insert(keyword.0.to_string(), property);
|
||||
}
|
||||
},
|
||||
|
||||
ParserState::Glyph => {
|
||||
if keyword.0.to_ascii_uppercase().as_str() == "ENDCHAR" {
|
||||
self.state = ParserState::Font;
|
||||
|
||||
} else {
|
||||
todo!("Parse Glyph Contents")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
todo!("Parse font to output")
|
||||
}
|
||||
}
|
||||
|
||||
enum ParserState {
|
||||
Font,
|
||||
Properties,
|
||||
Glyph,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ParseError {
|
||||
InvalidKeyword,
|
||||
BDFVersionInvalid,
|
||||
ContentVersionInvalid,
|
||||
SizeInvalid,
|
||||
MetricsSetInvalid,
|
||||
SWidthInvalid,
|
||||
DWidthInvalid,
|
||||
SWidth1Invalid,
|
||||
DWidth1Invalid,
|
||||
VVEctorInvalid,
|
||||
CharsInvalid,
|
||||
|
||||
MultipleStartFont,
|
||||
MultipleContentVersion,
|
||||
MultipleFont,
|
||||
|
||||
}
|
||||
|
||||
27
src/properties.rs
Normal file
27
src/properties.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct Properties {
|
||||
pub(crate) properties: HashMap<String, Property>
|
||||
}
|
||||
|
||||
impl Properties {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
properties: HashMap::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Property {
|
||||
Integer(i32),
|
||||
Text(String),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Property {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Integer(i) => write!(f, "{}", i),
|
||||
Self::Text(t) => write!(f, "{}", t),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user