Skip to content

Commit

Permalink
full config to runtime generation working.
Browse files Browse the repository at this point in the history
  • Loading branch information
gbin committed May 20, 2024
1 parent 287486f commit ea1b40b
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 37 deletions.
15 changes: 8 additions & 7 deletions copper/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
use std::collections::HashMap;
use std::iter::Map;
use std::path::Iter;

use petgraph::dot::Config as PetConfig;
use petgraph::dot::Dot;
use petgraph::graph::NodeIndex;
use petgraph::stable_graph::{NodeIndices, StableDiGraph};
use petgraph::stable_graph::StableDiGraph;
use ron::extensions::Extensions;
use ron::value::Value as RonValue;
use ron::Options;
use ron::value::Value as RonValue;
use serde::{Deserialize, Serialize};
use uom::si::rational::Time;
use uom::si::time::nanosecond;

pub type ConfigNodeId = u32;
pub type NodeConfig = HashMap<String, Value>;
pub type NodeInstanceConfig = HashMap<String, Value>;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Value(RonValue);
Expand Down Expand Up @@ -82,7 +79,7 @@ pub struct ConfigNode {
#[serde(skip_serializing_if = "Option::is_none")]
base_period_ns: Option<isize>,
#[serde(skip_serializing_if = "Option::is_none")]
instance_config: Option<NodeConfig>,
instance_config: Option<NodeInstanceConfig>,
}

impl ConfigNode {
Expand All @@ -105,6 +102,10 @@ impl ConfigNode {
self.type_name.as_ref().unwrap()
}

pub fn get_instance_config(&self) -> Option<&NodeInstanceConfig> {
self.instance_config.as_ref()
}

#[allow(dead_code)]
pub fn base_period(&self) -> Option<Time> {
self.base_period_ns
Expand Down
10 changes: 3 additions & 7 deletions copper/src/cutask.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
use serde::{Deserialize, Serialize};

use crate::config::NodeConfig;
use crate::config::NodeInstanceConfig;
use crate::CuResult;

// Everything that is stateful in copper for zero copy constraints need to be restricted to this trait.
pub trait CuMsg: Default + Serialize + for<'a> Deserialize<'a> + Sized {}

// Also anything that follows this contract can be a message
impl<T> CuMsg for T where T: Default + Serialize + for<'a> Deserialize<'a> + Sized {}

pub type CuError = String;

// Define your custom Result type alias
pub type CuResult<T> = std::result::Result<T, CuError>;

// Because of the Rust orphan rule, we need to define the common methods in a macro.
// This can be cleaned up with a proc macro or with a negative impl
// https://doc.rust-lang.org/beta/unstable-book/language-features/negative-impls.html when
// they are stabilized.
macro_rules! cu_task_common {
() => {
fn new(config: NodeConfig) -> CuResult<Self>
fn new(config: Option<&NodeInstanceConfig>) -> CuResult<Self>
where
Self: Sized;

Expand Down
4 changes: 4 additions & 0 deletions copper/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
pub mod config;
pub mod cutask;
pub mod serde;

// Copper common error type.
pub type CuError = String;
pub type CuResult<T> = std::result::Result<T, CuError>;
69 changes: 58 additions & 11 deletions copper_derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
extern crate proc_macro;

use copper::config::CopperConfig;
use format::{highlight_rust_code, rustfmt_generated_code};
use proc_macro::TokenStream;

use proc_macro2::Ident;
use quote::quote;
use syn::meta::parser;
use syn::punctuated::Punctuated;
use syn::Fields::{Named, Unit, Unnamed};
use syn::{
parse_macro_input, parse_quote, parse_str, Field, FieldMutability, ItemStruct, LitStr, Type,
TypeTuple,
Field, FieldMutability, ItemStruct, LitStr, parse_macro_input, parse_str, Type, TypeTuple,
};
use syn::Fields::{Named, Unit, Unnamed};
use syn::meta::parser;
use syn::punctuated::Punctuated;

use copper::config::CopperConfig;
use format::{highlight_rust_code, rustfmt_generated_code};

mod format;
mod utils;
Expand All @@ -36,20 +37,22 @@ pub fn copper_runtime(args: TokenStream, input: TokenStream) -> TokenStream {
.expect("Expected config file attribute like #[CopperRuntime(config = \"path\")]")
.value();
let mut config_full_path = utils::caller_crate_root();
config_full_path.push(config_file);
config_full_path.push(&config_file);
let config_content = std::fs::read_to_string(&config_full_path)
.unwrap_or_else(|_| panic!("Failed to read configuration file: {:?}", &config_full_path));

let copper_config = CopperConfig::deserialize(&config_content);
let all_node_configs = copper_config.get_all_nodes();

// Collect all the type names used by our configs.
let all_configs_type_names = all_node_configs
let all_configs_type_names: Vec<String> = all_node_configs
.iter()
.map(|node_config| node_config.get_type_name());
.map(|node_config| node_config.get_type_name().to_string())
.collect();

// Transform them as Rust types
let all_configs_types: Vec<Type> = all_configs_type_names
.iter()
.map(|name| {
println!("Found type: {}", name);
parse_str(name).unwrap()
Expand All @@ -59,7 +62,7 @@ pub fn copper_runtime(args: TokenStream, input: TokenStream) -> TokenStream {
// Build the tuple of all those types
let tuple_types = TypeTuple {
paren_token: Default::default(),
elems: Punctuated::from_iter(all_configs_types),
elems: Punctuated::from_iter(all_configs_types.clone()),
};

// add that to a new field
Expand All @@ -86,10 +89,54 @@ pub fn copper_runtime(args: TokenStream, input: TokenStream) -> TokenStream {
}
};

// Generate the code to create instances of the nodes
// It maps the types to their index
let node_instances_init_code: Vec<_> = all_configs_types
.iter()
.enumerate()
.map(|(index, ty)| {
let ty_name = &all_configs_type_names[index];
let error = format!(
"Failed to get create instance for {}, instance index {}.",
ty_name, index
);
quote! {
#ty::new(all_instances_configs[#index]).expect(#error)
}
})
.collect();

// Convert the modified struct back into a TokenStream
let result = quote! {
use copper::config::ConfigNode;
use copper::config::CopperConfig;
use copper::config::NodeInstanceConfig;
use copper::cutask::CuSrcTask; // Needed for the instantiation of tasks
use copper::cutask::CuTask; // Needed for the instantiation of tasks
use copper::cutask::CuSinkTask; // Needed for the instantiation of tasks
use copper::CuResult;
use std::fs::read_to_string;

pub #item_struct

impl #name {

pub fn new() -> CuResult<Self> {
let config_filename = #config_file;

let config_content = read_to_string(config_filename)
.unwrap_or_else(|_| panic!("Failed to read configuration file: {:?}", &config_filename));
let copper_config = CopperConfig::deserialize(&config_content);
let all_instances_configs: Vec<Option<&NodeInstanceConfig>> = copper_config.get_all_nodes().iter().map(|node_config| node_config.get_instance_config()).collect();

let node_instances = (
#(#node_instances_init_code),*
);
Ok(#name {
node_instances,
})
}

pub fn hello(&self) {
println!("Hello from CopperRuntime");
}
Expand Down
1 change: 1 addition & 0 deletions copper_derive_test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ edition = "2021"
copper-derive = { path = "../copper_derive" }
simplelogger = { path = "../examples/simplelogger" }
v4lsrc = { path = "../examples/v4lsrc" }
copper = { path = "../copper" }

[build-dependencies]
copper = { path = "../copper" }
Expand Down
2 changes: 1 addition & 1 deletion copper_derive_test/copperconfig.ron
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
type_name: "v4lsrc::Video4LinuxSource",
base_period_ns: 1000000000,
instance_config: {
"device": "/dev/video0",
"dev": "/dev/video0",
},
),
(
Expand Down
2 changes: 1 addition & 1 deletion copper_derive_test/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ use copper_derive::copper_runtime;
struct MyRuntime {}

fn main() {
let runtime = MyRuntime{node_instances: (1,2)};
let runtime = MyRuntime::new().expect("Failed to create runtime.");
runtime.hello();
}
11 changes: 6 additions & 5 deletions examples/simplelogger/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use std::fs::File;
use std::io::Write;

use serde::{Deserialize, Serialize};

use copper::config::NodeConfig;
use copper::cutask::{CuResult, CuSinkTask};
use copper::config::NodeInstanceConfig;
use copper::CuResult;
use copper::cutask::CuSinkTask;
use v4lsrc::ImageMsg;

pub struct SimpleLogger {
Expand All @@ -15,10 +14,12 @@ pub struct SimpleLogger {
impl CuSinkTask for SimpleLogger {
type Input = ImageMsg;

fn new(config: NodeConfig) -> CuResult<Self>
fn new(config: Option<&NodeInstanceConfig>) -> CuResult<Self>
where
Self: Sized,
{
let config = config
.ok_or_else(|| "SimpleLogger needs a config, None was passed as NodeInstanceConfig")?;
let path = (*config.get("path").unwrap()).clone().into();
Ok(SimpleLogger {
path,
Expand Down
19 changes: 14 additions & 5 deletions examples/v4lsrc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ use linux_video::{Device, Stream};
use linux_video::types::*;
use serde::{Deserialize, Serialize};

use copper::config::NodeConfig;
use copper::cutask::{CuResult, CuSrcTask};
use copper::config::NodeInstanceConfig;
use copper::CuResult;
use copper::cutask::CuSrcTask;
use copper::serde::arrays;

#[derive(Serialize, Deserialize)]
Expand Down Expand Up @@ -47,11 +48,19 @@ pub struct Video4LinuxSource {
impl CuSrcTask for Video4LinuxSource {
type Msg = ImageMsg;

fn new(config: NodeConfig) -> CuResult<Self>
fn new(config: Option<&NodeInstanceConfig>) -> CuResult<Self>
where
Self: Sized,
{
let dev: String = (*config.get("dev").unwrap()).clone().into();
let config = config.ok_or_else(|| {
"Video4LinuxSource needs a config, None was passed as NodeInstanceConfig"
})?;

let dev: String = (*config
.get("dev")
.expect("v4lsrc expects a dev config value pointing to the video device"))
.clone()
.into();
let device = Device::open(dev).unwrap();
Ok(Video4LinuxSource {
device,
Expand Down Expand Up @@ -94,7 +103,7 @@ mod tests {
#[test]
fn emulate_runtime() -> CuResult<()> {
println!("Build config");
let config = NodeConfig::default();
let config = NodeInstanceConfig::default();
println!("Build task");
let mut task = Video4LinuxSource::new(config)?;
println!("Build img");
Expand Down

0 comments on commit ea1b40b

Please sign in to comment.