Skip to main content

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}