X-Git-Url: http://git.code-monkey.de/?a=blobdiff_plain;f=src%2Fcommon%2Fbuffer.rs;fp=src%2Fcommon%2Fbuffer.rs;h=deb8ef7e129e15c417bcfbac77255d1a93eef230;hb=1989d593a5511a6a766d432c48f79412416b3700;hp=0000000000000000000000000000000000000000;hpb=2cd9f6b175d16cb0a5c8bb7f3e387fecd27a7199;p=gps-watch.git diff --git a/src/common/buffer.rs b/src/common/buffer.rs new file mode 100644 index 0000000..deb8ef7 --- /dev/null +++ b/src/common/buffer.rs @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2017-2019 Tilman Sauerbeck (tilman at code-monkey de) + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +use core::ptr; + +pub enum BufferUserData { +} + +#[repr(C)] +pub struct Buffer { + buf: *mut u8, + callback: extern fn(*mut BufferUserData, *const u8, usize, usize) -> isize, + user_data: *mut BufferUserData, + allocated: usize, + length: usize, +} + +extern fn dummy_callback(_: *mut BufferUserData, _: *const u8, _: usize, _: usize) -> isize { + -1 +} + +#[no_mangle] +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) { + let buffer = &mut *_buffer; + + buffer.buf = buf; + buffer.allocated = bufsiz; + buffer.callback = callback; + buffer.user_data = user_data; + buffer.length = 0; +} + +unsafe fn buffer_consume(buffer: &mut Buffer, length: usize) { + buffer.length -= length; + + ptr::copy(buffer.buf.offset(length as isize), buffer.buf, buffer.length); +} + +#[no_mangle] +pub unsafe extern fn buffer_flush(_buffer: *mut Buffer) -> i32 { + let buffer = &mut *_buffer; + + while buffer.length > 0 { + let nwritten = (buffer.callback)(buffer.user_data, buffer.buf, buffer.allocated, buffer.length); + + if nwritten == -1 { + return -1; + } + + buffer_consume(buffer, nwritten as usize); + } + + 0 +} + +fn min(a: usize, b: usize) -> usize { + if a < b { + a + } else { + b + } +} + +#[no_mangle] +pub unsafe extern fn buffer_write(_buffer: *mut Buffer, src: *const u8, srcsiz: usize) -> isize { + let buffer = &mut *_buffer; + + if buffer.allocated == buffer.length { + if buffer_flush(_buffer) < 0 { + return -1; + } + } + + let nwrite = min(buffer.allocated - buffer.length, srcsiz); + + ptr::copy_nonoverlapping(src, buffer.buf.offset(buffer.length as isize), nwrite); + + buffer.length += nwrite; + + nwrite as isize +} + +#[no_mangle] +pub unsafe extern fn buffer_write_all(_buffer: *mut Buffer, src: *const u8, srcsiz: usize) -> isize { + let mut offset = 0; + let mut left = srcsiz; + + while left > 0 { + let data = src.offset(offset); + let nwritten = buffer_write(_buffer, data, left); + + if nwritten < 0 { + return -1; + } + + left -= nwritten as usize; + offset += nwritten; + } + + 0 +} + +impl Buffer { + // Allocates and initializes a buffer. + pub fn new(buf: *mut u8, bufsiz: usize, callback: extern fn(*mut BufferUserData, *const u8, usize, usize) -> isize, user_data: *mut BufferUserData) -> Buffer { + Buffer { + buf: buf, + callback: callback, + user_data: user_data, + allocated: bufsiz, + length: 0, + } + } + + // Allocates a buffer, but does not initialize it. + // The buffer won't be usable until the init() function is called on it. + pub fn alloc() -> Buffer { + Buffer { + buf: 0 as *mut u8, + callback: dummy_callback, + user_data: 0 as *mut BufferUserData, + allocated: 0, + length: 0, + } + } + + pub fn init(&mut self, buf: *mut u8, bufsiz: usize, callback: extern fn(*mut BufferUserData, *const u8, usize, usize) -> isize, user_data: *mut BufferUserData) { + unsafe { + buffer_init(self, buf, bufsiz, callback, user_data); + } + } + + pub fn write(&mut self, data: &[u8]) { + unsafe { + buffer_write_all(self, data.as_ptr(), data.len()); + } + } + + pub fn flush(&mut self) -> i32 { + unsafe { + buffer_flush(self) + } + } + + pub fn len(&self) -> usize { + self.length + } +}