clippet/lib.rs
1//! Provides a teeny way to have some nice byte structures that's easy to use.
2//! It's all provided in one structure and many function implementation.
3use bytes::BytesMut;
4use std::io::BufReader;
5use std::io::prelude::*;
6use std::fs::File;
7
8/// A structure for containing chunks of data and information about it.
9/// The label field is useful for storing things like MIME types.
10/// The size field is automatically increased when you append to the data field.
11#[derive(Debug)]
12pub struct Clippet {
13 label: String,
14 size: i32,
15 data: Vec<BytesMut>,
16}
17
18impl Clippet {
19 /// Returns the label field.
20 ///
21 /// ```no_run
22 /// let data = Clippet { label : "Hello!".to_string(), ... };
23 /// assert_eq!(data.get_label(), "Hello!")
24 /// ```
25 pub fn get_label(&self) -> String {
26 return self.label.to_string()
27 }
28 /// Changes the label field.
29 ///
30 /// ```no_run
31 /// let data = Clippet { ... };
32 /// assert_eq!(data.set_label("Hello!"), true);
33 /// ```
34 pub fn set_label(&mut self, label: &str) -> bool {
35 self.label = label.to_string();
36 if &self.label == label {
37 return true
38 } else {
39 return false
40 }
41 }
42 /// Appends a sequence of bytes to the Clippet structure.
43 /// Also increases the size field by one.
44 ///
45 /// ```no_run
46 /// let bytes = BytesMut::from("Hello, world!");
47 /// let mut data = Clippet { ... };
48 /// data.add_bytes(bytes);
49 /// ```
50 pub fn add_bytes(&mut self, bytes: BytesMut) {
51 self.data.push(bytes);
52 self.size = self.size + 1;
53 }
54 /// Removes a sequence of bytes from the Clippet structure.
55 /// Also decreases the size field by one.
56 ///
57 /// ```no_run
58 /// let mut data = Clippet { ... };
59 /// data.get_size() // e.g. 10
60 /// data.drop_bytes(5) // drops 6th sequence of bytes
61 /// data.get_size() // 9
62 /// ```
63 pub fn drop_bytes(&mut self, index: usize) {
64 self.data.remove(index);
65 self.size = self.size - 1;
66 }
67 /// Returns the size of the data field.
68 ///
69 /// ```no_run
70 /// let data = Clippet { ... };
71 /// assert_eq!(data.get_size(), 0);
72 /// ```
73 pub fn get_size(&self) -> i32 {
74 return self.size
75 }
76 /// Returns a sequence of bytes.
77 ///
78 /// ```no_run
79 /// let bytes = BytesMut::from("Hello, world!");
80 /// let mut data = Clippet { ... };
81 /// data.add_bytes(bytes);
82 /// assert_eq!(data.get_data(0), bytes);
83 /// ```
84 pub fn get_data(&self, index: usize) -> BytesMut {
85 return self.data[index].to_owned()
86 }
87 /// Takes an indexed byte sequence and returns it as a String.
88 /// ```no_run
89 /// let bytes = BytesMut::from("Hello, world!");
90 /// let mut data = Clippet { ... };
91 /// data.add_bytes(bytes);
92 /// assert_eq!(data.get_as_string(0), "Hello, world!");
93 /// ```
94 pub fn get_as_string(&self, index: usize) -> String {
95 let bytes = self.get_data(index);
96 let y = bytes.as_ref();
97 let x = String::from_utf8_lossy(y).to_string();
98 return x
99 }
100 /// Takes a filename and splits it into sequences of bytes within a Clippet.
101 /// It is recommended to use smaller byte sequences, however this is user-configurable.
102 ///
103 /// ```no_run
104 /// let data = Clippet::from_file("example.txt", 512);
105 /// ```
106 pub fn from_file(name: &str, size: usize) -> Clippet {
107 let mut i = false;
108 let mut data: Vec<BytesMut> = vec![];
109 let f = File::open(name).unwrap();
110 let mut reader = BufReader::with_capacity(size, f);
111 while !i {
112 let buffer = reader.fill_buf().unwrap();
113 let bytes = BytesMut::from(buffer);
114 data.push(bytes);
115 let length = buffer.len();
116 if length < size { i = true; }
117 reader.consume(length);
118 }
119 let clip = Clippet { label: "".to_string(), size: data.len() as i32, data: data };
120 return clip
121
122 }
123 /// Takes a sequence of bytes and wraps it around a Clippet structure.
124 ///
125 /// ```no_run
126 /// let data = Clippet::from_bytes(foo);
127 /// ```
128 pub fn from_bytes(bytes: BytesMut) -> Clippet {
129 let clip = Clippet { label: "".to_string(), size: 1, data: vec![bytes] };
130 return clip
131 }
132 /// Alias of `get_size(&self)`
133 pub fn len(&self) -> i32 {
134 return self.get_size()
135 }
136 /// Takes a string and splits it into sequences of bytes within a Clippet.
137 /// It is recommended to use smaller byte sequences, however this is user-configurable.
138 /// This uses a string reference.
139 ///
140 /// ```no_run
141 /// let data = Clippet::from_string("Lorem ipsum dolor amet...", 512);
142 /// ```
143 pub fn from_string(str: &str, size: usize) -> Clippet {
144 let mut i = false;
145 let mut data: Vec<BytesMut> = vec![];
146 let string = str.as_bytes();
147 let mut reader = BufReader::with_capacity(size, string);
148 while !i {
149 let buffer = reader.fill_buf().unwrap();
150 let bytes = BytesMut::from(buffer);
151 data.push(bytes);
152 let length = buffer.len();
153 if length < size { i = true; }
154 reader.consume(length);
155 }
156 let clip = Clippet { label: "".to_string(), size: data.len() as i32, data: data };
157 return clip
158
159 }
160 /// Consumes the Clippet, combines all of its byte sequences and outputs them as a String literal.
161 ///
162 /// ```no_run
163 /// let data = Clippet::from_string("Hello, World!", 512);
164 /// println!("{}", data.combine()); /// Hello, World!
165 /// ```
166 pub fn combine(self) -> String {
167 let mut string = "".to_string();
168 for v in self.data {
169 let y = v.as_ref();
170 let x = String::from_utf8_lossy(y).to_string();
171 if string == "".to_string() {
172 string = x;
173 } else {
174 string = format!("{}{}", string, x);
175 }
176 }
177 return string
178 }
179 /// Replaces the Clippet with one that has all of its data in one chunk.
180 /// The label is retained, the data is not modified apart from being dechunked.
181 ///
182 /// ```no_run
183 /// let data = Clippet::from_string("HelloWorld", 5); // [b"Hello", b"World"]
184 /// let data = data.dechunk(); // [b"HelloWorld"]
185 /// ```
186 pub fn dechunk(self) -> Clippet {
187 // Retain label.
188 let label = self.label.to_string();
189 let data = self.combine();
190 let clip = Clippet { label: label, size: 1, data: vec![BytesMut::from(data.as_str())] };
191 return clip
192 }
193 /// Combines the Clippet and then remakes it, retaining the label, with the specified max chunk size.
194 /// No data is modified.
195 ///
196 /// ```no_run
197 /// let longstring = "long string bla bla bla..."; // Pretend this is 2KB large!
198 /// let data = Clippet::from_string(longstring, 512); // size: 4
199 /// let data = data.rechunk(1024) // size: 2
200 /// ```
201 pub fn rechunk(self, size: usize) -> Clippet {
202 let label = self.label.to_string();
203 let data = self.combine();
204 let mut clip = Clippet::from_string(&data, size);
205 if label != "".to_string() { clip.label = label; }
206 return clip
207 }
208}