source-text 0.1.0

Process &str from either a file or in-memory string w/ the source in help context.
Documentation

Enable API's that consume &str to retrieve the text string from any LoadSource source while tracking the origin.

Terminology

This crate uses some terminology to help in disambiguation:

  • "text" - an &str to be "processed" by application code; in contrast to &str used for other purposes such as naming the origin of a "text" or used in error messages.
  • "source" - a [Source] value which tracks both a text and the name of its origin.

Example: [Parsable]

Suppose we have a config file parser which parses a configuration into a Config struct. We want to be able to either parse strings in memory or load and parse config files from disk, with error messages indicating the source:

use indoc::indoc; // For cleanly formatting test assertions.
use source_text::Parsable;

#[derive(Debug)]
pub struct Config {
// ...
}

impl Parsable for Config {
fn parse_text(text: &str) -> anyhow::Result<Self> {
if text.is_empty() {
Err(anyhow::Error::msg("empty input\n"))
} else {
todo!("implement an `&str` parser...");
}
}
}

let err1 = Config::parse_source("").err().unwrap();

assert_eq!(
format!("{:?}", err1).trim_end(),
indoc! {
r#"
Error in <input>:

Caused by:
empty input
"#
}.trim_end()
);

let configpath = std::path::Path::new("/__this_path_should_not_exist__");
let err2 = Config::parse_source(configpath).err().unwrap();

assert_eq!(
format!("{:?}", err2).trim_end(),
indoc! { r#"
Error in "/__this_path_should_not_exist__":

Caused by:
No such file or directory (os error 2)
"# }.trim_end(),
);

Example: process_text

If [Parsable] does not fit your usage, you can wrap any fn(&str) -> anyhow::Result<T> with [process_text]:

use indoc::indoc; // For cleanly formatting test assertions.

fn count_lines<S>(source: S) -> anyhow::Result<usize>
where S: source_text::LoadSource,
{
source_text::process_text(source, |text: &str| {
Ok(text.lines().count())
})
}

fn main() {
let linecount = count_lines("Hello\nWorld!").unwrap();
assert_eq!(2, linecount);

let path = std::path::Path::new("/__this_path_should_not_exist__");
let err = count_lines(path).err().unwrap();

assert_eq!(
format!("{:?}", err).trim_end(),
indoc! { r#"
Error in "/__this_path_should_not_exist__":

Caused by:
No such file or directory (os error 2)
"# }.trim_end(),
);
}