rs_blocks/blocks/
block.rs

1// Copyright ⓒ 2019-2021 Lewis Belcher
2// Licensed under the MIT license (see LICENSE or <http://opensource.org/licenses/MIT>).
3// All files in the project carrying such notice may not be copied, modified, or
4// distributed except according to those terms
5
6//! Base implementation and traits for all blocks.
7
8use anyhow::Context;
9use serde::{Deserialize, Serialize};
10use std::convert::TryFrom;
11use std::path::Path;
12
13/// The type sent by a block to the main thread.
14pub type Message = (String, String);
15
16#[derive(Serialize)]
17pub struct Block {
18	pub name: String,
19
20	#[serde(skip_serializing_if = "Option::is_none")]
21	pub background: Option<String>,
22	#[serde(skip_serializing_if = "Option::is_none")]
23	pub colour: Option<String>,
24	#[serde(skip_serializing_if = "Option::is_none")]
25	pub full_text: Option<String>,
26	#[serde(skip_serializing_if = "Option::is_none")]
27	pub markup: Option<String>,
28	#[serde(skip_serializing_if = "Option::is_none")]
29	pub separator: Option<bool>,
30	#[serde(skip_serializing_if = "Option::is_none")]
31	pub separator_block_width: Option<usize>,
32}
33
34impl Block {
35	pub fn new(name: String, pango: bool) -> Block {
36		Block {
37			name,
38			background: None,
39			colour: None,
40			full_text: None,
41			markup: if pango {
42				Some("pango".to_string())
43			} else {
44				None
45			},
46			separator: None,
47			separator_block_width: Some(18),
48		}
49	}
50
51	pub fn to_string(&self) -> String {
52		if let Ok(s) = serde_json::to_string(self) {
53			s
54		} else {
55			format!("Error in '{}'", self.name)
56		}
57	}
58}
59
60/// Configure trait for blocks.
61///
62/// Configuration is in toml format sent as a string so that each block
63/// sender can deserialise it in its own way.
64pub trait Configure {
65	fn new<'a>(config: &'a str) -> anyhow::Result<Self>
66	where
67		Self: Sized + Deserialize<'a>,
68	{
69		toml::from_str(config).context(format!("Invalid config block '{}'", config))
70	}
71
72	fn get_name(&self) -> String;
73}
74
75/// Sender trait for blocks.
76///
77/// A block must implement creating a closure which sends messages over a
78/// channel when new updates for publishing are ready.
79pub trait Sender: Configure {
80	fn add_sender(&self, channel: crossbeam_channel::Sender<Message>) -> anyhow::Result<()>;
81}
82
83#[derive(Deserialize)]
84#[serde(try_from = "String")]
85pub struct ValidatedPath(pub String);
86
87impl TryFrom<String> for ValidatedPath {
88	type Error = String;
89
90	fn try_from(value: String) -> Result<Self, Self::Error> {
91		if Path::new(&value).exists() {
92			Ok(ValidatedPath(value))
93		} else {
94			Err(format!("Path '{}' does not exist", value))
95		}
96	}
97}
98
99#[cfg(test)]
100mod test {
101	use super::*;
102
103	#[test]
104	fn create_json() {
105		Block::new("hi".to_string(), true).to_string();
106	}
107}