Skip to content

Commit

Permalink
Added first cut design of Intermediate Representation module
Browse files Browse the repository at this point in the history
  • Loading branch information
jhugman committed Oct 21, 2021
1 parent 73b922e commit d6d6d1d
Show file tree
Hide file tree
Showing 6 changed files with 246 additions and 1 deletion.
5 changes: 4 additions & 1 deletion components/support/nimbus-fml/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ license = "MPL-2.0"

[dependencies]
clap = "2.33"
anyhow = "1"
anyhow = "1.0.44"
serde_json = "1"
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0.29"
22 changes: 22 additions & 0 deletions components/support/nimbus-fml/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* */

//! Not complete yet
//! This is where the error definitions can go
//! TODO: Implement proper error handling, this would include defining the error enum,
//! impl std::error::Error using `thiserror` and ensuring all errors are handled appropriately
#[derive(Debug, thiserror::Error)]
pub enum FMLError {
#[error("IO error: {0}")]
IOError(#[from] std::io::Error),
#[error("JSON Error: {0}")]
JSONError(#[from] serde_json::Error),
#[error("Invalid path: {0}")]
InvalidPath(String),
#[error("Internal error: {0}")]
InternalError(&'static str),
}

pub type Result<T, E = FMLError> = std::result::Result<T, E>;
5 changes: 5 additions & 0 deletions components/support/nimbus-fml/src/fixtures.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

pub(crate) mod ir;
71 changes: 71 additions & 0 deletions components/support/nimbus-fml/src/fixtures/ir.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use crate::ir::{EnumDef, FeatureDef, FeatureManifest, PropDef, TypeRef, VariantDef};
use serde_json::json;

pub(crate) fn get_simple_nimbus_validation_feature() -> FeatureManifest {
FeatureManifest {
enum_defs: vec![],
obj_defs: vec![],
feature_defs: vec![FeatureDef::new(
"nimbus-validation",
"A simple validation feature",
vec![
PropDef {
name: "enabled".into(),
doc: "An example boolean property".into(),
typ: TypeRef::Boolean,
default: json!(true),
},
PropDef {
name: "row-count".into(),
doc: "An example integer property".into(),
typ: TypeRef::Boolean,
default: json!(2),
},
PropDef {
name: "deeplink".into(),
doc: "An example string property".into(),
typ: TypeRef::String,
default: json!("deeplink://settings"),
},
],
None,
)],
}
}

pub(crate) fn get_simple_homescreen_feature() -> FeatureManifest {
FeatureManifest {
enum_defs: vec![EnumDef {
name: "SectionId".into(),
doc: "The sections of the homescreen".into(),
variants: vec![
VariantDef::new("top-sites", "The original frecency sorted sites"),
VariantDef::new("jump-back-in", "Jump back in section"),
VariantDef::new("recently-saved", "Tabs that have been bookmarked recently"),
],
}],
obj_defs: vec![],
feature_defs: vec![FeatureDef::new(
"homescreen",
"Represents the homescreen feature",
vec![PropDef {
name: "sections-enabled".into(),
doc: "A map of booleans".into(),
typ: TypeRef::EnumMap(
Box::new(TypeRef::Enum("SectionId".into())),
Box::new(TypeRef::String),
),
default: json!({
"top-sites": true,
"jump-back-in": false,
"recently-saved": false,
}),
}],
None,
)],
}
}
138 changes: 138 additions & 0 deletions components/support/nimbus-fml/src/ir.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use serde::{Deserialize, Serialize};
use serde_json::Value;

/// The `TypeRef` enum defines a reference to a type.
///
/// Other types will be defined in terms of these enum values.
///
/// They represent the types available via the current `Variables` API—
/// some primitives and structural types— and can be represented by
/// Kotlin, Swift and JSON Schema.
///
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub(crate) enum TypeRef {
// Current primitives.
String,
Int,
Boolean,

// Strings can be coerced into a few types.
// The types here will require the app's bundle or context to look up the final value.
// They will likely have
BundleText(String),
BundleImage(String),

Enum(String),
// JSON objects can represent a data class.
Object(String),

// JSON objects can also represent a `Map<String, V>` or a `Map` with
// keys that can be derived from a string.
StringMap(Box<TypeRef>),
// We can coerce the String keys into Enums, so this repesents that.
EnumMap(Box<TypeRef>, Box<TypeRef>),

List(Box<TypeRef>),
Option(Box<TypeRef>),
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub(crate) struct FeatureManifest {
pub enum_defs: Vec<EnumDef>,
pub obj_defs: Vec<ObjectDef>,
pub feature_defs: Vec<FeatureDef>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub(crate) struct FeatureDef {
name: String,
doc: String,
props: Vec<PropDef>,
default: Option<Literal>,
}
impl FeatureDef {
pub fn new(name: &str, doc: &str, props: Vec<PropDef>, default: Option<Literal>) -> Self {
Self {
name: name.into(),
doc: doc.into(),
props,
default,
}
}
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub(crate) struct EnumDef {
pub name: String,
pub doc: String,
pub variants: Vec<VariantDef>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub(crate) struct FromStringDef {
pub name: String,
pub doc: String,
pub variants: Vec<VariantDef>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct VariantDef {
name: String,
doc: String,
}
impl VariantDef {
pub fn new(name: &str, doc: &str) -> Self {
Self {
name: name.into(),
doc: doc.into(),
}
}
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub(crate) struct ObjectDef {
name: String,
doc: String,
props: Vec<PropDef>,
}
impl ObjectDef {
pub fn new(name: &str, doc: &str, props: Vec<PropDef>) -> Self {
Self {
name: name.into(),
doc: doc.into(),
props,
}
}
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub(crate) struct PropDef {
pub name: String,
pub doc: String,
pub typ: TypeRef,
pub default: Literal,
}

type Literal = Value;

#[cfg(test)]
mod unit_tests {
use super::*;
use crate::error::Result;
use crate::fixtures::ir;

#[test]
fn can_ir_represent_smoke_test() -> Result<()> {
let m1 = ir::get_simple_homescreen_feature();
let string = serde_json::to_string(&m1)?;
let m2: FeatureManifest = serde_json::from_str(&string)?;

assert_eq!(m1, m2);

Ok(())
}
}
6 changes: 6 additions & 0 deletions components/support/nimbus-fml/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

pub mod error;
pub mod ir;
pub mod parser;

#[cfg(test)]
#[allow(dead_code)]
pub mod fixtures;

0 comments on commit d6d6d1d

Please sign in to comment.