kik_sync_service/lib.rs
1//! # kik_sync_service
2//!
3//! A synchronous work system for dealing with small inputs that lead to heavy workloads.
4//!
5//!
6//! ## Why Use This
7//!
8//! This "*Message* + *worker* thread" system was built for the following situations:
9//!
10//! - When there is a small sample of inputs that can generate a very large amount of data.
11//!
12//! - When a small input can generate a very heavy workload.
13//!
14//! - When there is no need to store the data generated in the memory.
15//!
16//! - When a system must process a stream of data and send it directly somewhere else.
17//!
18//! - I.E. sound processing, image processing, handling network requests, etc.
19//!
20//! - When generating individual frames for some GUI.
21//!
22//!
23//! The system consists of several *Worker*s and a single thread (*FeederRecycler*) sending and retrieving messages. If the (work time)/message is high enough,
24//! this single thread handling input/output might have enough time to store data in the memory without slowing down the workers.
25//! It's up to the creativity of each user.
26//!
27//! # Example
28//!
29//! This is huge because we need to first create a struct that implements *MessageData*, then another for *MessageInput*, then another for *Message*.
30//!
31//! But what kind of data and how it's worked is all up to the user. Just create the *DeliveryService* channel,
32//! use default values or a custom *ChannelConfig* argument. Then create a vector of the input data you need.
33//! Feed that data into the *DeliveryService* by calling "*feed_feeder*" method. As soon as data starts being fed *Worker*s will work.
34//! Finally start getting the results with a "for" call to a mutable reference of the channel.
35//! Repeat feed and iterate as many times as needed.
36//!
37//!
38//! use kik_sync_service::message::{Message, MessageData, MessageInput};
39//! use kik_sync_service::channel::{DeliveryService};
40//!
41//!
42//! // What type of data should be returned.
43//! pub struct MessageArray{
44//! data: [u32; 1024],
45//! }
46//!
47//! impl Clone for MessageArray{
48//! fn clone(&self) -> Self{
49//! let mut new_array: [u32; 1024] = [0; 1024];
50//! for i in 0..1024{
51//! new_array[i] = self.data[i];
52//! }
53//! MessageArray{
54//! data: new_array,
55//! }
56//! }
57//! }
58//!
59//! // with this trait it can be used as data for a Message.
60//! impl MessageData for MessageArray{
61//! fn new() -> Self{
62//! MessageArray{
63//! data: [0; 1024],
64//! }
65//! }
66//! }
67//!
68//! impl MessageArray{
69//! pub fn get(&mut self) -> &mut [u32; 1024]{
70//! &mut self.data
71//! }
72//! }
73//!
74//!
75//! // What kind of input it needs.
76//! pub struct Coordinates{
77//! pub x0: usize,
78//! pub y0: usize,
79//! pub x1: usize,
80//! pub y1: usize,
81//! }
82//!
83//! // Doesn't need to implement Copy, but needs Clone.
84//! impl Clone for Coordinates{
85//! fn clone(&self) -> Self{
86//! Coordinates{
87//! x0: self.x0,
88//! y0: self.y0,
89//! x1: self.x1,
90//! y1: self.y1,
91//! }
92//! }
93//! }
94//!
95//! // This implementation tells the compiler that this object can be
96//! // used as input for the worker threads, and it can only work with MessageArray.
97//! impl MessageInput<MessageArray> for Coordinates{
98//! fn new() -> Self{
99//! Coordinates{
100//! x0: 0,
101//! y0: 0,
102//! x1: 0,
103//! y1: 0,
104//! }
105//! }
106//! }
107//!
108//!
109//! // This is the message that holds both the data and input.
110//! // Feel free to add anything else you might need to work with it.
111//! pub struct ThreadMessage{
112//! pub array: MessageArray,
113//! pub current_input: Coordinates,
114//! }
115//!
116//! impl Clone for ThreadMessage{
117//! fn clone(&self) -> Self{
118//! ThreadMessage{
119//! array: self.array.clone(),
120//! current_input: self.current_input.clone(),
121//! }
122//! }
123//! }
124//!
125//! // ThreadMessage uses MessageArray as data,
126//! // ThreadMessage uses Coordinates as input to change the data.
127//! impl Message<MessageArray, Coordinates> for ThreadMessage {
128//!
129//! fn set_input(&mut self, message_input: Coordinates){
130//! self.current_input = message_input.clone();
131//! }
132//!
133//! fn work (&mut self){
134//! let (x0, y0, x1, y1) = (
135//! self.current_input.x0,
136//! self.current_input.y0,
137//! self.current_input.x1,
138//! self.current_input.y1,
139//! );
140//!
141//! let array = self.array.get();
142//! let mut counter: usize = 0;
143//!
144//! // Not very creative right now, each operation will count from 0 to 1024.
145//! // This is just to show that the results are being made and returned. I'll use it to generate fractals in the next project.
146//! // I'm thankful for anyone willing to offer a better example for this later.
147//! // Counting in the first line will go like 0 1 2 3 ... 30 31 1 2 3 ...
148//! // Counting in the second line will go like 32 33 34 35 ... 59 60 61 62 63 ...
149//! // And so forth until 1023 in the last line.
150//! for _y in (y0)..(y1){
151//! for _x in (x0)..(x1){
152//! let value = counter;
153//! array[counter] = value as u32;
154//!
155//! counter = counter + 1;
156//! }
157//! }
158//! }
159//!
160//! fn clone_message_data(&self) -> MessageArray{
161//! self.array.clone()
162//! }
163//!
164//! fn new() -> Self{
165//! let new_data = MessageArray::new();
166//! let new_input = Coordinates::new();
167//!
168//! ThreadMessage{
169//! current_input: new_input,
170//! array: new_data,
171//! }
172//! }
173//!
174//! }
175//!
176//! // Finally, Now that all the data structure is set, time to use the channel.
177//! #[test]
178//! fn test(){
179//! let width: usize = 1024;
180//! let height: usize = 768;
181//! let mut coordinates: Vec<Coordinates> = Vec::with_capacity((height as f32/32.0 * width as f32/32.0)as usize);
182//! assert_eq!(width % 32, 0);
183//! assert_eq!(height % 32, 0);
184//!
185//! // Creating a vec of coordinates to use as input.
186//! // for y in 0..24
187//! for y in 0..(((height as f32)/32.0) as usize){
188//! // for x in 0..32
189//! for x in 0..(((width as f32)/32.0) as usize){
190//! let (x0, y0) = (32 * x, 32 * y);
191//! coordinates.push(Coordinates{x0: x0, y0: y0, x1: x0 + 32, y1: y0 + 32});
192//! }
193//! }
194//! // Personal Note:
195//! // create a vec of inputs
196//! // create channel
197//! // send the vec of inputs
198//! // iterate through the channel
199//! // print the resulting values
200//!
201//! //data is MessageArray
202//! //input is Coordinates
203//! //message is ThreadMessage
204//!
205//! // Creating a channel that uses MessageArray as MessageData, Coordinates as MessageInput, ThreadMessage as Message. Default config values have been used.
206//! let mut kiki_channel: DeliveryService<MessageArray,Coordinates,ThreadMessage> = DeliveryService::default();
207//! kiki_channel.feed_feeder(&mut coordinates);
208//!
209//! let mut counter = 0;
210//! // Need to iterate through a mutable reference of kiki_channel to maintain ownership of it.
211//! for mut i in &mut kiki_channel{
212//! let mut highest: u32 = 0;
213//! let message_array = i.get();
214//! for j in message_array{
215//! if highest < *j {
216//! highest = *j;
217//! }
218//! }
219//! // All the highest values for each line will be 31, 63, n * 32 -1, ...
220//! assert_eq!(highest % 32, 31);
221//! println!("Total line {}: {}", counter, highest);
222//! counter += 1;
223//! }
224//!
225//! // Creating another vec to feed the structure again.
226//! // for y in 0..24
227//! for y in 0..(((height as f32)/32.0) as usize){
228//! // for x in 0..32
229//! for x in 0..(((width as f32)/32.0) as usize){
230//! let (x0, y0) = (32 * x, 32 * y);
231//! coordinates.push(Coordinates{x0: x0, y0: y0, x1: x0 + 32, y1: y0 + 32});
232//! }
233//! }
234//!
235//! // You can feed more input values after emptying the results from last run.
236//! kiki_channel.feed_feeder(&mut coordinates);
237//!
238//! let mut counter = 0;
239//! // The worker threads and feeder will only be closed when channel goes out of scope (unless they panic).
240//! // Need to iterate through a mutable reference of kiki_channel to maintain ownership of it.
241//! for mut i in &mut kiki_channel{
242//! let mut highest: u32 = 0;
243//! let message_array = i.get();
244//! for j in message_array{
245//! if highest < *j {
246//! highest = *j;
247//! }
248//! }
249//! // Used this when I was testing as fn main
250//! // if counter % 13 == 0{
251//! // println!("Total linha {}: {}", counter, total);
252//! // }
253//!
254//! // All the highest values for each line will be 31, 63, n * 32 -1, ...
255//! assert_eq!(highest % 32, 31);
256//! println!("Total line {}: {}", counter, highest);
257//! counter += 1;
258//! }
259//! }
260//!
261//!
262
263// This crate is a library
264#![crate_type = "lib"]
265// The library is named "kik_sync_service"
266#![crate_name = "kik_sync_service"]
267
268mod kik_message;
269mod kik_channel;
270mod kik_worker;
271mod kik_feeder;
272mod kik_message_example;
273
274/// Holds the traits used for message sharing and how to work them. They must be manually set by the user before using channel.
275pub mod message{
276 pub use crate::kik_message::{Message,MessageInput, MessageData};
277}
278
279/// DeliveryService is the channel used for the synchronous message-sharing and work. It can be created with DeliveryService::default values or be customized by using ChannelConfig as argument for DeliveryService::new.
280pub mod channel{
281 pub use crate::kik_channel::{ChannelConfig, DeliveryService};
282}