Skip to content

Commit

Permalink
Get rid of itertools dependency.
Browse files Browse the repository at this point in the history
Also, write rust code to strings rather than byte vectors.
Source code should be utf-8.
  • Loading branch information
kaj committed Feb 6, 2025
1 parent 911c601 commit 4682cb4
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 128 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ project adheres to
## Unreleased

* Updated `nom` to 8.0.0, and added `nom-language`.
* Removed `itertools` depenendency.
* MSRV is now 1.65.0, as required by `nom` 8.0.


Expand Down
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ tide013 = ["http-types"]
[dependencies]
base64 = "0.22.1"
bytecount = "0.6.0"
itertools = "0.14.0"
md5 = "0.7"
nom = "8.0.0"
nom-language = "0.1.0"
Expand Down
80 changes: 41 additions & 39 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ mod templateexpression;
use parseresult::show_errors;
use std::env;
use std::error::Error;
use std::fmt::{self, Debug, Display};
use std::fmt::{self, Debug, Display, Write as _};
use std::fs::{create_dir_all, read_dir, File};
use std::io::{self, Read, Write};
use std::io::{self, Read};
use std::path::{Path, PathBuf};
use template::template;

Expand Down Expand Up @@ -211,7 +211,7 @@ pub use staticfiles::StaticFiles;
///
/// [cargo]: https://doc.rust-lang.org/cargo/
pub struct Ructe {
f: Vec<u8>,
f: String,
outdir: PathBuf,
}

Expand Down Expand Up @@ -241,32 +241,32 @@ impl Ructe {
///
/// [cargo]: https://doc.rust-lang.org/cargo/
pub fn new(outdir: PathBuf) -> Result<Ructe> {
let mut f = Vec::with_capacity(512);
let mut f = String::with_capacity(512);
let outdir = outdir.join("templates");
create_dir_all(&outdir)?;
f.write_all(b"pub mod templates {\n")?;
f.write_str("pub mod templates {\n")?;
write_if_changed(
&outdir.join("_utils.rs"),
include_bytes!(concat!(
include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/src/templates/utils.rs"
)),
)?;
f.write_all(
b"#[doc(hidden)]\nmod _utils;\n\
#[doc(inline)]\npub use self::_utils::*;\n\n",
f.write_str(
"#[doc(hidden)]\nmod _utils;\n\
#[doc(inline)]\npub use self::_utils::*;\n\n",
)?;
if cfg!(feature = "warp03") {
write_if_changed(
&outdir.join("_utils_warp03.rs"),
include_bytes!(concat!(
include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/src/templates/utils_warp03.rs"
)),
)?;
f.write_all(
b"#[doc(hidden)]\nmod _utils_warp03;\n\
#[doc(inline)]\npub use self::_utils_warp03::*;\n\n",
f.write_str(
"#[doc(hidden)]\nmod _utils_warp03;\n\
#[doc(inline)]\npub use self::_utils_warp03::*;\n\n",
)?;
}
Ok(Ructe { f, outdir })
Expand Down Expand Up @@ -320,7 +320,7 @@ impl Ructe {
///
/// [`StaticFile`]: templates::StaticFile
pub fn statics(&mut self) -> Result<StaticFiles> {
self.f.write_all(b"pub mod statics;")?;
self.f.write_str("pub mod statics;")?;
StaticFiles::for_template_dir(
&self.outdir,
&PathBuf::from(get_env("CARGO_MANIFEST_DIR")?),
Expand All @@ -330,27 +330,24 @@ impl Ructe {

impl Drop for Ructe {
fn drop(&mut self) {
let _ = self.f.write_all(b"}\n");
let _ = self.f.write_str("}\n");
let _ =
write_if_changed(&self.outdir.join("../templates.rs"), &self.f);
}
}

fn write_if_changed(path: &Path, content: &[u8]) -> io::Result<()> {
use std::fs::{read, write};
if let Ok(old) = read(path) {
fn write_if_changed(path: &Path, content: &str) -> Result<()> {
use std::fs::{read_to_string, write};
if let Ok(old) = read_to_string(path) {
if old == content {
return Ok(());
}
}
write(path, content)
write(path, content.as_bytes())?;
Ok(())
}

fn handle_entries(
f: &mut impl Write,
indir: &Path,
outdir: &Path,
) -> Result<()> {
fn handle_entries(f: &mut String, indir: &Path, outdir: &Path) -> Result<()> {
println!("cargo:rerun-if-changed={}", indir.display());
for entry in read_dir(indir)? {
let entry = entry?;
Expand All @@ -359,11 +356,11 @@ fn handle_entries(
if let Some(filename) = entry.file_name().to_str() {
let outdir = outdir.join(filename);
create_dir_all(&outdir)?;
let mut modrs = Vec::with_capacity(512);
modrs.write_all(
b"#[allow(clippy::useless_attribute, unused)]\n\
use super::{Html,ToHtml};\n",
)?;
let mut modrs = String::with_capacity(512);
modrs.push_str(
"#[allow(clippy::useless_attribute, unused)]\n\
use super::{Html,ToHtml};\n",
);
handle_entries(&mut modrs, &path, &outdir)?;
write_if_changed(&outdir.join("mod.rs"), &modrs)?;
writeln!(f, "pub mod {filename};\n")?;
Expand Down Expand Up @@ -391,17 +388,13 @@ fn handle_entries(
Ok(())
}

fn handle_template(
name: &str,
path: &Path,
outdir: &Path,
) -> io::Result<bool> {
fn handle_template(name: &str, path: &Path, outdir: &Path) -> Result<bool> {
let mut input = File::open(path)?;
let mut buf = Vec::new();
input.read_to_end(&mut buf)?;
match template(&buf) {
Ok((_, t)) => {
let mut data = Vec::new();
let mut data = String::new();
t.write_rust(&mut data, name)?;
write_if_changed(
&outdir.join(format!("template_{name}.rs")),
Expand Down Expand Up @@ -429,16 +422,19 @@ pub enum RucteError {
Io(io::Error),
/// Error resolving a given environment variable.
Env(String, env::VarError),
/// Error bundling a sass stylesheet as css.
/// A build-time formatting error in Ructe
Fmt(fmt::Error),
#[cfg(feature = "sass")]
/// Error bundling a sass stylesheet as css.
Sass(rsass::Error),
}

impl Error for RucteError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self {
RucteError::Io(e) => Some(e),
RucteError::Env(_, e) => Some(e),
Self::Io(e) => Some(e),
Self::Env(_, e) => Some(e),
Self::Fmt(e) => Some(e),
#[cfg(feature = "sass")]
RucteError::Sass(e) => Some(e),
}
Expand All @@ -455,6 +451,7 @@ impl Debug for RucteError {
match self {
RucteError::Io(err) => Display::fmt(err, out),
RucteError::Env(var, err) => write!(out, "{var:?}: {err}"),
Self::Fmt(err) => Display::fmt(err, out),
#[cfg(feature = "sass")]
RucteError::Sass(err) => Debug::fmt(err, out),
}
Expand All @@ -466,6 +463,11 @@ impl From<io::Error> for RucteError {
RucteError::Io(e)
}
}
impl From<fmt::Error> for RucteError {
fn from(value: fmt::Error) -> Self {
Self::Fmt(value)
}
}

#[cfg(feature = "sass")]
impl From<rsass::Error> for RucteError {
Expand All @@ -475,4 +477,4 @@ impl From<rsass::Error> for RucteError {
}

/// A result where the error type is a [`RucteError`].
pub type Result<T> = std::result::Result<T, RucteError>;
pub type Result<T, E = RucteError> = std::result::Result<T, E>;
51 changes: 27 additions & 24 deletions src/staticfiles.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use super::Result;
use itertools::Itertools;
use std::ascii::escape_default;
use std::collections::BTreeMap;
use std::fmt::{self, Display};
use std::fmt::{self, Display, Write};
use std::fs::{read_dir, File};
use std::io::{Read, Write};
use std::io::Read;
use std::path::{Path, PathBuf};

/// Handler for static files.
Expand Down Expand Up @@ -147,7 +146,7 @@ use std::path::{Path, PathBuf};
/// ```
pub struct StaticFiles {
/// Rust source file `statics.rs` beeing written.
src: Vec<u8>,
src: String,
/// Path for writing the file `statics.rs`.
src_path: PathBuf,
/// Base path for finding static files with relative paths
Expand All @@ -163,17 +162,17 @@ impl StaticFiles {
outdir: &Path,
base_path: &Path,
) -> Result<Self> {
let mut src = Vec::with_capacity(512);
let mut src = String::with_capacity(512);
if cfg!(feature = "mime03") {
src.write_all(b"use mime::Mime;\n\n")?;
src.write_str("use mime::Mime;\n\n")?;
}
if cfg!(feature = "tide013") {
src.write_all(b"use tide::http::mime::{self, Mime};\n\n")?;
src.write_str("use tide::http::mime::{self, Mime};\n\n")?;
} else if cfg!(feature = "http-types") {
src.write_all(b"use http_types::mime::{self, Mime};\n\n")?;
src.write_str("use http_types::mime::{self, Mime};\n\n")?;
}
src.write_all(
b"/// A static file has a name (so its url can be recognized) and the
src.write_str(
"/// A static file has a name (so its url can be recognized) and the
/// actual file contents.
///
/// The name includes a short (48 bits as 8 base64 characters) hash of
Expand All @@ -185,13 +184,13 @@ pub struct StaticFile {
pub name: &'static str,
")?;
if cfg!(feature = "mime03") {
src.write_all(b" pub mime: &'static Mime,\n")?;
src.write_str(" pub mime: &'static Mime,\n")?;
}
if cfg!(feature = "http-types") {
src.write_all(b" pub mime: &'static Mime,\n")?;
src.write_str(" pub mime: &'static Mime,\n")?;
}
src.write_all(
b"}
src.write_str(
"}
#[allow(dead_code)]
impl StaticFile {
/// Get a single `StaticFile` by name, if it exists.
Expand Down Expand Up @@ -520,17 +519,21 @@ impl Drop for StaticFiles {
/// Write the ending of the statics source code, declaring the
/// `STATICS` variable.
fn drop(&mut self) {
fn do_write(s: &mut StaticFiles) -> Result<()> {
write!(s.src, "\npub static STATICS: &[&StaticFile] = &[")?;
let mut q = s.names_r.values();
if let Some(a) = q.next() {
write!(s.src, "&{a}")?;
}
for a in q {
write!(s.src, ", &{a}")?;
}
writeln!(s.src, "];")?;
super::write_if_changed(&s.src_path, &s.src)?;
Ok(())
}
// Ignore a possible write failure, rather than a panic in drop.
let _ = writeln!(
self.src,
"\npub static STATICS: &[&StaticFile] \
= &[{}];",
self.names_r
.iter()
.map(|s| format!("&{}", s.1))
.format(", "),
);
let _ = super::write_if_changed(&self.src_path, &self.src);
let _ = do_write(self);
}
}

Expand Down
47 changes: 27 additions & 20 deletions src/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use crate::expression::{input_to_str, rust_name};
use crate::parseresult::PResult;
use crate::spacelike::spacelike;
use crate::templateexpression::{template_expression, TemplateExpression};
use itertools::Itertools;
use nom::branch::alt;
use nom::bytes::complete::is_not;
use nom::bytes::complete::tag;
Expand All @@ -12,7 +11,7 @@ use nom::error::context;
use nom::multi::{many0, many_till, separated_list0, separated_list1};
use nom::sequence::{delimited, preceded, terminated};
use nom::Parser as _;
use std::io::{self, Write};
use std::fmt::Write;

#[derive(Debug, PartialEq, Eq)]
pub struct Template {
Expand All @@ -27,9 +26,9 @@ impl Template {
&self,
out: &mut impl Write,
name: &str,
) -> io::Result<()> {
out.write_all(
b"use std::io::{self, Write};\n\
) -> std::fmt::Result {
out.write_str(
"use std::io::{self, Write};\n\
#[allow(clippy::useless_attribute, unused)]\n\
use super::{Html,ToHtml};\n",
)?;
Expand All @@ -40,24 +39,32 @@ impl Template {
out,
"\n\
#[allow(clippy::used_underscore_binding)]\n\
pub fn {name}<{ta}{ta_sep}W>(#[allow(unused_mut)] mut _ructe_out_: W{args}) -> io::Result<()>\n\
where W: Write {{\n\
{body}\
Ok(())\n\
}}",
pub fn {name}<{ta}{ta_sep}W>(\
\n #[allow(unused_mut)] mut _ructe_out_: W,",
name = name,
ta = self.type_args,
ta_sep = if self.type_args.is_empty() { "" } else { ", " },
args =
self.args.iter().format_with("", |arg, f| f(&format_args!(
", {}",
arg.replace(
" Content",
" impl FnOnce(&mut W) -> io::Result<()>"
)
))),
body = self.body.iter().map(|b| b.code()).format(""),
)
)?;
for arg in &self.args {
writeln!(
out,
" {},",
arg.replace(
" Content",
" impl FnOnce(&mut W) -> io::Result<()>"
)
)?;
}
writeln!(
out,
") -> io::Result<()>\n\
where W: Write {{",
)?;
for b in &self.body {
b.write_code(out)?;
}
writeln!(out, "Ok(())\n}}")?;
Ok(())
}
}

Expand Down
Loading

0 comments on commit 4682cb4

Please sign in to comment.