blob: 7f58baf74660b3e2574a90dc85fd45d1b649f5e7 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#![deny(missing_docs)]
//! Utility methods and traits used throughout assembly.
mod insert_unique;
mod path_to_string;
mod paths;
pub use insert_unique::{DuplicateKeyError, InsertAllUniqueExt, InsertUniqueExt, MapEntry};
pub use path_to_string::PathToStringExt;
pub use paths::{
normalize_path, path_relative_from, path_relative_from_file, resolve_path,
resolve_path_from_file, PathTypeMarker, TypedPathBuf,
};
use anyhow::{Context as _, Result};
use std::io::Read;
/// Deserialize an instance of type T from an IO stream of JSON5.
pub fn from_reader<R, T>(reader: &mut R) -> Result<T>
where
R: Read,
T: serde::de::DeserializeOwned,
{
let mut data = String::default();
reader.read_to_string(&mut data).context("Cannot read the config")?;
serde_json5::from_str(&data).context("Cannot parse the config")
}
/// Helper fn to insert into an empty Option, or return an Error.
pub fn set_option_once_or<T, E>(
opt: &mut Option<T>,
value: impl Into<Option<T>>,
e: E,
) -> Result<(), E> {
let value = value.into();
if value.is_none() {
Ok(())
} else {
if opt.is_some() {
Err(e)
} else {
*opt = value;
Ok(())
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use anyhow::anyhow;
use serde::Deserialize;
use std::io::Cursor;
#[derive(Debug, Deserialize, PartialEq)]
struct MyStruct {
key1: String,
}
#[test]
fn test_set_option_once() {
let mut opt = None;
// should be able to set None on None.
assert!(
set_option_once_or(&mut opt, None, anyhow!("an error")).is_ok(),
"Setting None on None failed"
);
// should be able to set Value on None.
assert!(
set_option_once_or(&mut opt, Some("some value"), anyhow!("an error")).is_ok(),
"initial set value failed"
);
assert_eq!(opt, Some("some value"));
// setting None on Some should be a no-op.
assert!(
set_option_once_or(&mut opt, None, anyhow!("an error")).is_ok(),
"Setting None on Some failed"
);
assert_eq!(opt, Some("some value"), "Setting None on Some was not a no-op");
// setting Some on Some should fail.
assert!(
set_option_once_or(&mut opt, "other value", anyhow!("an error")).is_err(),
"Setting Some on Some did not fail"
);
assert_eq!(
opt,
Some("some value"),
"Setting Some(other) on Some(value) changed the value with an error"
);
}
#[test]
fn reader_valid_json5() {
let json5: String = r#"{key1: "value1",}"#.to_string();
let mut cursor = Cursor::new(json5);
let value: MyStruct = from_reader(&mut cursor).unwrap();
assert_eq!(value.key1, "value1");
}
#[test]
fn reader_invalid_json5() {
#[derive(Deserialize)]
#[serde(deny_unknown_fields)]
struct MyStruct {}
let json5: String = r#"{key1: "value1",}"#.to_string();
let mut cursor = Cursor::new(json5);
let value: Result<MyStruct> = from_reader(&mut cursor);
assert!(value.is_err());
}
}