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

Code before:
}

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 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))
}

Review comment (suggestion):
I think you can do a `HashSet::from_iter` here! It should be something like:

```rust
HashSet::<char>::from_iter(alphabet.chars())
```

I wonder if it's worth returning an error when we know we'll get the repeated characters (I think ya'll talked about this as well, so I'm definitely fine either way)

Code after:

fn kebabcase(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
  Ok(s.to_kebab_case())
}

fn lowercamelcase(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
  Ok(s.to_lower_camel_case())
}

fn lowercase(_evaluator: &Evaluator, s: &str) -> Result<String, String> {
  Ok(s.to_lowercase())
}

fn num_cpus(_evaluator: &Evaluator) -> Result<String, String> {
  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))
}