servicepoint-binding-c/src/brightness_grid.rs
2025-05-06 21:27:01 +02:00

195 lines
5.1 KiB
Rust

use crate::{
heap_drop, heap_move_nonnull, heap_move_ok, heap_move_some, heap_remove,
byte_slice::ByteSlice,
};
use servicepoint::{
Brightness, BrightnessGrid, BrightnessGridCommand, ByteGrid, DataRef, Grid,
Origin, Packet,
};
use std::mem::transmute;
use std::ptr::NonNull;
/// Creates a new [BrightnessGrid] with the specified dimensions.
///
/// returns: [BrightnessGrid] initialized to 0.
///
/// # Examples
/// ```C
/// UdpSocket *connection = sp_udp_open("127.0.0.1:2342");
/// if (connection == NULL)
/// return 1;
///
/// BrightnessGrid *grid = sp_brightness_grid_new(2, 2);
/// sp_brightness_grid_set(grid, 0, 0, 0);
/// sp_brightness_grid_set(grid, 1, 1, 10);
///
/// TypedCommand *command = sp_command_char_brightness(grid);
/// sp_udp_free(connection);
/// ```
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_new(
width: usize,
height: usize,
) -> NonNull<BrightnessGrid> {
heap_move_nonnull(BrightnessGrid::new(width, height))
}
/// Loads a [BrightnessGrid] with the specified dimensions from the provided data.
///
/// Any out of range values will be set to [Brightness::MAX] or [Brightness::MIN].
///
/// returns: new [BrightnessGrid] instance, or NULL in case of an error.
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_load(
width: usize,
height: usize,
data: ByteSlice,
) -> *mut BrightnessGrid {
let data = unsafe { data.as_slice() };
heap_move_some(
ByteGrid::load(width, height, data)
.map(move |grid| grid.map(Brightness::saturating_from)),
)
}
/// Clones a [BrightnessGrid].
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_clone(
brightness_grid: NonNull<BrightnessGrid>,
) -> NonNull<BrightnessGrid> {
heap_move_nonnull(unsafe { brightness_grid.as_ref().clone() })
}
/// Deallocates a [BrightnessGrid].
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_free(
brightness_grid: NonNull<BrightnessGrid>,
) {
unsafe { heap_drop(brightness_grid) }
}
/// Gets the current value at the specified position.
///
/// # Arguments
///
/// - `brightness_grid`: instance to read from
/// - `x` and `y`: position of the cell to read
///
/// returns: value at position
///
/// # Panics
/// - When accessing `x` or `y` out of bounds.
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_get(
brightness_grid: NonNull<BrightnessGrid>,
x: usize,
y: usize,
) -> Brightness {
unsafe { brightness_grid.as_ref().get(x, y) }
}
/// Sets the value of the specified position in the [BrightnessGrid].
///
/// # Arguments
///
/// - `brightness_grid`: instance to write to
/// - `x` and `y`: position of the cell
/// - `value`: the value to write to the cell
///
/// returns: old value of the cell
///
/// # Panics
///
/// - When accessing `x` or `y` out of bounds.
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_set(
brightness_grid: NonNull<BrightnessGrid>,
x: usize,
y: usize,
value: Brightness,
) {
unsafe { (*brightness_grid.as_ptr()).set(x, y, value) };
}
/// Sets the value of all cells in the [BrightnessGrid].
///
/// # Arguments
///
/// - `brightness_grid`: instance to write to
/// - `value`: the value to set all cells to
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_fill(
brightness_grid: NonNull<BrightnessGrid>,
value: Brightness,
) {
unsafe { (*brightness_grid.as_ptr()).fill(value) };
}
/// Gets the width of the [BrightnessGrid] instance.
///
/// # Arguments
///
/// - `brightness_grid`: instance to read from
///
/// returns: width
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_width(
brightness_grid: NonNull<BrightnessGrid>,
) -> usize {
unsafe { brightness_grid.as_ref().width() }
}
/// Gets the height of the [BrightnessGrid] instance.
///
/// # Arguments
///
/// - `brightness_grid`: instance to read from
///
/// returns: height
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_height(
brightness_grid: NonNull<BrightnessGrid>,
) -> usize {
unsafe { brightness_grid.as_ref().height() }
}
/// Gets an unsafe reference to the data of the [BrightnessGrid] instance.
///
/// The returned memory is valid for the lifetime of the brightness grid.
///
/// # Arguments
///
/// - `brightness_grid`: instance to read from
///
/// returns: slice of bytes underlying the `brightness_grid`.
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_unsafe_data_ref(
brightness_grid: NonNull<BrightnessGrid>,
) -> ByteSlice {
//noinspection RsAssertEqual
const _: () = assert!(size_of::<Brightness>() == 1);
let data = unsafe { (*brightness_grid.as_ptr()).data_ref_mut() };
unsafe {
ByteSlice::from_slice(transmute::<&mut [Brightness], &mut [u8]>(data))
}
}
/// Creates a [BrightnessGridCommand] and immediately turns that into a [Packet].
///
/// The provided [BrightnessGrid] gets consumed.
///
/// Returns NULL in case of an error.
#[no_mangle]
pub unsafe extern "C" fn sp_brightness_grid_into_packet(
grid: NonNull<BrightnessGrid>,
x: usize,
y: usize,
) -> *mut Packet {
let grid = unsafe { heap_remove(grid) };
heap_move_ok(Packet::try_from(BrightnessGridCommand {
grid,
origin: Origin::new(x, y),
}))
}