Repository: casey/just
File: src/function.rs (Rust)

Code before:
      .join(path)
      .exists()
      .to_string(),
  )
}

fn pick(_evaluator: &Evaluator, count: &str, alphabet: Option<&str>) -> Result<String, String> {
  let alphabet = alphabet.unwrap_or("0123456789abcdef");
  if alphabet.is_empty() {
    return Err(String::from("no characters in alphabet"));
  }
  let mut alphabet_unique = HashSet::<char>::with_capacity(alphabet.len());
  for c in alphabet.chars() {
    if !alphabet_unique.insert(c) {
      return Err(format!("alphabet contains repeated character {c}"));
    }
  }
  let alphabet = alphabet_unique.drain().collect::<Vec<char>>();
  let len: usize = match count.parse::<usize>() {
    Ok(l) => l,
    _ => return Err(format!("Could not parse `{count}` as a positive integer")),
  };
  let mut rng = thread_rng();
  let mut r = String::with_capacity(len);
  while r.len() < len {
    r.push(*alphabet.choose(&mut rng).unwrap());
  }
  Ok(r)
}

fn quote(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
  Ok(format!("'{}'", s.replace('\'', "'\\''")))
}

fn replace(_evaluator: &Evaluator, s: &str, from: &str, to: &str) -> Result<String, String> {
  Ok(s.replace(from, to))
}

fn replace_regex(
  _evaluator: &Evaluator,
  s: &str,
  regex: &str,
  replacement: &str,
) -> Result<String, String> {
  Ok(
    Regex::new(regex)
      .map_err(|err| err.to_string())?
      .replace_all(s, replacement)
      .to_string(),
  )
}

Review comment (suggestion):
NIT: you might want to consider checking out the `IteratorRandom` trait in `rand::seq`, I think it might have an example that could make this more concise:

https://docs.rs/rand/latest/rand/seq/trait.IteratorRandom.html#method.choose_multiple_fill

or

https://docs.rs/rand/latest/rand/seq/trait.SliceRandom.html#tymethod.choose_multiple

Fortunately/unfortunately part of Rust is defininely digging in docs (glad they're there!) and finding the 👨‍🍳 💋 APIs to use -- there usually is a nice one for most things people want to do (in well written crates).



Code after:
  let num = num_cpus::get();
  Ok(num.to_string())
}

fn os(_evaluator: &Evaluator) -> Result<String, String> {
  Ok(target::os().to_owned())
}

fn os_family(_evaluator: &Evaluator) -> Result<String, String> {
  Ok(target::family().to_owned())
}

fn parent_directory(_evaluator: &Evaluator, path: &str) -> Result<String, String> {
  Utf8Path::new(path)
    .parent()
    .map(Utf8Path::to_string)
    .ok_or_else(|| format!("Could not extract parent directory from `{path}`"))
}

fn path_exists(evaluator: &Evaluator, path: &str) -> Result<String, String> {
  Ok(
    evaluator
      .search
      .working_directory
      .join(path)
      .exists()
      .to_string(),
  )
}

fn quote(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
  Ok(format!("'{}'", s.replace('\'', "'\\''")))
}

fn replace(_evaluator: &Evaluator, s: &str, from: &str, to: &str) -> Result<String, String> {
  Ok(s.replace(from, to))
}

fn replace_regex(
  _evaluator: &Evaluator,
  s: &str,
  regex: &str,
  replacement: &str,
) -> Result<String, String> {
  Ok(
    Regex::new(regex)
      .map_err(|err| err.to_string())?
      .replace_all(s, replacement)
      .to_string(),
  )
}