diff --git a/build.rs b/build.rs
index 0bc6e0a..83e9641 100644
--- a/build.rs
+++ b/build.rs
@@ -10,7 +10,9 @@ fn main() {
     let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
     println!("cargo::rerun-if-changed={crate_dir}");
 
-    let config = cbindgen::Config::from_file(crate_dir.clone() + "/cbindgen.toml").unwrap();
+    let config =
+        cbindgen::Config::from_file(crate_dir.clone() + "/cbindgen.toml")
+            .unwrap();
 
     let output_dir = env::var("OUT_DIR").unwrap();
     let header_file = output_dir.clone() + "/servicepoint.h";
diff --git a/cbindgen.toml b/cbindgen.toml
index 29c19a8..48ef574 100644
--- a/cbindgen.toml
+++ b/cbindgen.toml
@@ -39,3 +39,6 @@ exclude = []
 
 [enum]
 rename_variants = "QualifiedScreamingSnakeCase"
+
+[ptr]
+non_null_attribute = "/*notnull*/"
diff --git a/include/servicepoint.h b/include/servicepoint.h
index 63c1179..4a0af95 100644
--- a/include/servicepoint.h
+++ b/include/servicepoint.h
@@ -239,7 +239,7 @@ typedef struct {
     /**
      * The start address of the memory
      */
-    uint8_t *start;
+    uint8_t */*notnull*/ start;
     /**
      * The amount of memory in bytes
      */
@@ -351,7 +351,7 @@ extern "C" {
  * - the returned instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_bitmap_free`.
  */
-Bitmap *sp_bitmap_clone(const Bitmap *bitmap);
+Bitmap */*notnull*/ sp_bitmap_clone(Bitmap */*notnull*/ bitmap);
 
 /**
  * Sets the state of all pixels in the [SPBitmap].
@@ -372,7 +372,7 @@ Bitmap *sp_bitmap_clone(const Bitmap *bitmap);
  * - `bitmap` points to a valid [SPBitmap]
  * - `bitmap` is not written to or read from concurrently
  */
-void sp_bitmap_fill(Bitmap *bitmap, bool value);
+void sp_bitmap_fill(Bitmap */*notnull*/ bitmap, bool value);
 
 /**
  * Deallocates a [SPBitmap].
@@ -386,12 +386,10 @@ void sp_bitmap_fill(Bitmap *bitmap, bool value);
  * The caller has to make sure that:
  *
  * - `bitmap` points to a valid [SPBitmap]
- * - `bitmap` is not used concurrently or after bitmap call
- * - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand]
  *
  * [SPCommand]: [crate::SPCommand]
  */
-void sp_bitmap_free(Bitmap *bitmap);
+void sp_bitmap_free(Bitmap */*notnull*/ bitmap);
 
 /**
  * Gets the current value at the specified position in the [SPBitmap].
@@ -413,7 +411,7 @@ void sp_bitmap_free(Bitmap *bitmap);
  * - `bitmap` points to a valid [SPBitmap]
  * - `bitmap` is not written to concurrently
  */
-bool sp_bitmap_get(const Bitmap *bitmap, size_t x, size_t y);
+bool sp_bitmap_get(Bitmap */*notnull*/ bitmap, size_t x, size_t y);
 
 /**
  * Gets the height in pixels of the [SPBitmap] instance.
@@ -432,7 +430,7 @@ bool sp_bitmap_get(const Bitmap *bitmap, size_t x, size_t y);
  *
  * - `bitmap` points to a valid [SPBitmap]
  */
-size_t sp_bitmap_height(const Bitmap *bitmap);
+size_t sp_bitmap_height(Bitmap */*notnull*/ bitmap);
 
 /**
  * Loads a [SPBitmap] with the specified dimensions from the provided data.
@@ -465,8 +463,7 @@ size_t sp_bitmap_height(const Bitmap *bitmap);
  */
 Bitmap *sp_bitmap_load(size_t width,
                        size_t height,
-                       const uint8_t *data,
-                       size_t data_length);
+                       SPByteSlice data);
 
 /**
  * Creates a new [SPBitmap] with the specified dimensions.
@@ -506,7 +503,7 @@ Bitmap *sp_bitmap_new(size_t width,
  * - the returned instance is freed in some way, either by using a consuming function or
  *   by explicitly calling [sp_bitmap_free].
  */
-Bitmap *sp_bitmap_new_screen_sized(void);
+Bitmap */*notnull*/ sp_bitmap_new_screen_sized(void);
 
 /**
  * Sets the value of the specified position in the [SPBitmap].
@@ -531,7 +528,7 @@ Bitmap *sp_bitmap_new_screen_sized(void);
  * - `bitmap` points to a valid [SPBitmap]
  * - `bitmap` is not written to or read from concurrently
  */
-void sp_bitmap_set(Bitmap *bitmap, size_t x, size_t y, bool value);
+void sp_bitmap_set(Bitmap */*notnull*/ bitmap, size_t x, size_t y, bool value);
 
 /**
  * Gets an unsafe reference to the data of the [SPBitmap] instance.
@@ -548,7 +545,7 @@ void sp_bitmap_set(Bitmap *bitmap, size_t x, size_t y, bool value);
  * - the returned memory range is never accessed after the passed [SPBitmap] has been freed
  * - the returned memory range is never accessed concurrently, either via the [SPBitmap] or directly
  */
-SPByteSlice sp_bitmap_unsafe_data_ref(Bitmap *bitmap);
+SPByteSlice sp_bitmap_unsafe_data_ref(Bitmap */*notnull*/ bitmap);
 
 /**
  * Gets the width in pixels of the [SPBitmap] instance.
@@ -567,7 +564,7 @@ SPByteSlice sp_bitmap_unsafe_data_ref(Bitmap *bitmap);
  *
  * - `bitmap` points to a valid [SPBitmap]
  */
-size_t sp_bitmap_width(const Bitmap *bitmap);
+size_t sp_bitmap_width(Bitmap */*notnull*/ bitmap);
 
 /**
  * Clones a [SPBitVec].
@@ -587,7 +584,7 @@ size_t sp_bitmap_width(const Bitmap *bitmap);
  * - the returned instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_bitvec_free`.
  */
-SPBitVec *sp_bitvec_clone(const SPBitVec *bit_vec);
+SPBitVec */*notnull*/ sp_bitvec_clone(SPBitVec */*notnull*/ bit_vec);
 
 /**
  * Sets the value of all bits in the [SPBitVec].
@@ -608,7 +605,7 @@ SPBitVec *sp_bitvec_clone(const SPBitVec *bit_vec);
  * - `bit_vec` points to a valid [SPBitVec]
  * - `bit_vec` is not written to or read from concurrently
  */
-void sp_bitvec_fill(SPBitVec *bit_vec, bool value);
+void sp_bitvec_fill(SPBitVec */*notnull*/ bit_vec, bool value);
 
 /**
  * Deallocates a [SPBitVec].
@@ -627,7 +624,7 @@ void sp_bitvec_fill(SPBitVec *bit_vec, bool value);
  *
  * [SPCommand]: [crate::SPCommand]
  */
-void sp_bitvec_free(SPBitVec *bit_vec);
+void sp_bitvec_free(SPBitVec */*notnull*/ bit_vec);
 
 /**
  * Gets the value of a bit from the [SPBitVec].
@@ -651,7 +648,7 @@ void sp_bitvec_free(SPBitVec *bit_vec);
  * - `bit_vec` points to a valid [SPBitVec]
  * - `bit_vec` is not written to concurrently
  */
-bool sp_bitvec_get(const SPBitVec *bit_vec, size_t index);
+bool sp_bitvec_get(SPBitVec */*notnull*/ bit_vec, size_t index);
 
 /**
  * Returns true if length is 0.
@@ -670,7 +667,7 @@ bool sp_bitvec_get(const SPBitVec *bit_vec, size_t index);
  *
  * - `bit_vec` points to a valid [SPBitVec]
  */
-bool sp_bitvec_is_empty(const SPBitVec *bit_vec);
+bool sp_bitvec_is_empty(SPBitVec */*notnull*/ bit_vec);
 
 /**
  * Gets the length of the [SPBitVec] in bits.
@@ -689,7 +686,7 @@ bool sp_bitvec_is_empty(const SPBitVec *bit_vec);
  *
  * - `bit_vec` points to a valid [SPBitVec]
  */
-size_t sp_bitvec_len(const SPBitVec *bit_vec);
+size_t sp_bitvec_len(SPBitVec */*notnull*/ bit_vec);
 
 /**
  * Interpret the data as a series of bits and load then into a new [SPBitVec] instance.
@@ -709,8 +706,7 @@ size_t sp_bitvec_len(const SPBitVec *bit_vec);
  * - the returned instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_bitvec_free`.
  */
-SPBitVec *sp_bitvec_load(const uint8_t *data,
-                         size_t data_length);
+SPBitVec */*notnull*/ sp_bitvec_load(SPByteSlice data);
 
 /**
  * Creates a new [SPBitVec] instance.
@@ -732,7 +728,7 @@ SPBitVec *sp_bitvec_load(const uint8_t *data,
  * - the returned instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_bitvec_free`.
  */
-SPBitVec *sp_bitvec_new(size_t size);
+SPBitVec */*notnull*/ sp_bitvec_new(size_t size);
 
 /**
  * Sets the value of a bit in the [SPBitVec].
@@ -755,7 +751,7 @@ SPBitVec *sp_bitvec_new(size_t size);
  * - `bit_vec` points to a valid [SPBitVec]
  * - `bit_vec` is not written to or read from concurrently
  */
-void sp_bitvec_set(SPBitVec *bit_vec, size_t index, bool value);
+void sp_bitvec_set(SPBitVec */*notnull*/ bit_vec, size_t index, bool value);
 
 /**
  * Gets an unsafe reference to the data of the [SPBitVec] instance.
@@ -776,7 +772,7 @@ void sp_bitvec_set(SPBitVec *bit_vec, size_t index, bool value);
  * - the returned memory range is never accessed after the passed [SPBitVec] has been freed
  * - the returned memory range is never accessed concurrently, either via the [SPBitVec] or directly
  */
-SPByteSlice sp_bitvec_unsafe_data_ref(SPBitVec *bit_vec);
+SPByteSlice sp_bitvec_unsafe_data_ref(SPBitVec */*notnull*/ bit_vec);
 
 /**
  * Clones a [SPBrightnessGrid].
@@ -800,7 +796,7 @@ SPByteSlice sp_bitvec_unsafe_data_ref(SPBitVec *bit_vec);
  * - the returned instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_brightness_grid_free`.
  */
-BrightnessGrid *sp_brightness_grid_clone(const BrightnessGrid *brightness_grid);
+BrightnessGrid */*notnull*/ sp_brightness_grid_clone(BrightnessGrid */*notnull*/ brightness_grid);
 
 /**
  * Sets the value of all cells in the [SPBrightnessGrid].
@@ -822,7 +818,8 @@ BrightnessGrid *sp_brightness_grid_clone(const BrightnessGrid *brightness_grid);
  * - `brightness_grid` points to a valid [SPBrightnessGrid]
  * - `brightness_grid` is not written to or read from concurrently
  */
-void sp_brightness_grid_fill(BrightnessGrid *brightness_grid, uint8_t value);
+void sp_brightness_grid_fill(BrightnessGrid */*notnull*/ brightness_grid,
+                             uint8_t value);
 
 /**
  * Deallocates a [SPBrightnessGrid].
@@ -845,7 +842,7 @@ void sp_brightness_grid_fill(BrightnessGrid *brightness_grid, uint8_t value);
  *
  * [SPCommand]: [crate::SPCommand]
  */
-void sp_brightness_grid_free(BrightnessGrid *brightness_grid);
+void sp_brightness_grid_free(BrightnessGrid */*notnull*/ brightness_grid);
 
 /**
  * Gets the current value at the specified position.
@@ -869,7 +866,7 @@ void sp_brightness_grid_free(BrightnessGrid *brightness_grid);
  * - `brightness_grid` points to a valid [SPBrightnessGrid]
  * - `brightness_grid` is not written to concurrently
  */
-uint8_t sp_brightness_grid_get(const BrightnessGrid *brightness_grid,
+uint8_t sp_brightness_grid_get(BrightnessGrid */*notnull*/ brightness_grid,
                                size_t x,
                                size_t y);
 
@@ -892,7 +889,7 @@ uint8_t sp_brightness_grid_get(const BrightnessGrid *brightness_grid,
  *
  * - `brightness_grid` points to a valid [SPBrightnessGrid]
  */
-size_t sp_brightness_grid_height(const BrightnessGrid *brightness_grid);
+size_t sp_brightness_grid_height(BrightnessGrid */*notnull*/ brightness_grid);
 
 /**
  * Loads a [SPBrightnessGrid] with the specified dimensions from the provided data.
@@ -915,8 +912,7 @@ size_t sp_brightness_grid_height(const BrightnessGrid *brightness_grid);
  */
 BrightnessGrid *sp_brightness_grid_load(size_t width,
                                         size_t height,
-                                        const uint8_t *data,
-                                        size_t data_length);
+                                        SPByteSlice data);
 
 /**
  * Creates a new [SPBrightnessGrid] with the specified dimensions.
@@ -930,8 +926,8 @@ BrightnessGrid *sp_brightness_grid_load(size_t width,
  * - the returned instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_brightness_grid_free`.
  */
-BrightnessGrid *sp_brightness_grid_new(size_t width,
-                                       size_t height);
+BrightnessGrid */*notnull*/ sp_brightness_grid_new(size_t width,
+                                                   size_t height);
 
 /**
  * Sets the value of the specified position in the [SPBrightnessGrid].
@@ -957,7 +953,7 @@ BrightnessGrid *sp_brightness_grid_new(size_t width,
  * - `brightness_grid` points to a valid [SPBrightnessGrid]
  * - `brightness_grid` is not written to or read from concurrently
  */
-void sp_brightness_grid_set(BrightnessGrid *brightness_grid,
+void sp_brightness_grid_set(BrightnessGrid */*notnull*/ brightness_grid,
                             size_t x,
                             size_t y,
                             uint8_t value);
@@ -983,7 +979,7 @@ void sp_brightness_grid_set(BrightnessGrid *brightness_grid,
  * - the returned memory range is never accessed after the passed [SPBrightnessGrid] has been freed
  * - the returned memory range is never accessed concurrently, either via the [SPBrightnessGrid] or directly
  */
-SPByteSlice sp_brightness_grid_unsafe_data_ref(BrightnessGrid *brightness_grid);
+SPByteSlice sp_brightness_grid_unsafe_data_ref(BrightnessGrid */*notnull*/ brightness_grid);
 
 /**
  * Gets the width of the [SPBrightnessGrid] instance.
@@ -1004,7 +1000,7 @@ SPByteSlice sp_brightness_grid_unsafe_data_ref(BrightnessGrid *brightness_grid);
  *
  * - `brightness_grid` points to a valid [SPBrightnessGrid]
  */
-size_t sp_brightness_grid_width(const BrightnessGrid *brightness_grid);
+size_t sp_brightness_grid_width(BrightnessGrid */*notnull*/ brightness_grid);
 
 /**
  * Clones a [SPCharGrid].
@@ -1024,7 +1020,7 @@ size_t sp_brightness_grid_width(const BrightnessGrid *brightness_grid);
  * - the returned instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_char_grid_free`.
  */
-CharGrid *sp_char_grid_clone(const CharGrid *char_grid);
+CharGrid */*notnull*/ sp_char_grid_clone(CharGrid */*notnull*/ char_grid);
 
 /**
  * Sets the value of all cells in the [SPCharGrid].
@@ -1045,7 +1041,7 @@ CharGrid *sp_char_grid_clone(const CharGrid *char_grid);
  * - `char_grid` points to a valid [SPCharGrid]
  * - `char_grid` is not written to or read from concurrently
  */
-void sp_char_grid_fill(CharGrid *char_grid, uint32_t value);
+void sp_char_grid_fill(CharGrid */*notnull*/ char_grid, uint32_t value);
 
 /**
  * Deallocates a [SPCharGrid].
@@ -1064,7 +1060,7 @@ void sp_char_grid_fill(CharGrid *char_grid, uint32_t value);
  *
  * [SPCommand]: [crate::SPCommand]
  */
-void sp_char_grid_free(CharGrid *char_grid);
+void sp_char_grid_free(CharGrid */*notnull*/ char_grid);
 
 /**
  * Gets the current value at the specified position.
@@ -1086,7 +1082,7 @@ void sp_char_grid_free(CharGrid *char_grid);
  * - `char_grid` points to a valid [SPCharGrid]
  * - `char_grid` is not written to concurrently
  */
-uint32_t sp_char_grid_get(const CharGrid *char_grid, size_t x, size_t y);
+uint32_t sp_char_grid_get(CharGrid */*notnull*/ char_grid, size_t x, size_t y);
 
 /**
  * Gets the height of the [SPCharGrid] instance.
@@ -1105,7 +1101,7 @@ uint32_t sp_char_grid_get(const CharGrid *char_grid, size_t x, size_t y);
  *
  * - `char_grid` points to a valid [SPCharGrid]
  */
-size_t sp_char_grid_height(const CharGrid *char_grid);
+size_t sp_char_grid_height(CharGrid */*notnull*/ char_grid);
 
 /**
  * Loads a [SPCharGrid] with the specified dimensions from the provided data.
@@ -1127,10 +1123,9 @@ size_t sp_char_grid_height(const CharGrid *char_grid);
  * - the returned instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_char_grid_free`.
  */
-CharGrid *sp_char_grid_load(size_t width,
-                            size_t height,
-                            const uint8_t *data,
-                            size_t data_length);
+CharGrid */*notnull*/ sp_char_grid_load(size_t width,
+                                        size_t height,
+                                        SPByteSlice data);
 
 /**
  * Creates a new [SPCharGrid] with the specified dimensions.
@@ -1144,8 +1139,8 @@ CharGrid *sp_char_grid_load(size_t width,
  * - the returned instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_char_grid_free`.
  */
-CharGrid *sp_char_grid_new(size_t width,
-                           size_t height);
+CharGrid */*notnull*/ sp_char_grid_new(size_t width,
+                                       size_t height);
 
 /**
  * Sets the value of the specified position in the [SPCharGrid].
@@ -1172,7 +1167,10 @@ CharGrid *sp_char_grid_new(size_t width,
  *
  * [SPBitVec]: [crate::SPBitVec]
  */
-void sp_char_grid_set(CharGrid *char_grid, size_t x, size_t y, uint32_t value);
+void sp_char_grid_set(CharGrid */*notnull*/ char_grid,
+                      size_t x,
+                      size_t y,
+                      uint32_t value);
 
 /**
  * Gets the width of the [SPCharGrid] instance.
@@ -1191,7 +1189,7 @@ void sp_char_grid_set(CharGrid *char_grid, size_t x, size_t y, uint32_t value);
  *
  * - `char_grid` points to a valid [SPCharGrid]
  */
-size_t sp_char_grid_width(const CharGrid *char_grid);
+size_t sp_char_grid_width(CharGrid */*notnull*/ char_grid);
 
 /**
  * Set pixel data starting at the pixel offset on screen.
@@ -1221,7 +1219,7 @@ size_t sp_char_grid_width(const CharGrid *char_grid);
  *   by explicitly calling `sp_command_free`.
  */
 Command *sp_command_bitmap_linear(size_t offset,
-                                  SPBitVec *bit_vec,
+                                  SPBitVec */*notnull*/ bit_vec,
                                   CompressionCode compression);
 
 /**
@@ -1252,7 +1250,7 @@ Command *sp_command_bitmap_linear(size_t offset,
  *   by explicitly calling `sp_command_free`.
  */
 Command *sp_command_bitmap_linear_and(size_t offset,
-                                      SPBitVec *bit_vec,
+                                      SPBitVec */*notnull*/ bit_vec,
                                       CompressionCode compression);
 
 /**
@@ -1283,7 +1281,7 @@ Command *sp_command_bitmap_linear_and(size_t offset,
  *   by explicitly calling `sp_command_free`.
  */
 Command *sp_command_bitmap_linear_or(size_t offset,
-                                     SPBitVec *bit_vec,
+                                     SPBitVec */*notnull*/ bit_vec,
                                      CompressionCode compression);
 
 /**
@@ -1310,7 +1308,7 @@ Command *sp_command_bitmap_linear_or(size_t offset,
  */
 Command *sp_command_bitmap_linear_win(size_t x,
                                       size_t y,
-                                      Bitmap *bitmap,
+                                      Bitmap */*notnull*/ bitmap,
                                       CompressionCode compression);
 
 /**
@@ -1341,7 +1339,7 @@ Command *sp_command_bitmap_linear_win(size_t x,
  *   by explicitly calling `sp_command_free`.
  */
 Command *sp_command_bitmap_linear_xor(size_t offset,
-                                      SPBitVec *bit_vec,
+                                      SPBitVec */*notnull*/ bit_vec,
                                       CompressionCode compression);
 
 /**
@@ -1360,7 +1358,7 @@ Command *sp_command_bitmap_linear_xor(size_t offset,
  * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_command_free`.
  */
-Command *sp_command_brightness(uint8_t brightness);
+Command */*notnull*/ sp_command_brightness(uint8_t brightness);
 
 /**
  * Set the brightness of individual tiles in a rectangular area of the display.
@@ -1382,9 +1380,9 @@ Command *sp_command_brightness(uint8_t brightness);
  * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_command_free`.
  */
-Command *sp_command_char_brightness(size_t x,
-                                    size_t y,
-                                    BrightnessGrid *grid);
+Command */*notnull*/ sp_command_char_brightness(size_t x,
+                                                size_t y,
+                                                BrightnessGrid */*notnull*/ grid);
 
 /**
  * Set all pixels to the off state.
@@ -1406,7 +1404,7 @@ Command *sp_command_char_brightness(size_t x,
  * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_command_free`.
  */
-Command *sp_command_clear(void);
+Command */*notnull*/ sp_command_clear(void);
 
 /**
  * Clones a [SPCommand] instance.
@@ -1426,7 +1424,7 @@ Command *sp_command_clear(void);
  * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_command_free`.
  */
-Command *sp_command_clone(const Command *command);
+Command */*notnull*/ sp_command_clone(Command */*notnull*/ command);
 
 /**
  * Show codepage 437 encoded text on the screen.
@@ -1448,9 +1446,9 @@ Command *sp_command_clone(const Command *command);
  * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_command_free`.
  */
-Command *sp_command_cp437_data(size_t x,
-                               size_t y,
-                               Cp437Grid *grid);
+Command */*notnull*/ sp_command_cp437_data(size_t x,
+                                           size_t y,
+                                           Cp437Grid */*notnull*/ grid);
 
 /**
  * A yet-to-be-tested command.
@@ -1464,7 +1462,7 @@ Command *sp_command_cp437_data(size_t x,
  * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_command_free`.
  */
-Command *sp_command_fade_out(void);
+Command */*notnull*/ sp_command_fade_out(void);
 
 /**
  * Deallocates a [SPCommand].
@@ -1488,7 +1486,7 @@ Command *sp_command_fade_out(void);
  * - `command` is not used concurrently or after this call
  * - `command` was not passed to another consuming function, e.g. to create a [SPPacket]
  */
-void sp_command_free(Command *command);
+void sp_command_free(Command */*notnull*/ command);
 
 /**
  * Kills the udp daemon on the display, which usually results in a restart.
@@ -1504,7 +1502,7 @@ void sp_command_free(Command *command);
  * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_command_free`.
  */
-Command *sp_command_hard_reset(void);
+Command */*notnull*/ sp_command_hard_reset(void);
 
 /**
  * A low-level display command.
@@ -1541,7 +1539,7 @@ Command *sp_command_hard_reset(void);
  * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_command_free`.
  */
-Command *sp_command_try_from_packet(Packet *packet);
+Command *sp_command_try_from_packet(Packet */*notnull*/ packet);
 
 /**
  * Show UTF-8 encoded text on the screen.
@@ -1563,9 +1561,9 @@ Command *sp_command_try_from_packet(Packet *packet);
  * - the returned [SPCommand] instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_command_free`.
  */
-Command *sp_command_utf8_data(size_t x,
-                              size_t y,
-                              CharGrid *grid);
+Command */*notnull*/ sp_command_utf8_data(size_t x,
+                                          size_t y,
+                                          CharGrid */*notnull*/ grid);
 
 /**
  * Closes and deallocates a [SPConnection].
@@ -1581,7 +1579,7 @@ Command *sp_command_utf8_data(size_t x,
  * - `connection` points to a valid [SPConnection]
  * - `connection` is not used concurrently or after this call
  */
-void sp_connection_free(UdpConnection *connection);
+void sp_connection_free(UdpConnection */*notnull*/ connection);
 
 /**
  * Creates a new instance of [SPConnection].
@@ -1599,7 +1597,7 @@ void sp_connection_free(UdpConnection *connection);
  * - the returned instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_connection_free`.
  */
-UdpConnection *sp_connection_open(const char *host);
+UdpConnection *sp_connection_open(char */*notnull*/ host);
 
 /**
  * Sends a [SPCommand] to the display using the [SPConnection].
@@ -1621,8 +1619,8 @@ UdpConnection *sp_connection_open(const char *host);
  * - `command` points to a valid instance of [SPPacket]
  * - `command` is not used concurrently or after this call
  */
-bool sp_connection_send_command(const UdpConnection *connection,
-                                Command *command);
+bool sp_connection_send_command(UdpConnection */*notnull*/ connection,
+                                Command */*notnull*/ command);
 
 /**
  * Sends a [SPPacket] to the display using the [SPConnection].
@@ -1644,7 +1642,8 @@ bool sp_connection_send_command(const UdpConnection *connection,
  * - `packet` points to a valid instance of [SPPacket]
  * - `packet` is not used concurrently or after this call
  */
-bool sp_connection_send_packet(const UdpConnection *connection, Packet *packet);
+bool sp_connection_send_packet(UdpConnection */*notnull*/ connection,
+                               Packet */*notnull*/ packet);
 
 /**
  * Clones a [SPCp437Grid].
@@ -1664,7 +1663,7 @@ bool sp_connection_send_packet(const UdpConnection *connection, Packet *packet);
  * - the returned instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_cp437_grid_free`.
  */
-Cp437Grid *sp_cp437_grid_clone(const Cp437Grid *cp437_grid);
+Cp437Grid */*notnull*/ sp_cp437_grid_clone(Cp437Grid */*notnull*/ cp437_grid);
 
 /**
  * Sets the value of all cells in the [SPCp437Grid].
@@ -1685,7 +1684,7 @@ Cp437Grid *sp_cp437_grid_clone(const Cp437Grid *cp437_grid);
  * - `cp437_grid` points to a valid [SPCp437Grid]
  * - `cp437_grid` is not written to or read from concurrently
  */
-void sp_cp437_grid_fill(Cp437Grid *cp437_grid, uint8_t value);
+void sp_cp437_grid_fill(Cp437Grid */*notnull*/ cp437_grid, uint8_t value);
 
 /**
  * Deallocates a [SPCp437Grid].
@@ -1704,7 +1703,7 @@ void sp_cp437_grid_fill(Cp437Grid *cp437_grid, uint8_t value);
  *
  * [SPCommand]: [crate::SPCommand]
  */
-void sp_cp437_grid_free(Cp437Grid *cp437_grid);
+void sp_cp437_grid_free(Cp437Grid */*notnull*/ cp437_grid);
 
 /**
  * Gets the current value at the specified position.
@@ -1726,7 +1725,9 @@ void sp_cp437_grid_free(Cp437Grid *cp437_grid);
  * - `cp437_grid` points to a valid [SPCp437Grid]
  * - `cp437_grid` is not written to concurrently
  */
-uint8_t sp_cp437_grid_get(const Cp437Grid *cp437_grid, size_t x, size_t y);
+uint8_t sp_cp437_grid_get(Cp437Grid */*notnull*/ cp437_grid,
+                          size_t x,
+                          size_t y);
 
 /**
  * Gets the height of the [SPCp437Grid] instance.
@@ -1745,7 +1746,7 @@ uint8_t sp_cp437_grid_get(const Cp437Grid *cp437_grid, size_t x, size_t y);
  *
  * - `cp437_grid` points to a valid [SPCp437Grid]
  */
-size_t sp_cp437_grid_height(const Cp437Grid *cp437_grid);
+size_t sp_cp437_grid_height(Cp437Grid */*notnull*/ cp437_grid);
 
 /**
  * Loads a [SPCp437Grid] with the specified dimensions from the provided data.
@@ -1768,8 +1769,7 @@ size_t sp_cp437_grid_height(const Cp437Grid *cp437_grid);
  */
 Cp437Grid *sp_cp437_grid_load(size_t width,
                               size_t height,
-                              const uint8_t *data,
-                              size_t data_length);
+                              SPByteSlice data);
 
 /**
  * Creates a new [SPCp437Grid] with the specified dimensions.
@@ -1783,8 +1783,8 @@ Cp437Grid *sp_cp437_grid_load(size_t width,
  * - the returned instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_cp437_grid_free`.
  */
-Cp437Grid *sp_cp437_grid_new(size_t width,
-                             size_t height);
+Cp437Grid */*notnull*/ sp_cp437_grid_new(size_t width,
+                                         size_t height);
 
 /**
  * Sets the value of the specified position in the [SPCp437Grid].
@@ -1811,7 +1811,7 @@ Cp437Grid *sp_cp437_grid_new(size_t width,
  *
  * [SPBitVec]: [crate::SPBitVec]
  */
-void sp_cp437_grid_set(Cp437Grid *cp437_grid,
+void sp_cp437_grid_set(Cp437Grid */*notnull*/ cp437_grid,
                        size_t x,
                        size_t y,
                        uint8_t value);
@@ -1833,7 +1833,7 @@ void sp_cp437_grid_set(Cp437Grid *cp437_grid,
  * - the returned memory range is never accessed after the passed [SPCp437Grid] has been freed
  * - the returned memory range is never accessed concurrently, either via the [SPCp437Grid] or directly
  */
-SPByteSlice sp_cp437_grid_unsafe_data_ref(Cp437Grid *cp437_grid);
+SPByteSlice sp_cp437_grid_unsafe_data_ref(Cp437Grid */*notnull*/ cp437_grid);
 
 /**
  * Gets the width of the [SPCp437Grid] instance.
@@ -1852,7 +1852,7 @@ SPByteSlice sp_cp437_grid_unsafe_data_ref(Cp437Grid *cp437_grid);
  *
  * - `cp437_grid` points to a valid [SPCp437Grid]
  */
-size_t sp_cp437_grid_width(const Cp437Grid *cp437_grid);
+size_t sp_cp437_grid_width(Cp437Grid */*notnull*/ cp437_grid);
 
 /**
  * Clones a [SPPacket].
@@ -1872,7 +1872,7 @@ size_t sp_cp437_grid_width(const Cp437Grid *cp437_grid);
  * - the returned instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_packet_free`.
  */
-Packet *sp_packet_clone(const Packet *packet);
+Packet */*notnull*/ sp_packet_clone(Packet */*notnull*/ packet);
 
 /**
  * Deallocates a [SPPacket].
@@ -1888,7 +1888,7 @@ Packet *sp_packet_clone(const Packet *packet);
  * - `packet` points to a valid [SPPacket]
  * - `packet` is not used concurrently or after this call
  */
-void sp_packet_free(Packet *packet);
+void sp_packet_free(Packet */*notnull*/ packet);
 
 /**
  * Turns a [SPCommand] into a [SPPacket].
@@ -1909,7 +1909,7 @@ void sp_packet_free(Packet *packet);
  * - the returned [SPPacket] instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_packet_free`.
  */
-Packet *sp_packet_from_command(Command *command);
+Packet *sp_packet_from_command(Command */*notnull*/ command);
 
 /**
  * Creates a raw [SPPacket] from parts.
@@ -1937,15 +1937,14 @@ Packet *sp_packet_from_command(Command *command);
  * - the returned [SPPacket] instance is freed in some way, either by using a consuming function or
  *   by explicitly calling [sp_packet_free].
  */
-Packet *sp_packet_from_parts(Header header,
-                             const uint8_t *payload,
-                             size_t payload_len);
+Packet */*notnull*/ sp_packet_from_parts(Header header,
+                                         const SPByteSlice *payload);
 
-Header *sp_packet_get_header(Packet *packet);
+Header */*notnull*/ sp_packet_get_header(Packet */*notnull*/ packet);
 
-SPByteSlice sp_packet_get_payload(Packet *packet);
+SPByteSlice sp_packet_get_payload(Packet */*notnull*/ packet);
 
-void sp_packet_set_payload(Packet *packet, SPByteSlice data);
+void sp_packet_set_payload(Packet */*notnull*/ packet, SPByteSlice data);
 
 /**
  * Tries to load a [SPPacket] from the passed array with the specified length.
@@ -1965,10 +1964,9 @@ void sp_packet_set_payload(Packet *packet, SPByteSlice data);
  * - the returned [SPPacket] instance is freed in some way, either by using a consuming function or
  *   by explicitly calling `sp_packet_free`.
  */
-Packet *sp_packet_try_load(const uint8_t *data,
-                           size_t length);
+Packet *sp_packet_try_load(SPByteSlice data);
 
-void sp_packet_write_to(const Packet *packet, SPByteSlice buffer);
+void sp_packet_write_to(Packet */*notnull*/ packet, SPByteSlice buffer);
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/src/bitmap.rs b/src/bitmap.rs
index 1f6327f..2e70efc 100644
--- a/src/bitmap.rs
+++ b/src/bitmap.rs
@@ -13,7 +13,7 @@
 //! sp_bitmap_free(grid);
 //! ```
 
-use servicepoint::{DataRef, Grid};
+use servicepoint::{Bitmap, DataRef, Grid};
 use std::ptr::NonNull;
 
 use crate::byte_slice::SPByteSlice;
@@ -43,8 +43,8 @@ use crate::byte_slice::SPByteSlice;
 pub unsafe extern "C" fn sp_bitmap_new(
     width: usize,
     height: usize,
-) -> *mut servicepoint::Bitmap {
-    if let Some(bitmap) = servicepoint::Bitmap::new(width, height) {
+) -> *mut Bitmap {
+    if let Some(bitmap) = Bitmap::new(width, height) {
         Box::leak(Box::new(bitmap))
     } else {
         std::ptr::null_mut()
@@ -62,9 +62,8 @@ pub unsafe extern "C" fn sp_bitmap_new(
 /// - the returned instance is freed in some way, either by using a consuming function or
 ///   by explicitly calling [sp_bitmap_free].
 #[no_mangle]
-pub unsafe extern "C" fn sp_bitmap_new_screen_sized(
-) -> NonNull<servicepoint::Bitmap> {
-    let result = Box::new(servicepoint::Bitmap::max_sized());
+pub unsafe extern "C" fn sp_bitmap_new_screen_sized() -> NonNull<Bitmap> {
+    let result = Box::new(Bitmap::max_sized());
     NonNull::from(Box::leak(result))
 }
 
@@ -99,12 +98,10 @@ pub unsafe extern "C" fn sp_bitmap_new_screen_sized(
 pub unsafe extern "C" fn sp_bitmap_load(
     width: usize,
     height: usize,
-    data: *const u8,
-    data_length: usize,
-) -> *mut servicepoint::Bitmap {
-    assert!(!data.is_null());
-    let data = unsafe { std::slice::from_raw_parts(data, data_length) };
-    if let Ok(bitmap) = servicepoint::Bitmap::load(width, height, data) {
+    data: SPByteSlice,
+) -> *mut Bitmap {
+    let data = unsafe { data.as_slice() };
+    if let Ok(bitmap) = Bitmap::load(width, height, data) {
         Box::leak(Box::new(bitmap))
     } else {
         std::ptr::null_mut()
@@ -129,10 +126,9 @@ pub unsafe extern "C" fn sp_bitmap_load(
 ///   by explicitly calling `sp_bitmap_free`.
 #[no_mangle]
 pub unsafe extern "C" fn sp_bitmap_clone(
-    bitmap: *const servicepoint::Bitmap,
-) -> NonNull<servicepoint::Bitmap> {
-    assert!(!bitmap.is_null());
-    let result = Box::new(unsafe { (*bitmap).clone() });
+    bitmap: NonNull<Bitmap>,
+) -> NonNull<Bitmap> {
+    let result = Box::new(unsafe { bitmap.as_ref().clone() });
     NonNull::from(Box::leak(result))
 }
 
@@ -147,14 +143,11 @@ pub unsafe extern "C" fn sp_bitmap_clone(
 /// The caller has to make sure that:
 ///
 /// - `bitmap` points to a valid [SPBitmap]
-/// - `bitmap` is not used concurrently or after bitmap call
-/// - `bitmap` was not passed to another consuming function, e.g. to create a [SPCommand]
 ///
 /// [SPCommand]: [crate::SPCommand]
 #[no_mangle]
-pub unsafe extern "C" fn sp_bitmap_free(bitmap: *mut servicepoint::Bitmap) {
-    assert!(!bitmap.is_null());
-    _ = unsafe { Box::from_raw(bitmap) };
+pub unsafe extern "C" fn sp_bitmap_free(bitmap: NonNull<Bitmap>) {
+    _ = unsafe { Box::from_raw(bitmap.as_ptr()) };
 }
 
 /// Gets the current value at the specified position in the [SPBitmap].
@@ -177,12 +170,11 @@ pub unsafe extern "C" fn sp_bitmap_free(bitmap: *mut servicepoint::Bitmap) {
 /// - `bitmap` is not written to concurrently
 #[no_mangle]
 pub unsafe extern "C" fn sp_bitmap_get(
-    bitmap: *const servicepoint::Bitmap,
+    bitmap: NonNull<Bitmap>,
     x: usize,
     y: usize,
 ) -> bool {
-    assert!(!bitmap.is_null());
-    unsafe { (*bitmap).get(x, y) }
+    unsafe { bitmap.as_ref().get(x, y) }
 }
 
 /// Sets the value of the specified position in the [SPBitmap].
@@ -208,13 +200,12 @@ pub unsafe extern "C" fn sp_bitmap_get(
 /// - `bitmap` is not written to or read from concurrently
 #[no_mangle]
 pub unsafe extern "C" fn sp_bitmap_set(
-    bitmap: *mut servicepoint::Bitmap,
+    bitmap: NonNull<Bitmap>,
     x: usize,
     y: usize,
     value: bool,
 ) {
-    assert!(!bitmap.is_null());
-    unsafe { (*bitmap).set(x, y, value) };
+    unsafe { (*bitmap.as_ptr()).set(x, y, value) };
 }
 
 /// Sets the state of all pixels in the [SPBitmap].
@@ -235,12 +226,8 @@ pub unsafe extern "C" fn sp_bitmap_set(
 /// - `bitmap` points to a valid [SPBitmap]
 /// - `bitmap` is not written to or read from concurrently
 #[no_mangle]
-pub unsafe extern "C" fn sp_bitmap_fill(
-    bitmap: *mut servicepoint::Bitmap,
-    value: bool,
-) {
-    assert!(!bitmap.is_null());
-    unsafe { (*bitmap).fill(value) };
+pub unsafe extern "C" fn sp_bitmap_fill(bitmap: NonNull<Bitmap>, value: bool) {
+    unsafe { (*bitmap.as_ptr()).fill(value) };
 }
 
 /// Gets the width in pixels of the [SPBitmap] instance.
@@ -259,11 +246,8 @@ pub unsafe extern "C" fn sp_bitmap_fill(
 ///
 /// - `bitmap` points to a valid [SPBitmap]
 #[no_mangle]
-pub unsafe extern "C" fn sp_bitmap_width(
-    bitmap: *const servicepoint::Bitmap,
-) -> usize {
-    assert!(!bitmap.is_null());
-    unsafe { (*bitmap).width() }
+pub unsafe extern "C" fn sp_bitmap_width(bitmap: NonNull<Bitmap>) -> usize {
+    unsafe { bitmap.as_ref().width() }
 }
 
 /// Gets the height in pixels of the [SPBitmap] instance.
@@ -282,11 +266,8 @@ pub unsafe extern "C" fn sp_bitmap_width(
 ///
 /// - `bitmap` points to a valid [SPBitmap]
 #[no_mangle]
-pub unsafe extern "C" fn sp_bitmap_height(
-    bitmap: *const servicepoint::Bitmap,
-) -> usize {
-    assert!(!bitmap.is_null());
-    unsafe { (*bitmap).height() }
+pub unsafe extern "C" fn sp_bitmap_height(bitmap: NonNull<Bitmap>) -> usize {
+    unsafe { bitmap.as_ref().height() }
 }
 
 /// Gets an unsafe reference to the data of the [SPBitmap] instance.
@@ -304,8 +285,7 @@ pub unsafe extern "C" fn sp_bitmap_height(
 /// - the returned memory range is never accessed concurrently, either via the [SPBitmap] or directly
 #[no_mangle]
 pub unsafe extern "C" fn sp_bitmap_unsafe_data_ref(
-    bitmap: *mut servicepoint::Bitmap,
+    mut bitmap: NonNull<Bitmap>,
 ) -> SPByteSlice {
-    assert!(!bitmap.is_null());
-    unsafe { SPByteSlice::from_slice((*bitmap).data_ref_mut()) }
+    unsafe { SPByteSlice::from_slice(bitmap.as_mut().data_ref_mut()) }
 }
diff --git a/src/bitvec.rs b/src/bitvec.rs
index 104ca27..c32ce78 100644
--- a/src/bitvec.rs
+++ b/src/bitvec.rs
@@ -13,19 +13,7 @@ use std::ptr::NonNull;
 /// sp_bitvec_set(vec, 5, true);
 /// sp_bitvec_free(vec);
 /// ```
-pub struct SPBitVec(servicepoint::BitVecU8Msb0);
-
-impl From<servicepoint::BitVecU8Msb0> for SPBitVec {
-    fn from(actual: servicepoint::BitVecU8Msb0) -> Self {
-        Self(actual)
-    }
-}
-
-impl From<SPBitVec> for servicepoint::BitVecU8Msb0 {
-    fn from(value: SPBitVec) -> Self {
-        value.0
-    }
-}
+pub struct SPBitVec(pub(crate) servicepoint::BitVecU8Msb0);
 
 impl Clone for SPBitVec {
     fn clone(&self) -> Self {
@@ -53,7 +41,8 @@ impl Clone for SPBitVec {
 ///   by explicitly calling `sp_bitvec_free`.
 #[no_mangle]
 pub unsafe extern "C" fn sp_bitvec_new(size: usize) -> NonNull<SPBitVec> {
-    let result = Box::new(SPBitVec(servicepoint::BitVecU8Msb0::repeat(false, size)));
+    let result =
+        Box::new(SPBitVec(servicepoint::BitVecU8Msb0::repeat(false, size)));
     NonNull::from(Box::leak(result))
 }
 
@@ -75,12 +64,11 @@ pub unsafe extern "C" fn sp_bitvec_new(size: usize) -> NonNull<SPBitVec> {
 ///   by explicitly calling `sp_bitvec_free`.
 #[no_mangle]
 pub unsafe extern "C" fn sp_bitvec_load(
-    data: *const u8,
-    data_length: usize,
+    data: SPByteSlice,
 ) -> NonNull<SPBitVec> {
-    assert!(!data.is_null());
-    let data = unsafe { std::slice::from_raw_parts(data, data_length) };
-    let result = Box::new(SPBitVec(servicepoint::BitVecU8Msb0::from_slice(data)));
+    let data = unsafe { data.as_slice() };
+    let result =
+        Box::new(SPBitVec(servicepoint::BitVecU8Msb0::from_slice(data)));
     NonNull::from(Box::leak(result))
 }
 
@@ -102,10 +90,9 @@ pub unsafe extern "C" fn sp_bitvec_load(
 ///   by explicitly calling `sp_bitvec_free`.
 #[no_mangle]
 pub unsafe extern "C" fn sp_bitvec_clone(
-    bit_vec: *const SPBitVec,
+    bit_vec: NonNull<SPBitVec>,
 ) -> NonNull<SPBitVec> {
-    assert!(!bit_vec.is_null());
-    let result = Box::new(unsafe { (*bit_vec).clone() });
+    let result = Box::new(unsafe { bit_vec.as_ref().clone() });
     NonNull::from(Box::leak(result))
 }
 
@@ -125,9 +112,8 @@ pub unsafe extern "C" fn sp_bitvec_clone(
 ///
 /// [SPCommand]: [crate::SPCommand]
 #[no_mangle]
-pub unsafe extern "C" fn sp_bitvec_free(bit_vec: *mut SPBitVec) {
-    assert!(!bit_vec.is_null());
-    _ = unsafe { Box::from_raw(bit_vec) };
+pub unsafe extern "C" fn sp_bitvec_free(bit_vec: NonNull<SPBitVec>) {
+    _ = unsafe { Box::from_raw(bit_vec.as_ptr()) };
 }
 
 /// Gets the value of a bit from the [SPBitVec].
@@ -152,11 +138,10 @@ pub unsafe extern "C" fn sp_bitvec_free(bit_vec: *mut SPBitVec) {
 /// - `bit_vec` is not written to concurrently
 #[no_mangle]
 pub unsafe extern "C" fn sp_bitvec_get(
-    bit_vec: *const SPBitVec,
+    bit_vec: NonNull<SPBitVec>,
     index: usize,
 ) -> bool {
-    assert!(!bit_vec.is_null());
-    unsafe { *(*bit_vec).0.get(index).unwrap() }
+    unsafe { *bit_vec.as_ref().0.get(index).unwrap() }
 }
 
 /// Sets the value of a bit in the [SPBitVec].
@@ -180,12 +165,11 @@ pub unsafe extern "C" fn sp_bitvec_get(
 /// - `bit_vec` is not written to or read from concurrently
 #[no_mangle]
 pub unsafe extern "C" fn sp_bitvec_set(
-    bit_vec: *mut SPBitVec,
+    bit_vec: NonNull<SPBitVec>,
     index: usize,
     value: bool,
 ) {
-    assert!(!bit_vec.is_null());
-    unsafe { (*bit_vec).0.set(index, value) }
+    unsafe { (*bit_vec.as_ptr()).0.set(index, value) }
 }
 
 /// Sets the value of all bits in the [SPBitVec].
@@ -206,9 +190,11 @@ pub unsafe extern "C" fn sp_bitvec_set(
 /// - `bit_vec` points to a valid [SPBitVec]
 /// - `bit_vec` is not written to or read from concurrently
 #[no_mangle]
-pub unsafe extern "C" fn sp_bitvec_fill(bit_vec: *mut SPBitVec, value: bool) {
-    assert!(!bit_vec.is_null());
-    unsafe { (*bit_vec).0.fill(value) }
+pub unsafe extern "C" fn sp_bitvec_fill(
+    bit_vec: NonNull<SPBitVec>,
+    value: bool,
+) {
+    unsafe { (*bit_vec.as_ptr()).0.fill(value) }
 }
 
 /// Gets the length of the [SPBitVec] in bits.
@@ -227,9 +213,8 @@ pub unsafe extern "C" fn sp_bitvec_fill(bit_vec: *mut SPBitVec, value: bool) {
 ///
 /// - `bit_vec` points to a valid [SPBitVec]
 #[no_mangle]
-pub unsafe extern "C" fn sp_bitvec_len(bit_vec: *const SPBitVec) -> usize {
-    assert!(!bit_vec.is_null());
-    unsafe { (*bit_vec).0.len() }
+pub unsafe extern "C" fn sp_bitvec_len(bit_vec: NonNull<SPBitVec>) -> usize {
+    unsafe { bit_vec.as_ref().0.len() }
 }
 
 /// Returns true if length is 0.
@@ -248,9 +233,10 @@ pub unsafe extern "C" fn sp_bitvec_len(bit_vec: *const SPBitVec) -> usize {
 ///
 /// - `bit_vec` points to a valid [SPBitVec]
 #[no_mangle]
-pub unsafe extern "C" fn sp_bitvec_is_empty(bit_vec: *const SPBitVec) -> bool {
-    assert!(!bit_vec.is_null());
-    unsafe { (*bit_vec).0.is_empty() }
+pub unsafe extern "C" fn sp_bitvec_is_empty(
+    bit_vec: NonNull<SPBitVec>,
+) -> bool {
+    unsafe { bit_vec.as_ref().0.is_empty() }
 }
 
 /// Gets an unsafe reference to the data of the [SPBitVec] instance.
@@ -272,8 +258,7 @@ pub unsafe extern "C" fn sp_bitvec_is_empty(bit_vec: *const SPBitVec) -> bool {
 /// - the returned memory range is never accessed concurrently, either via the [SPBitVec] or directly
 #[no_mangle]
 pub unsafe extern "C" fn sp_bitvec_unsafe_data_ref(
-    bit_vec: *mut SPBitVec,
+    bit_vec: NonNull<SPBitVec>,
 ) -> SPByteSlice {
-    assert!(!bit_vec.is_null());
-    unsafe { SPByteSlice::from_slice((*bit_vec).0.as_raw_mut_slice() ) }
+    unsafe { SPByteSlice::from_slice((*bit_vec.as_ptr()).0.as_raw_mut_slice()) }
 }
diff --git a/src/brightness_grid.rs b/src/brightness_grid.rs
index 4620a7d..c6abbb4 100644
--- a/src/brightness_grid.rs
+++ b/src/brightness_grid.rs
@@ -32,7 +32,6 @@ pub const SP_BRIGHTNESS_MAX: u8 = 11;
 /// Count of possible brightness values
 pub const SP_BRIGHTNESS_LEVELS: u8 = 12;
 
-
 /// Creates a new [SPBrightnessGrid] with the specified dimensions.
 ///
 /// returns: [SPBrightnessGrid] initialized to 0. Will never return NULL.
@@ -48,9 +47,7 @@ pub unsafe extern "C" fn sp_brightness_grid_new(
     width: usize,
     height: usize,
 ) -> NonNull<BrightnessGrid> {
-    let result = Box::new(servicepoint::BrightnessGrid::new(
-        width, height,
-    ));
+    let result = Box::new(BrightnessGrid::new(width, height));
     NonNull::from(Box::leak(result))
 }
 
@@ -75,16 +72,14 @@ pub unsafe extern "C" fn sp_brightness_grid_new(
 pub unsafe extern "C" fn sp_brightness_grid_load(
     width: usize,
     height: usize,
-    data: *const u8,
-    data_length: usize,
+    data: SPByteSlice,
 ) -> *mut BrightnessGrid {
-    assert!(!data.is_null());
-    let data = unsafe { std::slice::from_raw_parts(data, data_length) };
+    let data = unsafe { data.as_slice() };
     let grid = match servicepoint::ByteGrid::load(width, height, data) {
         None => return std::ptr::null_mut(),
         Some(grid) => grid,
     };
-    if let Ok(grid) = servicepoint::BrightnessGrid::try_from(grid) {
+    if let Ok(grid) = BrightnessGrid::try_from(grid) {
         Box::leak(Box::new(grid))
     } else {
         std::ptr::null_mut()
@@ -113,10 +108,9 @@ pub unsafe extern "C" fn sp_brightness_grid_load(
 ///   by explicitly calling `sp_brightness_grid_free`.
 #[no_mangle]
 pub unsafe extern "C" fn sp_brightness_grid_clone(
-    brightness_grid: *const BrightnessGrid,
+    brightness_grid: NonNull<BrightnessGrid>,
 ) -> NonNull<BrightnessGrid> {
-    assert!(!brightness_grid.is_null());
-    let result = Box::new(unsafe { (*brightness_grid).clone() });
+    let result = Box::new(unsafe { brightness_grid.as_ref().clone() });
     NonNull::from(Box::leak(result))
 }
 
@@ -141,10 +135,9 @@ pub unsafe extern "C" fn sp_brightness_grid_clone(
 /// [SPCommand]: [crate::SPCommand]
 #[no_mangle]
 pub unsafe extern "C" fn sp_brightness_grid_free(
-    brightness_grid: *mut BrightnessGrid,
+    brightness_grid: NonNull<BrightnessGrid>,
 ) {
-    assert!(!brightness_grid.is_null());
-    _ = unsafe { Box::from_raw(brightness_grid) };
+    _ = unsafe { Box::from_raw(brightness_grid.as_ptr()) };
 }
 
 /// Gets the current value at the specified position.
@@ -169,12 +162,11 @@ pub unsafe extern "C" fn sp_brightness_grid_free(
 /// - `brightness_grid` is not written to concurrently
 #[no_mangle]
 pub unsafe extern "C" fn sp_brightness_grid_get(
-    brightness_grid: *const BrightnessGrid,
+    brightness_grid: NonNull<BrightnessGrid>,
     x: usize,
     y: usize,
 ) -> u8 {
-    assert!(!brightness_grid.is_null());
-    unsafe { (*brightness_grid).get(x, y) }.into()
+    unsafe { brightness_grid.as_ref().get(x, y) }.into()
 }
 
 /// Sets the value of the specified position in the [SPBrightnessGrid].
@@ -201,15 +193,14 @@ pub unsafe extern "C" fn sp_brightness_grid_get(
 /// - `brightness_grid` is not written to or read from concurrently
 #[no_mangle]
 pub unsafe extern "C" fn sp_brightness_grid_set(
-    brightness_grid: *mut BrightnessGrid,
+    brightness_grid: NonNull<BrightnessGrid>,
     x: usize,
     y: usize,
     value: u8,
 ) {
-    assert!(!brightness_grid.is_null());
     let brightness = servicepoint::Brightness::try_from(value)
         .expect("invalid brightness value");
-    unsafe { (*brightness_grid).set(x, y, brightness) };
+    unsafe { (*brightness_grid.as_ptr()).set(x, y, brightness) };
 }
 
 /// Sets the value of all cells in the [SPBrightnessGrid].
@@ -232,13 +223,12 @@ pub unsafe extern "C" fn sp_brightness_grid_set(
 /// - `brightness_grid` is not written to or read from concurrently
 #[no_mangle]
 pub unsafe extern "C" fn sp_brightness_grid_fill(
-    brightness_grid: *mut BrightnessGrid,
+    brightness_grid: NonNull<BrightnessGrid>,
     value: u8,
 ) {
-    assert!(!brightness_grid.is_null());
     let brightness = servicepoint::Brightness::try_from(value)
         .expect("invalid brightness value");
-    unsafe { (*brightness_grid).fill(brightness) };
+    unsafe { (*brightness_grid.as_ptr()).fill(brightness) };
 }
 
 /// Gets the width of the [SPBrightnessGrid] instance.
@@ -260,10 +250,9 @@ pub unsafe extern "C" fn sp_brightness_grid_fill(
 /// - `brightness_grid` points to a valid [SPBrightnessGrid]
 #[no_mangle]
 pub unsafe extern "C" fn sp_brightness_grid_width(
-    brightness_grid: *const BrightnessGrid,
+    brightness_grid: NonNull<BrightnessGrid>,
 ) -> usize {
-    assert!(!brightness_grid.is_null());
-    unsafe { (*brightness_grid).width() }
+    unsafe { brightness_grid.as_ref().width() }
 }
 
 /// Gets the height of the [SPBrightnessGrid] instance.
@@ -285,10 +274,9 @@ pub unsafe extern "C" fn sp_brightness_grid_width(
 /// - `brightness_grid` points to a valid [SPBrightnessGrid]
 #[no_mangle]
 pub unsafe extern "C" fn sp_brightness_grid_height(
-    brightness_grid: *const BrightnessGrid,
+    brightness_grid: NonNull<BrightnessGrid>,
 ) -> usize {
-    assert!(!brightness_grid.is_null());
-    unsafe { (*brightness_grid).height() }
+    unsafe { brightness_grid.as_ref().height() }
 }
 
 /// Gets an unsafe reference to the data of the [SPBrightnessGrid] instance.
@@ -312,12 +300,10 @@ pub unsafe extern "C" fn sp_brightness_grid_height(
 /// - the returned memory range is never accessed concurrently, either via the [SPBrightnessGrid] or directly
 #[no_mangle]
 pub unsafe extern "C" fn sp_brightness_grid_unsafe_data_ref(
-    brightness_grid: *mut BrightnessGrid,
+    brightness_grid: NonNull<BrightnessGrid>,
 ) -> SPByteSlice {
-    assert!(!brightness_grid.is_null());
-    assert_eq!(core::mem::size_of::<servicepoint::Brightness>(), 1);
-    let data = unsafe { (*brightness_grid).data_ref_mut() };
+    assert_eq!(size_of::<servicepoint::Brightness>(), 1);
+    let data = unsafe { (*brightness_grid.as_ptr()).data_ref_mut() };
     // this assumes more about the memory layout than rust guarantees. yikes!
     unsafe { SPByteSlice::from_slice(transmute(data)) }
-
 }
diff --git a/src/byte_slice.rs b/src/byte_slice.rs
index a87c952..066a405 100644
--- a/src/byte_slice.rs
+++ b/src/byte_slice.rs
@@ -28,7 +28,7 @@ impl SPByteSlice {
         unsafe { std::slice::from_raw_parts(self.start.as_ptr(), self.length) }
     }
 
-    pub(crate) unsafe fn as_slice_mut(&mut self) -> &mut [u8] {
+    pub(crate) unsafe fn as_slice_mut(&self) -> &mut [u8] {
         unsafe {
             std::slice::from_raw_parts_mut(self.start.as_ptr(), self.length)
         }
diff --git a/src/char_grid.rs b/src/char_grid.rs
index 71013d5..a845f4e 100644
--- a/src/char_grid.rs
+++ b/src/char_grid.rs
@@ -18,6 +18,7 @@
 //! sp_char_grid_free(grid);
 //! ```
 
+use crate::SPByteSlice;
 use servicepoint::{CharGrid, Grid};
 use std::ptr::NonNull;
 
@@ -36,7 +37,7 @@ pub unsafe extern "C" fn sp_char_grid_new(
     width: usize,
     height: usize,
 ) -> NonNull<CharGrid> {
-    let result =        Box::new(CharGrid::new(width, height));
+    let result = Box::new(CharGrid::new(width, height));
     NonNull::from(Box::leak(result))
 }
 
@@ -62,16 +63,12 @@ pub unsafe extern "C" fn sp_char_grid_new(
 pub unsafe extern "C" fn sp_char_grid_load(
     width: usize,
     height: usize,
-    data: *const u8,
-    data_length: usize,
+    data: SPByteSlice,
 ) -> NonNull<CharGrid> {
-    assert!(data.is_null());
-    let data = unsafe { std::slice::from_raw_parts(data, data_length) };
+    let data = unsafe { data.as_slice() };
     // TODO remove unwrap
-    let result = Box::new(
-        CharGrid::load_utf8(width, height, data.to_vec())
-            .unwrap(),
-    );
+    let result =
+        Box::new(CharGrid::load_utf8(width, height, data.to_vec()).unwrap());
     NonNull::from(Box::leak(result))
 }
 
@@ -93,10 +90,9 @@ pub unsafe extern "C" fn sp_char_grid_load(
 ///   by explicitly calling `sp_char_grid_free`.
 #[no_mangle]
 pub unsafe extern "C" fn sp_char_grid_clone(
-    char_grid: *const CharGrid,
+    char_grid: NonNull<CharGrid>,
 ) -> NonNull<CharGrid> {
-    assert!(!char_grid.is_null());
-    let result = Box::new(unsafe { (*char_grid).clone() });
+    let result = Box::new(unsafe { char_grid.as_ref().clone() });
     NonNull::from(Box::leak(result))
 }
 
@@ -116,9 +112,8 @@ pub unsafe extern "C" fn sp_char_grid_clone(
 ///
 /// [SPCommand]: [crate::SPCommand]
 #[no_mangle]
-pub unsafe extern "C" fn sp_char_grid_free(char_grid: *mut CharGrid) {
-    assert!(!char_grid.is_null());
-    _ = unsafe { Box::from_raw(char_grid) };
+pub unsafe extern "C" fn sp_char_grid_free(char_grid: NonNull<CharGrid>) {
+    _ = unsafe { Box::from_raw(char_grid.as_ptr()) };
 }
 
 /// Gets the current value at the specified position.
@@ -141,12 +136,11 @@ pub unsafe extern "C" fn sp_char_grid_free(char_grid: *mut CharGrid) {
 /// - `char_grid` is not written to concurrently
 #[no_mangle]
 pub unsafe extern "C" fn sp_char_grid_get(
-    char_grid: *const CharGrid,
+    char_grid: NonNull<CharGrid>,
     x: usize,
     y: usize,
 ) -> u32 {
-    assert!(!char_grid.is_null());
-    unsafe { (*char_grid).get(x, y) as u32 }
+    unsafe { char_grid.as_ref().get(x, y) as u32 }
 }
 
 /// Sets the value of the specified position in the [SPCharGrid].
@@ -174,13 +168,12 @@ pub unsafe extern "C" fn sp_char_grid_get(
 /// [SPBitVec]: [crate::SPBitVec]
 #[no_mangle]
 pub unsafe extern "C" fn sp_char_grid_set(
-    char_grid: *mut CharGrid,
+    char_grid: NonNull<CharGrid>,
     x: usize,
     y: usize,
     value: u32,
 ) {
-    assert!(!char_grid.is_null());
-    unsafe { (*char_grid).set(x, y, char::from_u32(value).unwrap()) };
+    unsafe { (*char_grid.as_ptr()).set(x, y, char::from_u32(value).unwrap()) };
 }
 
 /// Sets the value of all cells in the [SPCharGrid].
@@ -202,11 +195,10 @@ pub unsafe extern "C" fn sp_char_grid_set(
 /// - `char_grid` is not written to or read from concurrently
 #[no_mangle]
 pub unsafe extern "C" fn sp_char_grid_fill(
-    char_grid: *mut CharGrid,
+    char_grid: NonNull<CharGrid>,
     value: u32,
 ) {
-    assert!(!char_grid.is_null());
-    unsafe { (*char_grid).fill(char::from_u32(value).unwrap()) };
+    unsafe { (*char_grid.as_ptr()).fill(char::from_u32(value).unwrap()) };
 }
 
 /// Gets the width of the [SPCharGrid] instance.
@@ -226,10 +218,9 @@ pub unsafe extern "C" fn sp_char_grid_fill(
 /// - `char_grid` points to a valid [SPCharGrid]
 #[no_mangle]
 pub unsafe extern "C" fn sp_char_grid_width(
-    char_grid: *const CharGrid,
+    char_grid: NonNull<CharGrid>,
 ) -> usize {
-    assert!(!char_grid.is_null());
-    unsafe { (*char_grid).width() }
+    unsafe { char_grid.as_ref().width() }
 }
 
 /// Gets the height of the [SPCharGrid] instance.
@@ -249,8 +240,7 @@ pub unsafe extern "C" fn sp_char_grid_width(
 /// - `char_grid` points to a valid [SPCharGrid]
 #[no_mangle]
 pub unsafe extern "C" fn sp_char_grid_height(
-    char_grid: *const CharGrid,
+    char_grid: NonNull<CharGrid>,
 ) -> usize {
-    assert!(!char_grid.is_null());
-    unsafe { (*char_grid).height() }
+    unsafe { char_grid.as_ref().height() }
 }
diff --git a/src/command.rs b/src/command.rs
index a4a2736..eccac1b 100644
--- a/src/command.rs
+++ b/src/command.rs
@@ -2,8 +2,11 @@
 //!
 //! prefix `sp_command_`
 
-use crate::{SPBitVec};
-use servicepoint::{BinaryOperation, BrightnessGrid, CharGrid, CompressionCode, Cp437Grid, GlobalBrightnessCommand, Packet, TypedCommand};
+use crate::SPBitVec;
+use servicepoint::{
+    BinaryOperation, Bitmap, BrightnessGrid, CharGrid, CompressionCode,
+    Cp437Grid, GlobalBrightnessCommand, Packet, TypedCommand,
+};
 use std::ptr::NonNull;
 
 /// A low-level display command.
@@ -21,7 +24,6 @@ use std::ptr::NonNull;
 ///
 /// [SPConnection]: [crate::SPConnection]
 
-
 /// Tries to turn a [SPPacket] into a [SPCommand].
 ///
 /// The packet is deallocated in the process.
@@ -43,9 +45,9 @@ use std::ptr::NonNull;
 ///   by explicitly calling `sp_command_free`.
 #[no_mangle]
 pub unsafe extern "C" fn sp_command_try_from_packet(
-    packet: *mut Packet,
+    packet: NonNull<Packet>,
 ) -> *mut TypedCommand {
-    let packet = *unsafe { Box::from_raw(packet) };
+    let packet = *unsafe { Box::from_raw(packet.as_ptr()) };
     match servicepoint::TypedCommand::try_from(packet) {
         Err(_) => std::ptr::null_mut(),
         Ok(command) => Box::into_raw(Box::new(command)),
@@ -70,10 +72,9 @@ pub unsafe extern "C" fn sp_command_try_from_packet(
 ///   by explicitly calling `sp_command_free`.
 #[no_mangle]
 pub unsafe extern "C" fn sp_command_clone(
-    command: *const TypedCommand,
+    command: NonNull<TypedCommand>,
 ) -> NonNull<TypedCommand> {
-    assert!(!command.is_null());
-    let result = Box::new(unsafe { (*command).clone() });
+    let result = Box::new(unsafe { command.as_ref().clone() });
     NonNull::from(Box::leak(result))
 }
 
@@ -155,8 +156,7 @@ pub unsafe extern "C" fn sp_command_brightness(
 ) -> NonNull<TypedCommand> {
     let brightness = servicepoint::Brightness::try_from(brightness)
         .expect("invalid brightness");
-    let result =
-        Box::new(GlobalBrightnessCommand::from(brightness).into());
+    let result = Box::new(GlobalBrightnessCommand::from(brightness).into());
     NonNull::from(Box::leak(result))
 }
 
@@ -182,10 +182,9 @@ pub unsafe extern "C" fn sp_command_brightness(
 pub unsafe extern "C" fn sp_command_char_brightness(
     x: usize,
     y: usize,
-    grid: *mut BrightnessGrid,
+    grid: NonNull<BrightnessGrid>,
 ) -> NonNull<TypedCommand> {
-    assert!(!grid.is_null());
-    let grid = unsafe { *Box::from_raw(grid) };
+    let grid = unsafe { *Box::from_raw(grid.as_ptr()) };
     let result = Box::new(
         servicepoint::BrightnessGridCommand {
             origin: servicepoint::Origin::new(x, y),
@@ -224,7 +223,7 @@ pub unsafe extern "C" fn sp_command_char_brightness(
 #[no_mangle]
 pub unsafe extern "C" fn sp_command_bitmap_linear(
     offset: usize,
-    bit_vec: *mut SPBitVec,
+    bit_vec: NonNull<SPBitVec>,
     compression: CompressionCode,
 ) -> *mut TypedCommand {
     unsafe {
@@ -265,7 +264,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear(
 #[no_mangle]
 pub unsafe extern "C" fn sp_command_bitmap_linear_and(
     offset: usize,
-    bit_vec: *mut SPBitVec,
+    bit_vec: NonNull<SPBitVec>,
     compression: CompressionCode,
 ) -> *mut TypedCommand {
     unsafe {
@@ -306,7 +305,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_and(
 #[no_mangle]
 pub unsafe extern "C" fn sp_command_bitmap_linear_or(
     offset: usize,
-    bit_vec: *mut SPBitVec,
+    bit_vec: NonNull<SPBitVec>,
     compression: CompressionCode,
 ) -> *mut TypedCommand {
     unsafe {
@@ -347,7 +346,7 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_or(
 #[no_mangle]
 pub unsafe extern "C" fn sp_command_bitmap_linear_xor(
     offset: usize,
-    bit_vec: *mut SPBitVec,
+    bit_vec: NonNull<SPBitVec>,
     compression: CompressionCode,
 ) -> *mut TypedCommand {
     unsafe {
@@ -363,23 +362,22 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_xor(
 #[inline]
 unsafe fn sp_command_bitmap_linear_internal(
     offset: usize,
-    bit_vec: *mut SPBitVec,
+    bit_vec: NonNull<SPBitVec>,
     compression: CompressionCode,
     operation: BinaryOperation,
 ) -> *mut TypedCommand {
-    assert!(!bit_vec.is_null());
-    let bit_vec = unsafe { *Box::from_raw(bit_vec) };
+    let bit_vec = unsafe { *Box::from_raw(bit_vec.as_ptr()) };
     let compression = match compression.try_into() {
         Ok(compression) => compression,
         Err(_) => return std::ptr::null_mut(),
     };
-    let command =         servicepoint::BitVecCommand {
-            offset,
-            operation,
-            bitvec: bit_vec.into(),
-            compression,
-        }
-        .into();
+    let command = servicepoint::BitVecCommand {
+        offset,
+        operation,
+        bitvec: bit_vec.0,
+        compression,
+    }
+    .into();
     Box::leak(Box::new(command))
 }
 
@@ -405,10 +403,9 @@ unsafe fn sp_command_bitmap_linear_internal(
 pub unsafe extern "C" fn sp_command_cp437_data(
     x: usize,
     y: usize,
-    grid: *mut Cp437Grid,
+    grid: NonNull<Cp437Grid>,
 ) -> NonNull<TypedCommand> {
-    assert!(!grid.is_null());
-    let grid = *unsafe { Box::from_raw(grid) };
+    let grid = *unsafe { Box::from_raw(grid.as_ptr()) };
     let result = Box::new(
         servicepoint::Cp437GridCommand {
             origin: servicepoint::Origin::new(x, y),
@@ -441,10 +438,9 @@ pub unsafe extern "C" fn sp_command_cp437_data(
 pub unsafe extern "C" fn sp_command_utf8_data(
     x: usize,
     y: usize,
-    grid: *mut CharGrid,
+    grid: NonNull<CharGrid>,
 ) -> NonNull<TypedCommand> {
-    assert!(!grid.is_null());
-    let grid = unsafe { *Box::from_raw(grid) };
+    let grid = unsafe { *Box::from_raw(grid.as_ptr()) };
     let result = Box::new(
         servicepoint::CharGridCommand {
             origin: servicepoint::Origin::new(x, y),
@@ -479,21 +475,20 @@ pub unsafe extern "C" fn sp_command_utf8_data(
 pub unsafe extern "C" fn sp_command_bitmap_linear_win(
     x: usize,
     y: usize,
-    bitmap: *mut servicepoint::Bitmap,
+    bitmap: NonNull<Bitmap>,
     compression: CompressionCode,
 ) -> *mut TypedCommand {
-    assert!(!bitmap.is_null());
-    let bitmap = unsafe { *Box::from_raw(bitmap) };
+    let bitmap = unsafe { *Box::from_raw(bitmap.as_ptr()) };
     let compression = match compression.try_into() {
         Ok(compression) => compression,
         Err(_) => return std::ptr::null_mut(),
     };
-    let command =         servicepoint::BitmapCommand {
-            origin: servicepoint::Origin::new(x, y),
-            bitmap,
-            compression,
-        }
-        .into();
+    let command = servicepoint::BitmapCommand {
+        origin: servicepoint::Origin::new(x, y),
+        bitmap,
+        compression,
+    }
+    .into();
     Box::leak(Box::new(command))
 }
 
@@ -518,7 +513,6 @@ pub unsafe extern "C" fn sp_command_bitmap_linear_win(
 /// - `command` is not used concurrently or after this call
 /// - `command` was not passed to another consuming function, e.g. to create a [SPPacket]
 #[no_mangle]
-pub unsafe extern "C" fn sp_command_free(command: *mut TypedCommand) {
-    assert!(!command.is_null());
-    _ = unsafe { Box::from_raw(command) };
+pub unsafe extern "C" fn sp_command_free(command: NonNull<TypedCommand>) {
+    _ = unsafe { Box::from_raw(command.as_ptr()) };
 }
diff --git a/src/connection.rs b/src/connection.rs
index 9458727..1705538 100644
--- a/src/connection.rs
+++ b/src/connection.rs
@@ -14,6 +14,7 @@
 
 use servicepoint::{Connection, Packet, TypedCommand, UdpConnection};
 use std::ffi::{c_char, CStr};
+use std::ptr::NonNull;
 
 /// Creates a new instance of [SPConnection].
 ///
@@ -31,10 +32,9 @@ use std::ffi::{c_char, CStr};
 ///   by explicitly calling `sp_connection_free`.
 #[no_mangle]
 pub unsafe extern "C" fn sp_connection_open(
-    host: *const c_char,
+    host: NonNull<c_char>,
 ) -> *mut UdpConnection {
-    assert!(!host.is_null());
-    let host = unsafe { CStr::from_ptr(host) }
+    let host = unsafe { CStr::from_ptr(host.as_ptr()) }
         .to_str()
         .expect("Bad encoding");
     let connection = match UdpConnection::open(host) {
@@ -93,13 +93,11 @@ pub unsafe extern "C" fn sp_connection_open(
 /// - `packet` is not used concurrently or after this call
 #[no_mangle]
 pub unsafe extern "C" fn sp_connection_send_packet(
-    connection: *const UdpConnection,
-    packet: *mut Packet,
+    connection: NonNull<UdpConnection>,
+    packet: NonNull<Packet>,
 ) -> bool {
-    assert!(!connection.is_null());
-    assert!(!packet.is_null());
-    let packet = unsafe { Box::from_raw(packet) };
-    unsafe { (*connection).send(*packet) }.is_ok()
+    let packet = unsafe { Box::from_raw(packet.as_ptr()) };
+    unsafe { connection.as_ref().send(*packet) }.is_ok()
 }
 
 /// Sends a [SPCommand] to the display using the [SPConnection].
@@ -122,13 +120,11 @@ pub unsafe extern "C" fn sp_connection_send_packet(
 /// - `command` is not used concurrently or after this call
 #[no_mangle]
 pub unsafe extern "C" fn sp_connection_send_command(
-    connection: *const UdpConnection,
-    command: *mut TypedCommand,
+    connection: NonNull<UdpConnection>,
+    command: NonNull<TypedCommand>,
 ) -> bool {
-    assert!(!connection.is_null());
-    assert!(!command.is_null());
-    let command = *unsafe { Box::from_raw(command) };
-    unsafe { (*connection).send(command) }.is_ok()
+    let command = *unsafe { Box::from_raw(command.as_ptr()) };
+    unsafe { connection.as_ref().send(command) }.is_ok()
 }
 
 /// Closes and deallocates a [SPConnection].
@@ -144,7 +140,8 @@ pub unsafe extern "C" fn sp_connection_send_command(
 /// - `connection` points to a valid [SPConnection]
 /// - `connection` is not used concurrently or after this call
 #[no_mangle]
-pub unsafe extern "C" fn sp_connection_free(connection: *mut UdpConnection) {
-    assert!(!connection.is_null());
-    _ = unsafe { Box::from_raw(connection) };
+pub unsafe extern "C" fn sp_connection_free(
+    connection: NonNull<UdpConnection>,
+) {
+    _ = unsafe { Box::from_raw(connection.as_ptr()) };
 }
diff --git a/src/cp437_grid.rs b/src/cp437_grid.rs
index 2ec009d..e635247 100644
--- a/src/cp437_grid.rs
+++ b/src/cp437_grid.rs
@@ -35,7 +35,7 @@ pub unsafe extern "C" fn sp_cp437_grid_new(
     width: usize,
     height: usize,
 ) -> NonNull<Cp437Grid> {
-    let result =        Box::new(Cp437Grid::new(width, height));
+    let result = Box::new(Cp437Grid::new(width, height));
     NonNull::from(Box::leak(result))
 }
 
@@ -60,11 +60,9 @@ pub unsafe extern "C" fn sp_cp437_grid_new(
 pub unsafe extern "C" fn sp_cp437_grid_load(
     width: usize,
     height: usize,
-    data: *const u8,
-    data_length: usize,
+    data: SPByteSlice,
 ) -> *mut Cp437Grid {
-    assert!(data.is_null());
-    let data = unsafe { std::slice::from_raw_parts(data, data_length) };
+    let data = unsafe { data.as_slice() };
     let grid = Cp437Grid::load(width, height, data);
     if let Some(grid) = grid {
         Box::leak(Box::new(grid))
@@ -91,10 +89,9 @@ pub unsafe extern "C" fn sp_cp437_grid_load(
 ///   by explicitly calling `sp_cp437_grid_free`.
 #[no_mangle]
 pub unsafe extern "C" fn sp_cp437_grid_clone(
-    cp437_grid: *const Cp437Grid,
+    cp437_grid: NonNull<Cp437Grid>,
 ) -> NonNull<Cp437Grid> {
-    assert!(!cp437_grid.is_null());
-    let result = Box::new(unsafe { (*cp437_grid).clone() });
+    let result = Box::new(unsafe { cp437_grid.as_ref().clone() });
     NonNull::from(Box::leak(result))
 }
 
@@ -114,9 +111,8 @@ pub unsafe extern "C" fn sp_cp437_grid_clone(
 ///
 /// [SPCommand]: [crate::SPCommand]
 #[no_mangle]
-pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: *mut Cp437Grid) {
-    assert!(!cp437_grid.is_null());
-    _ = unsafe { Box::from_raw(cp437_grid) };
+pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: NonNull<Cp437Grid>) {
+    _ = unsafe { Box::from_raw(cp437_grid.as_ptr()) };
 }
 
 /// Gets the current value at the specified position.
@@ -139,12 +135,11 @@ pub unsafe extern "C" fn sp_cp437_grid_free(cp437_grid: *mut Cp437Grid) {
 /// - `cp437_grid` is not written to concurrently
 #[no_mangle]
 pub unsafe extern "C" fn sp_cp437_grid_get(
-    cp437_grid: *const Cp437Grid,
+    cp437_grid: NonNull<Cp437Grid>,
     x: usize,
     y: usize,
 ) -> u8 {
-    assert!(!cp437_grid.is_null());
-    unsafe { (*cp437_grid).get(x, y) }
+    unsafe { cp437_grid.as_ref().get(x, y) }
 }
 
 /// Sets the value of the specified position in the [SPCp437Grid].
@@ -172,13 +167,12 @@ pub unsafe extern "C" fn sp_cp437_grid_get(
 /// [SPBitVec]: [crate::SPBitVec]
 #[no_mangle]
 pub unsafe extern "C" fn sp_cp437_grid_set(
-    cp437_grid: *mut Cp437Grid,
+    cp437_grid: NonNull<Cp437Grid>,
     x: usize,
     y: usize,
     value: u8,
 ) {
-    assert!(!cp437_grid.is_null());
-    unsafe { (*cp437_grid).set(x, y, value) };
+    unsafe { (*cp437_grid.as_ptr()).set(x, y, value) };
 }
 
 /// Sets the value of all cells in the [SPCp437Grid].
@@ -200,11 +194,10 @@ pub unsafe extern "C" fn sp_cp437_grid_set(
 /// - `cp437_grid` is not written to or read from concurrently
 #[no_mangle]
 pub unsafe extern "C" fn sp_cp437_grid_fill(
-    cp437_grid: *mut Cp437Grid,
+    cp437_grid: NonNull<Cp437Grid>,
     value: u8,
 ) {
-    assert!(!cp437_grid.is_null());
-    unsafe { (*cp437_grid).fill(value) };
+    unsafe { (*cp437_grid.as_ptr()).fill(value) };
 }
 
 /// Gets the width of the [SPCp437Grid] instance.
@@ -224,10 +217,9 @@ pub unsafe extern "C" fn sp_cp437_grid_fill(
 /// - `cp437_grid` points to a valid [SPCp437Grid]
 #[no_mangle]
 pub unsafe extern "C" fn sp_cp437_grid_width(
-    cp437_grid: *const Cp437Grid,
+    cp437_grid: NonNull<Cp437Grid>,
 ) -> usize {
-    assert!(!cp437_grid.is_null());
-    unsafe { (*cp437_grid).width() }
+    unsafe { cp437_grid.as_ref().width() }
 }
 
 /// Gets the height of the [SPCp437Grid] instance.
@@ -247,10 +239,9 @@ pub unsafe extern "C" fn sp_cp437_grid_width(
 /// - `cp437_grid` points to a valid [SPCp437Grid]
 #[no_mangle]
 pub unsafe extern "C" fn sp_cp437_grid_height(
-    cp437_grid: *const Cp437Grid,
+    cp437_grid: NonNull<Cp437Grid>,
 ) -> usize {
-    assert!(!cp437_grid.is_null());
-    unsafe { (*cp437_grid).height() }
+    unsafe { cp437_grid.as_ref().height() }
 }
 
 /// Gets an unsafe reference to the data of the [SPCp437Grid] instance.
@@ -270,7 +261,7 @@ pub unsafe extern "C" fn sp_cp437_grid_height(
 /// - the returned memory range is never accessed concurrently, either via the [SPCp437Grid] or directly
 #[no_mangle]
 pub unsafe extern "C" fn sp_cp437_grid_unsafe_data_ref(
-    cp437_grid: *mut Cp437Grid,
+    cp437_grid: NonNull<Cp437Grid>,
 ) -> SPByteSlice {
-    unsafe {SPByteSlice::from_slice((*cp437_grid).data_ref_mut()) }
+    unsafe { SPByteSlice::from_slice((*cp437_grid.as_ptr()).data_ref_mut()) }
 }
diff --git a/src/lib.rs b/src/lib.rs
index d00e579..831daea 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -45,7 +45,6 @@ mod connection;
 mod cp437_grid;
 mod packet;
 
-
 use std::time::Duration;
 
 /// Actual hardware limit is around 28-29ms/frame. Rounded up for less dropped packets.
diff --git a/src/packet.rs b/src/packet.rs
index 71bbbae..f8235ab 100644
--- a/src/packet.rs
+++ b/src/packet.rs
@@ -28,10 +28,9 @@ use std::ptr::NonNull;
 ///   by explicitly calling `sp_packet_free`.
 #[no_mangle]
 pub unsafe extern "C" fn sp_packet_from_command(
-    command: *mut TypedCommand,
+    command: NonNull<TypedCommand>,
 ) -> *mut Packet {
-    assert!(!command.is_null());
-    let command = unsafe { *Box::from_raw(command) };
+    let command = unsafe { *Box::from_raw(command.as_ptr()) };
     if let Ok(packet) = command.try_into() {
         Box::leak(Box::new(packet))
     } else {
@@ -56,12 +55,8 @@ pub unsafe extern "C" fn sp_packet_from_command(
 /// - the returned [SPPacket] instance is freed in some way, either by using a consuming function or
 ///   by explicitly calling `sp_packet_free`.
 #[no_mangle]
-pub unsafe extern "C" fn sp_packet_try_load(
-    data: *const u8,
-    length: usize,
-) -> *mut Packet {
-    assert!(!data.is_null());
-    let data = unsafe { std::slice::from_raw_parts(data, length) };
+pub unsafe extern "C" fn sp_packet_try_load(data: SPByteSlice) -> *mut Packet {
+    let data = unsafe { data.as_slice() };
     match servicepoint::Packet::try_from(data) {
         Err(_) => std::ptr::null_mut(),
         Ok(packet) => Box::into_raw(Box::new(packet)),
@@ -95,16 +90,12 @@ pub unsafe extern "C" fn sp_packet_try_load(
 #[no_mangle]
 pub unsafe extern "C" fn sp_packet_from_parts(
     header: Header,
-    payload: *const u8,
-    payload_len: usize,
+    payload: *const SPByteSlice,
 ) -> NonNull<Packet> {
-    assert_eq!(payload.is_null(), payload_len == 0);
-
     let payload = if payload.is_null() {
         vec![]
     } else {
-        let payload =
-            unsafe { std::slice::from_raw_parts(payload, payload_len) };
+        let payload = unsafe { (*payload).as_slice() };
         Vec::from(payload)
     };
 
@@ -113,34 +104,34 @@ pub unsafe extern "C" fn sp_packet_from_parts(
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn sp_packet_get_header(packet: *mut Packet) -> *mut Header {
-    assert!(!packet.is_null());
-    &mut unsafe { (*packet).header }
+pub unsafe extern "C" fn sp_packet_get_header(
+    packet: NonNull<Packet>,
+) -> NonNull<Header> {
+    NonNull::from(&mut unsafe { (*packet.as_ptr()).header })
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn sp_packet_get_payload(packet: *mut Packet) -> SPByteSlice {
-    assert!(!packet.is_null());
-    unsafe { SPByteSlice::from_slice(&mut *(*packet).payload) }
+pub unsafe extern "C" fn sp_packet_get_payload(
+    packet: NonNull<Packet>,
+) -> SPByteSlice {
+    unsafe { SPByteSlice::from_slice(&mut *(*packet.as_ptr()).payload) }
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn sp_packet_set_payload(packet: *mut Packet, data: SPByteSlice) {
-    assert!(!packet.is_null());
-    unsafe {
-        (*packet).payload = data.as_slice().to_vec()
-    }
+pub unsafe extern "C" fn sp_packet_set_payload(
+    packet: NonNull<Packet>,
+    data: SPByteSlice,
+) {
+    unsafe { (*packet.as_ptr()).payload = data.as_slice().to_vec() }
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn sp_packet_write_to(
-    packet: *const Packet,
-    mut buffer: SPByteSlice,
+    packet: NonNull<Packet>,
+    buffer: SPByteSlice,
 ) {
-    assert!(!packet.is_null());
-
     unsafe {
-        (*packet).serialize_to(buffer.as_slice_mut());
+        packet.as_ref().serialize_to(buffer.as_slice_mut());
     }
 }
 
@@ -162,10 +153,9 @@ pub unsafe extern "C" fn sp_packet_write_to(
 ///   by explicitly calling `sp_packet_free`.
 #[no_mangle]
 pub unsafe extern "C" fn sp_packet_clone(
-    packet: *const Packet,
+    packet: NonNull<Packet>,
 ) -> NonNull<Packet> {
-    assert!(!packet.is_null());
-    let result = Box::new(unsafe { (*packet).clone() });
+    let result = Box::new(unsafe { packet.as_ref().clone() });
     NonNull::from(Box::leak(result))
 }
 
@@ -182,7 +172,6 @@ pub unsafe extern "C" fn sp_packet_clone(
 /// - `packet` points to a valid [SPPacket]
 /// - `packet` is not used concurrently or after this call
 #[no_mangle]
-pub unsafe extern "C" fn sp_packet_free(packet: *mut Packet) {
-    assert!(!packet.is_null());
-    _ = unsafe { Box::from_raw(packet) }
+pub unsafe extern "C" fn sp_packet_free(packet: NonNull<Packet>) {
+    _ = unsafe { Box::from_raw(packet.as_ptr()) }
 }