common: Add the buffer module.
[gps-watch.git] / src / common / buffer.rs
1 /*
2  * Copyright (c) 2017-2019 Tilman Sauerbeck (tilman at code-monkey de)
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23
24 use core::ptr;
25
26 pub enum BufferUserData {
27 }
28
29 #[repr(C)]
30 pub struct Buffer {
31     buf: *mut u8,
32     callback: extern fn(*mut BufferUserData, *const u8, usize, usize) -> isize,
33     user_data: *mut BufferUserData,
34     allocated: usize,
35     length: usize,
36 }
37
38 extern fn dummy_callback(_: *mut BufferUserData, _: *const u8, _: usize, _: usize) -> isize {
39     -1
40 }
41
42 #[no_mangle]
43 pub unsafe extern fn buffer_init(_buffer: *mut Buffer, buf: *mut u8, bufsiz: usize, callback: extern fn(*mut BufferUserData, *const u8, usize, usize) -> isize, user_data: *mut BufferUserData) {
44     let buffer = &mut *_buffer;
45
46     buffer.buf = buf;
47     buffer.allocated = bufsiz;
48     buffer.callback = callback;
49     buffer.user_data = user_data;
50     buffer.length = 0;
51 }
52
53 unsafe fn buffer_consume(buffer: &mut Buffer, length: usize) {
54     buffer.length -= length;
55
56     ptr::copy(buffer.buf.offset(length as isize), buffer.buf, buffer.length);
57 }
58
59 #[no_mangle]
60 pub unsafe extern fn buffer_flush(_buffer: *mut Buffer) -> i32 {
61     let buffer = &mut *_buffer;
62
63     while buffer.length > 0 {
64         let nwritten = (buffer.callback)(buffer.user_data, buffer.buf, buffer.allocated, buffer.length);
65
66         if nwritten == -1 {
67             return -1;
68         }
69
70         buffer_consume(buffer, nwritten as usize);
71     }
72
73     0
74 }
75
76 fn min(a: usize, b: usize) -> usize {
77     if a < b {
78         a
79     } else {
80         b
81     }
82 }
83
84 #[no_mangle]
85 pub unsafe extern fn buffer_write(_buffer: *mut Buffer, src: *const u8, srcsiz: usize) -> isize {
86     let buffer = &mut *_buffer;
87
88     if buffer.allocated == buffer.length {
89         if buffer_flush(_buffer) < 0 {
90             return -1;
91         }
92     }
93
94     let nwrite = min(buffer.allocated - buffer.length, srcsiz);
95
96     ptr::copy_nonoverlapping(src, buffer.buf.offset(buffer.length as isize), nwrite);
97
98     buffer.length += nwrite;
99
100     nwrite as isize
101 }
102
103 #[no_mangle]
104 pub unsafe extern fn buffer_write_all(_buffer: *mut Buffer, src: *const u8, srcsiz: usize) -> isize {
105     let mut offset = 0;
106     let mut left = srcsiz;
107
108     while left > 0 {
109         let data = src.offset(offset);
110         let nwritten = buffer_write(_buffer, data, left);
111
112         if nwritten < 0 {
113             return -1;
114         }
115
116         left -= nwritten as usize;
117         offset += nwritten;
118     }
119
120     0
121 }
122
123 impl Buffer {
124     // Allocates and initializes a buffer.
125     pub fn new(buf: *mut u8, bufsiz: usize, callback: extern fn(*mut BufferUserData, *const u8, usize, usize) -> isize, user_data: *mut BufferUserData) -> Buffer {
126         Buffer {
127             buf: buf,
128             callback: callback,
129             user_data: user_data,
130             allocated: bufsiz,
131             length: 0,
132         }
133     }
134
135     // Allocates a buffer, but does not initialize it.
136     // The buffer won't be usable until the init() function is called on it.
137     pub fn alloc() -> Buffer {
138         Buffer {
139             buf: 0 as *mut u8,
140             callback: dummy_callback,
141             user_data: 0 as *mut BufferUserData,
142             allocated: 0,
143             length: 0,
144         }
145     }
146
147     pub fn init(&mut self, buf: *mut u8, bufsiz: usize, callback: extern fn(*mut BufferUserData, *const u8, usize, usize) -> isize, user_data: *mut BufferUserData) {
148         unsafe {
149             buffer_init(self, buf, bufsiz, callback, user_data);
150         }
151     }
152
153     pub fn write(&mut self, data: &[u8]) {
154         unsafe {
155             buffer_write_all(self, data.as_ptr(), data.len());
156         }
157     }
158
159     pub fn flush(&mut self) -> i32 {
160         unsafe {
161             buffer_flush(self)
162         }
163     }
164
165     pub fn len(&self) -> usize {
166         self.length
167     }
168 }