Program Listing for File schemas.cpp

Return to documentation for file (foxglove/src/schemas.cpp)

// Generated by https://github.com/foxglove/foxglove-sdk

#include <foxglove-c/foxglove-c.h>
#include <foxglove/arena.hpp>
#include <foxglove/context.hpp>
#include <foxglove/error.hpp>
#include <foxglove/schemas.hpp>

#include <cstring>
#include <optional>

namespace foxglove::schemas {

void ChannelDeleter::operator()(const foxglove_channel* ptr) const noexcept {
  foxglove_channel_free(ptr);
};

void arrowPrimitiveToC(foxglove_arrow_primitive& dest, const ArrowPrimitive& src, Arena& arena);
void cameraCalibrationToC(
  foxglove_camera_calibration& dest, const CameraCalibration& src, Arena& arena
);
void circleAnnotationToC(
  foxglove_circle_annotation& dest, const CircleAnnotation& src, Arena& arena
);
void compressedImageToC(foxglove_compressed_image& dest, const CompressedImage& src, Arena& arena);
void compressedVideoToC(foxglove_compressed_video& dest, const CompressedVideo& src, Arena& arena);
void cubePrimitiveToC(foxglove_cube_primitive& dest, const CubePrimitive& src, Arena& arena);
void cylinderPrimitiveToC(
  foxglove_cylinder_primitive& dest, const CylinderPrimitive& src, Arena& arena
);
void frameTransformToC(foxglove_frame_transform& dest, const FrameTransform& src, Arena& arena);
void frameTransformsToC(foxglove_frame_transforms& dest, const FrameTransforms& src, Arena& arena);
void geoJSONToC(foxglove_geo_json& dest, const GeoJSON& src, Arena& arena);
void gridToC(foxglove_grid& dest, const Grid& src, Arena& arena);
void imageAnnotationsToC(
  foxglove_image_annotations& dest, const ImageAnnotations& src, Arena& arena
);
void keyValuePairToC(foxglove_key_value_pair& dest, const KeyValuePair& src, Arena& arena);
void laserScanToC(foxglove_laser_scan& dest, const LaserScan& src, Arena& arena);
void linePrimitiveToC(foxglove_line_primitive& dest, const LinePrimitive& src, Arena& arena);
void locationFixToC(foxglove_location_fix& dest, const LocationFix& src, Arena& arena);
void logToC(foxglove_log& dest, const Log& src, Arena& arena);
void modelPrimitiveToC(foxglove_model_primitive& dest, const ModelPrimitive& src, Arena& arena);
void packedElementFieldToC(
  foxglove_packed_element_field& dest, const PackedElementField& src, Arena& arena
);
void pointCloudToC(foxglove_point_cloud& dest, const PointCloud& src, Arena& arena);
void pointsAnnotationToC(
  foxglove_points_annotation& dest, const PointsAnnotation& src, Arena& arena
);
void poseToC(foxglove_pose& dest, const Pose& src, Arena& arena);
void poseInFrameToC(foxglove_pose_in_frame& dest, const PoseInFrame& src, Arena& arena);
void posesInFrameToC(foxglove_poses_in_frame& dest, const PosesInFrame& src, Arena& arena);
void rawAudioToC(foxglove_raw_audio& dest, const RawAudio& src, Arena& arena);
void rawImageToC(foxglove_raw_image& dest, const RawImage& src, Arena& arena);
void sceneEntityToC(foxglove_scene_entity& dest, const SceneEntity& src, Arena& arena);
void sceneEntityDeletionToC(
  foxglove_scene_entity_deletion& dest, const SceneEntityDeletion& src, Arena& arena
);
void sceneUpdateToC(foxglove_scene_update& dest, const SceneUpdate& src, Arena& arena);
void spherePrimitiveToC(foxglove_sphere_primitive& dest, const SpherePrimitive& src, Arena& arena);
void textAnnotationToC(foxglove_text_annotation& dest, const TextAnnotation& src, Arena& arena);
void textPrimitiveToC(foxglove_text_primitive& dest, const TextPrimitive& src, Arena& arena);
void triangleListPrimitiveToC(
  foxglove_triangle_list_primitive& dest, const TriangleListPrimitive& src, Arena& arena
);

FoxgloveResult<ArrowPrimitiveChannel> ArrowPrimitiveChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_arrow_primitive(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return ArrowPrimitiveChannel(ChannelUniquePtr(channel));
}

FoxgloveError ArrowPrimitiveChannel::log(
  const ArrowPrimitive& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_arrow_primitive c_msg;
  arrowPrimitiveToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_arrow_primitive(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t ArrowPrimitiveChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<CameraCalibrationChannel> CameraCalibrationChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_camera_calibration(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return CameraCalibrationChannel(ChannelUniquePtr(channel));
}

FoxgloveError CameraCalibrationChannel::log(
  const CameraCalibration& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_camera_calibration c_msg;
  cameraCalibrationToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_camera_calibration(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t CameraCalibrationChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<CircleAnnotationChannel> CircleAnnotationChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_circle_annotation(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return CircleAnnotationChannel(ChannelUniquePtr(channel));
}

FoxgloveError CircleAnnotationChannel::log(
  const CircleAnnotation& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_circle_annotation c_msg;
  circleAnnotationToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_circle_annotation(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t CircleAnnotationChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<ColorChannel> ColorChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error =
    foxglove_channel_create_color({topic.data(), topic.size()}, context.getInner(), &channel);
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return ColorChannel(ChannelUniquePtr(channel));
}

FoxgloveError ColorChannel::log(const Color& msg, std::optional<uint64_t> log_time) noexcept {
  return FoxgloveError(foxglove_channel_log_color(
    impl_.get(), reinterpret_cast<const foxglove_color*>(&msg), log_time ? &*log_time : nullptr
  ));
}

uint64_t ColorChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<CompressedImageChannel> CompressedImageChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_compressed_image(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return CompressedImageChannel(ChannelUniquePtr(channel));
}

FoxgloveError CompressedImageChannel::log(
  const CompressedImage& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_compressed_image c_msg;
  compressedImageToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_compressed_image(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t CompressedImageChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<CompressedVideoChannel> CompressedVideoChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_compressed_video(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return CompressedVideoChannel(ChannelUniquePtr(channel));
}

FoxgloveError CompressedVideoChannel::log(
  const CompressedVideo& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_compressed_video c_msg;
  compressedVideoToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_compressed_video(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t CompressedVideoChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<CubePrimitiveChannel> CubePrimitiveChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_cube_primitive(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return CubePrimitiveChannel(ChannelUniquePtr(channel));
}

FoxgloveError CubePrimitiveChannel::log(
  const CubePrimitive& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_cube_primitive c_msg;
  cubePrimitiveToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_cube_primitive(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t CubePrimitiveChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<CylinderPrimitiveChannel> CylinderPrimitiveChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_cylinder_primitive(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return CylinderPrimitiveChannel(ChannelUniquePtr(channel));
}

FoxgloveError CylinderPrimitiveChannel::log(
  const CylinderPrimitive& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_cylinder_primitive c_msg;
  cylinderPrimitiveToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_cylinder_primitive(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t CylinderPrimitiveChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<FrameTransformChannel> FrameTransformChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_frame_transform(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return FrameTransformChannel(ChannelUniquePtr(channel));
}

FoxgloveError FrameTransformChannel::log(
  const FrameTransform& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_frame_transform c_msg;
  frameTransformToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_frame_transform(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t FrameTransformChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<FrameTransformsChannel> FrameTransformsChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_frame_transforms(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return FrameTransformsChannel(ChannelUniquePtr(channel));
}

FoxgloveError FrameTransformsChannel::log(
  const FrameTransforms& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_frame_transforms c_msg;
  frameTransformsToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_frame_transforms(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t FrameTransformsChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<GeoJSONChannel> GeoJSONChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error =
    foxglove_channel_create_geo_json({topic.data(), topic.size()}, context.getInner(), &channel);
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return GeoJSONChannel(ChannelUniquePtr(channel));
}

FoxgloveError GeoJSONChannel::log(const GeoJSON& msg, std::optional<uint64_t> log_time) noexcept {
  Arena arena;
  foxglove_geo_json c_msg;
  geoJSONToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_geo_json(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t GeoJSONChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<GridChannel> GridChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error =
    foxglove_channel_create_grid({topic.data(), topic.size()}, context.getInner(), &channel);
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return GridChannel(ChannelUniquePtr(channel));
}

FoxgloveError GridChannel::log(const Grid& msg, std::optional<uint64_t> log_time) noexcept {
  Arena arena;
  foxglove_grid c_msg;
  gridToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_grid(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t GridChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<ImageAnnotationsChannel> ImageAnnotationsChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_image_annotations(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return ImageAnnotationsChannel(ChannelUniquePtr(channel));
}

FoxgloveError ImageAnnotationsChannel::log(
  const ImageAnnotations& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_image_annotations c_msg;
  imageAnnotationsToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_image_annotations(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t ImageAnnotationsChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<KeyValuePairChannel> KeyValuePairChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_key_value_pair(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return KeyValuePairChannel(ChannelUniquePtr(channel));
}

FoxgloveError KeyValuePairChannel::log(
  const KeyValuePair& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_key_value_pair c_msg;
  keyValuePairToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_key_value_pair(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t KeyValuePairChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<LaserScanChannel> LaserScanChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error =
    foxglove_channel_create_laser_scan({topic.data(), topic.size()}, context.getInner(), &channel);
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return LaserScanChannel(ChannelUniquePtr(channel));
}

FoxgloveError LaserScanChannel::log(
  const LaserScan& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_laser_scan c_msg;
  laserScanToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_laser_scan(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t LaserScanChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<LinePrimitiveChannel> LinePrimitiveChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_line_primitive(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return LinePrimitiveChannel(ChannelUniquePtr(channel));
}

FoxgloveError LinePrimitiveChannel::log(
  const LinePrimitive& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_line_primitive c_msg;
  linePrimitiveToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_line_primitive(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t LinePrimitiveChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<LocationFixChannel> LocationFixChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_location_fix(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return LocationFixChannel(ChannelUniquePtr(channel));
}

FoxgloveError LocationFixChannel::log(
  const LocationFix& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_location_fix c_msg;
  locationFixToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_location_fix(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t LocationFixChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<LogChannel> LogChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error =
    foxglove_channel_create_log({topic.data(), topic.size()}, context.getInner(), &channel);
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return LogChannel(ChannelUniquePtr(channel));
}

FoxgloveError LogChannel::log(const Log& msg, std::optional<uint64_t> log_time) noexcept {
  Arena arena;
  foxglove_log c_msg;
  logToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_log(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t LogChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<ModelPrimitiveChannel> ModelPrimitiveChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_model_primitive(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return ModelPrimitiveChannel(ChannelUniquePtr(channel));
}

FoxgloveError ModelPrimitiveChannel::log(
  const ModelPrimitive& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_model_primitive c_msg;
  modelPrimitiveToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_model_primitive(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t ModelPrimitiveChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<PackedElementFieldChannel> PackedElementFieldChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_packed_element_field(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return PackedElementFieldChannel(ChannelUniquePtr(channel));
}

FoxgloveError PackedElementFieldChannel::log(
  const PackedElementField& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_packed_element_field c_msg;
  packedElementFieldToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_packed_element_field(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t PackedElementFieldChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<Point2Channel> Point2Channel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error =
    foxglove_channel_create_point2({topic.data(), topic.size()}, context.getInner(), &channel);
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return Point2Channel(ChannelUniquePtr(channel));
}

FoxgloveError Point2Channel::log(const Point2& msg, std::optional<uint64_t> log_time) noexcept {
  return FoxgloveError(foxglove_channel_log_point2(
    impl_.get(), reinterpret_cast<const foxglove_point2*>(&msg), log_time ? &*log_time : nullptr
  ));
}

uint64_t Point2Channel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<Point3Channel> Point3Channel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error =
    foxglove_channel_create_point3({topic.data(), topic.size()}, context.getInner(), &channel);
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return Point3Channel(ChannelUniquePtr(channel));
}

FoxgloveError Point3Channel::log(const Point3& msg, std::optional<uint64_t> log_time) noexcept {
  return FoxgloveError(foxglove_channel_log_point3(
    impl_.get(), reinterpret_cast<const foxglove_point3*>(&msg), log_time ? &*log_time : nullptr
  ));
}

uint64_t Point3Channel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<PointCloudChannel> PointCloudChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error =
    foxglove_channel_create_point_cloud({topic.data(), topic.size()}, context.getInner(), &channel);
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return PointCloudChannel(ChannelUniquePtr(channel));
}

FoxgloveError PointCloudChannel::log(
  const PointCloud& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_point_cloud c_msg;
  pointCloudToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_point_cloud(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t PointCloudChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<PointsAnnotationChannel> PointsAnnotationChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_points_annotation(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return PointsAnnotationChannel(ChannelUniquePtr(channel));
}

FoxgloveError PointsAnnotationChannel::log(
  const PointsAnnotation& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_points_annotation c_msg;
  pointsAnnotationToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_points_annotation(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t PointsAnnotationChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<PoseChannel> PoseChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error =
    foxglove_channel_create_pose({topic.data(), topic.size()}, context.getInner(), &channel);
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return PoseChannel(ChannelUniquePtr(channel));
}

FoxgloveError PoseChannel::log(const Pose& msg, std::optional<uint64_t> log_time) noexcept {
  Arena arena;
  foxglove_pose c_msg;
  poseToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_pose(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t PoseChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<PoseInFrameChannel> PoseInFrameChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_pose_in_frame(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return PoseInFrameChannel(ChannelUniquePtr(channel));
}

FoxgloveError PoseInFrameChannel::log(
  const PoseInFrame& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_pose_in_frame c_msg;
  poseInFrameToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_pose_in_frame(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t PoseInFrameChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<PosesInFrameChannel> PosesInFrameChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_poses_in_frame(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return PosesInFrameChannel(ChannelUniquePtr(channel));
}

FoxgloveError PosesInFrameChannel::log(
  const PosesInFrame& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_poses_in_frame c_msg;
  posesInFrameToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_poses_in_frame(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t PosesInFrameChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<QuaternionChannel> QuaternionChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error =
    foxglove_channel_create_quaternion({topic.data(), topic.size()}, context.getInner(), &channel);
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return QuaternionChannel(ChannelUniquePtr(channel));
}

FoxgloveError QuaternionChannel::log(
  const Quaternion& msg, std::optional<uint64_t> log_time
) noexcept {
  return FoxgloveError(foxglove_channel_log_quaternion(
    impl_.get(), reinterpret_cast<const foxglove_quaternion*>(&msg), log_time ? &*log_time : nullptr
  ));
}

uint64_t QuaternionChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<RawAudioChannel> RawAudioChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error =
    foxglove_channel_create_raw_audio({topic.data(), topic.size()}, context.getInner(), &channel);
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return RawAudioChannel(ChannelUniquePtr(channel));
}

FoxgloveError RawAudioChannel::log(const RawAudio& msg, std::optional<uint64_t> log_time) noexcept {
  Arena arena;
  foxglove_raw_audio c_msg;
  rawAudioToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_raw_audio(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t RawAudioChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<RawImageChannel> RawImageChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error =
    foxglove_channel_create_raw_image({topic.data(), topic.size()}, context.getInner(), &channel);
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return RawImageChannel(ChannelUniquePtr(channel));
}

FoxgloveError RawImageChannel::log(const RawImage& msg, std::optional<uint64_t> log_time) noexcept {
  Arena arena;
  foxglove_raw_image c_msg;
  rawImageToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_raw_image(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t RawImageChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<SceneEntityChannel> SceneEntityChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_scene_entity(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return SceneEntityChannel(ChannelUniquePtr(channel));
}

FoxgloveError SceneEntityChannel::log(
  const SceneEntity& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_scene_entity c_msg;
  sceneEntityToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_scene_entity(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t SceneEntityChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<SceneEntityDeletionChannel> SceneEntityDeletionChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_scene_entity_deletion(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return SceneEntityDeletionChannel(ChannelUniquePtr(channel));
}

FoxgloveError SceneEntityDeletionChannel::log(
  const SceneEntityDeletion& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_scene_entity_deletion c_msg;
  sceneEntityDeletionToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_scene_entity_deletion(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t SceneEntityDeletionChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<SceneUpdateChannel> SceneUpdateChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_scene_update(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return SceneUpdateChannel(ChannelUniquePtr(channel));
}

FoxgloveError SceneUpdateChannel::log(
  const SceneUpdate& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_scene_update c_msg;
  sceneUpdateToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_scene_update(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t SceneUpdateChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<SpherePrimitiveChannel> SpherePrimitiveChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_sphere_primitive(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return SpherePrimitiveChannel(ChannelUniquePtr(channel));
}

FoxgloveError SpherePrimitiveChannel::log(
  const SpherePrimitive& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_sphere_primitive c_msg;
  spherePrimitiveToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_sphere_primitive(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t SpherePrimitiveChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<TextAnnotationChannel> TextAnnotationChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_text_annotation(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return TextAnnotationChannel(ChannelUniquePtr(channel));
}

FoxgloveError TextAnnotationChannel::log(
  const TextAnnotation& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_text_annotation c_msg;
  textAnnotationToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_text_annotation(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t TextAnnotationChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<TextPrimitiveChannel> TextPrimitiveChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_text_primitive(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return TextPrimitiveChannel(ChannelUniquePtr(channel));
}

FoxgloveError TextPrimitiveChannel::log(
  const TextPrimitive& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_text_primitive c_msg;
  textPrimitiveToC(c_msg, msg, arena);
  return FoxgloveError(
    foxglove_channel_log_text_primitive(impl_.get(), &c_msg, log_time ? &*log_time : nullptr)
  );
}

uint64_t TextPrimitiveChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<TriangleListPrimitiveChannel> TriangleListPrimitiveChannel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error = foxglove_channel_create_triangle_list_primitive(
    {topic.data(), topic.size()}, context.getInner(), &channel
  );
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return TriangleListPrimitiveChannel(ChannelUniquePtr(channel));
}

FoxgloveError TriangleListPrimitiveChannel::log(
  const TriangleListPrimitive& msg, std::optional<uint64_t> log_time
) noexcept {
  Arena arena;
  foxglove_triangle_list_primitive c_msg;
  triangleListPrimitiveToC(c_msg, msg, arena);
  return FoxgloveError(foxglove_channel_log_triangle_list_primitive(
    impl_.get(), &c_msg, log_time ? &*log_time : nullptr
  ));
}

uint64_t TriangleListPrimitiveChannel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<Vector2Channel> Vector2Channel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error =
    foxglove_channel_create_vector2({topic.data(), topic.size()}, context.getInner(), &channel);
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return Vector2Channel(ChannelUniquePtr(channel));
}

FoxgloveError Vector2Channel::log(const Vector2& msg, std::optional<uint64_t> log_time) noexcept {
  return FoxgloveError(foxglove_channel_log_vector2(
    impl_.get(), reinterpret_cast<const foxglove_vector2*>(&msg), log_time ? &*log_time : nullptr
  ));
}

uint64_t Vector2Channel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

FoxgloveResult<Vector3Channel> Vector3Channel::create(
  const std::string_view& topic, const Context& context
) {
  const foxglove_channel* channel = nullptr;
  foxglove_error error =
    foxglove_channel_create_vector3({topic.data(), topic.size()}, context.getInner(), &channel);
  if (error != foxglove_error::FOXGLOVE_ERROR_OK || channel == nullptr) {
    return foxglove::unexpected(FoxgloveError(error));
  }
  return Vector3Channel(ChannelUniquePtr(channel));
}

FoxgloveError Vector3Channel::log(const Vector3& msg, std::optional<uint64_t> log_time) noexcept {
  return FoxgloveError(foxglove_channel_log_vector3(
    impl_.get(), reinterpret_cast<const foxglove_vector3*>(&msg), log_time ? &*log_time : nullptr
  ));
}

uint64_t Vector3Channel::id() const noexcept {
  return foxglove_channel_get_id(impl_.get());
}

void arrowPrimitiveToC(
  foxglove_arrow_primitive& dest, const ArrowPrimitive& src, [[maybe_unused]] Arena& arena
) {
  dest.pose = src.pose ? arena.map_one<foxglove_pose>(src.pose.value(), poseToC) : nullptr;
  dest.shaft_length = src.shaft_length;
  dest.shaft_diameter = src.shaft_diameter;
  dest.head_length = src.head_length;
  dest.head_diameter = src.head_diameter;
  dest.color = src.color ? reinterpret_cast<const foxglove_color*>(&*src.color) : nullptr;
}

void cameraCalibrationToC(
  foxglove_camera_calibration& dest, const CameraCalibration& src, [[maybe_unused]] Arena& arena
) {
  dest.timestamp =
    src.timestamp ? reinterpret_cast<const foxglove_timestamp*>(&*src.timestamp) : nullptr;
  dest.frame_id = {src.frame_id.data(), src.frame_id.size()};
  dest.width = src.width;
  dest.height = src.height;
  dest.distortion_model = {src.distortion_model.data(), src.distortion_model.size()};
  dest.d = src.d.data();
  dest.d_count = src.d.size();
  ::memcpy(dest.k, src.k.data(), src.k.size() * sizeof(*src.k.data()));
  ::memcpy(dest.r, src.r.data(), src.r.size() * sizeof(*src.r.data()));
  ::memcpy(dest.p, src.p.data(), src.p.size() * sizeof(*src.p.data()));
}

void circleAnnotationToC(
  foxglove_circle_annotation& dest, const CircleAnnotation& src, [[maybe_unused]] Arena& arena
) {
  dest.timestamp =
    src.timestamp ? reinterpret_cast<const foxglove_timestamp*>(&*src.timestamp) : nullptr;
  dest.position = src.position ? reinterpret_cast<const foxglove_point2*>(&*src.position) : nullptr;
  dest.diameter = src.diameter;
  dest.thickness = src.thickness;
  dest.fill_color =
    src.fill_color ? reinterpret_cast<const foxglove_color*>(&*src.fill_color) : nullptr;
  dest.outline_color =
    src.outline_color ? reinterpret_cast<const foxglove_color*>(&*src.outline_color) : nullptr;
}

void compressedImageToC(
  foxglove_compressed_image& dest, const CompressedImage& src, [[maybe_unused]] Arena& arena
) {
  dest.timestamp =
    src.timestamp ? reinterpret_cast<const foxglove_timestamp*>(&*src.timestamp) : nullptr;
  dest.frame_id = {src.frame_id.data(), src.frame_id.size()};
  dest.data = reinterpret_cast<const unsigned char*>(src.data.data());
  dest.data_len = src.data.size();
  dest.format = {src.format.data(), src.format.size()};
}

void compressedVideoToC(
  foxglove_compressed_video& dest, const CompressedVideo& src, [[maybe_unused]] Arena& arena
) {
  dest.timestamp =
    src.timestamp ? reinterpret_cast<const foxglove_timestamp*>(&*src.timestamp) : nullptr;
  dest.frame_id = {src.frame_id.data(), src.frame_id.size()};
  dest.data = reinterpret_cast<const unsigned char*>(src.data.data());
  dest.data_len = src.data.size();
  dest.format = {src.format.data(), src.format.size()};
}

void cubePrimitiveToC(
  foxglove_cube_primitive& dest, const CubePrimitive& src, [[maybe_unused]] Arena& arena
) {
  dest.pose = src.pose ? arena.map_one<foxglove_pose>(src.pose.value(), poseToC) : nullptr;
  dest.size = src.size ? reinterpret_cast<const foxglove_vector3*>(&*src.size) : nullptr;
  dest.color = src.color ? reinterpret_cast<const foxglove_color*>(&*src.color) : nullptr;
}

void cylinderPrimitiveToC(
  foxglove_cylinder_primitive& dest, const CylinderPrimitive& src, [[maybe_unused]] Arena& arena
) {
  dest.pose = src.pose ? arena.map_one<foxglove_pose>(src.pose.value(), poseToC) : nullptr;
  dest.size = src.size ? reinterpret_cast<const foxglove_vector3*>(&*src.size) : nullptr;
  dest.bottom_scale = src.bottom_scale;
  dest.top_scale = src.top_scale;
  dest.color = src.color ? reinterpret_cast<const foxglove_color*>(&*src.color) : nullptr;
}

void frameTransformToC(
  foxglove_frame_transform& dest, const FrameTransform& src, [[maybe_unused]] Arena& arena
) {
  dest.timestamp =
    src.timestamp ? reinterpret_cast<const foxglove_timestamp*>(&*src.timestamp) : nullptr;
  dest.parent_frame_id = {src.parent_frame_id.data(), src.parent_frame_id.size()};
  dest.child_frame_id = {src.child_frame_id.data(), src.child_frame_id.size()};
  dest.translation =
    src.translation ? reinterpret_cast<const foxglove_vector3*>(&*src.translation) : nullptr;
  dest.rotation =
    src.rotation ? reinterpret_cast<const foxglove_quaternion*>(&*src.rotation) : nullptr;
}

void frameTransformsToC(
  foxglove_frame_transforms& dest, const FrameTransforms& src, [[maybe_unused]] Arena& arena
) {
  dest.transforms = arena.map<foxglove_frame_transform>(src.transforms, frameTransformToC);
  dest.transforms_count = src.transforms.size();
}

void geoJSONToC(foxglove_geo_json& dest, const GeoJSON& src, [[maybe_unused]] Arena& arena) {
  dest.geojson = {src.geojson.data(), src.geojson.size()};
}

void gridToC(foxglove_grid& dest, const Grid& src, [[maybe_unused]] Arena& arena) {
  dest.timestamp =
    src.timestamp ? reinterpret_cast<const foxglove_timestamp*>(&*src.timestamp) : nullptr;
  dest.frame_id = {src.frame_id.data(), src.frame_id.size()};
  dest.pose = src.pose ? arena.map_one<foxglove_pose>(src.pose.value(), poseToC) : nullptr;
  dest.column_count = src.column_count;
  dest.cell_size =
    src.cell_size ? reinterpret_cast<const foxglove_vector2*>(&*src.cell_size) : nullptr;
  dest.row_stride = src.row_stride;
  dest.cell_stride = src.cell_stride;
  dest.fields = arena.map<foxglove_packed_element_field>(src.fields, packedElementFieldToC);
  dest.fields_count = src.fields.size();
  dest.data = reinterpret_cast<const unsigned char*>(src.data.data());
  dest.data_len = src.data.size();
}

void imageAnnotationsToC(
  foxglove_image_annotations& dest, const ImageAnnotations& src, [[maybe_unused]] Arena& arena
) {
  dest.circles = arena.map<foxglove_circle_annotation>(src.circles, circleAnnotationToC);
  dest.circles_count = src.circles.size();
  dest.points = arena.map<foxglove_points_annotation>(src.points, pointsAnnotationToC);
  dest.points_count = src.points.size();
  dest.texts = arena.map<foxglove_text_annotation>(src.texts, textAnnotationToC);
  dest.texts_count = src.texts.size();
}

void keyValuePairToC(
  foxglove_key_value_pair& dest, const KeyValuePair& src, [[maybe_unused]] Arena& arena
) {
  dest.key = {src.key.data(), src.key.size()};
  dest.value = {src.value.data(), src.value.size()};
}

void laserScanToC(foxglove_laser_scan& dest, const LaserScan& src, [[maybe_unused]] Arena& arena) {
  dest.timestamp =
    src.timestamp ? reinterpret_cast<const foxglove_timestamp*>(&*src.timestamp) : nullptr;
  dest.frame_id = {src.frame_id.data(), src.frame_id.size()};
  dest.pose = src.pose ? arena.map_one<foxglove_pose>(src.pose.value(), poseToC) : nullptr;
  dest.start_angle = src.start_angle;
  dest.end_angle = src.end_angle;
  dest.ranges = src.ranges.data();
  dest.ranges_count = src.ranges.size();
  dest.intensities = src.intensities.data();
  dest.intensities_count = src.intensities.size();
}

void linePrimitiveToC(
  foxglove_line_primitive& dest, const LinePrimitive& src, [[maybe_unused]] Arena& arena
) {
  dest.type = static_cast<foxglove_line_type>(src.type);
  dest.pose = src.pose ? arena.map_one<foxglove_pose>(src.pose.value(), poseToC) : nullptr;
  dest.thickness = src.thickness;
  dest.scale_invariant = src.scale_invariant;
  dest.points = reinterpret_cast<const foxglove_point3*>(src.points.data());
  dest.points_count = src.points.size();
  dest.color = src.color ? reinterpret_cast<const foxglove_color*>(&*src.color) : nullptr;
  dest.colors = reinterpret_cast<const foxglove_color*>(src.colors.data());
  dest.colors_count = src.colors.size();
  dest.indices = src.indices.data();
  dest.indices_count = src.indices.size();
}

void locationFixToC(
  foxglove_location_fix& dest, const LocationFix& src, [[maybe_unused]] Arena& arena
) {
  dest.timestamp =
    src.timestamp ? reinterpret_cast<const foxglove_timestamp*>(&*src.timestamp) : nullptr;
  dest.frame_id = {src.frame_id.data(), src.frame_id.size()};
  dest.latitude = src.latitude;
  dest.longitude = src.longitude;
  dest.altitude = src.altitude;
  ::memcpy(
    dest.position_covariance,
    src.position_covariance.data(),
    src.position_covariance.size() * sizeof(*src.position_covariance.data())
  );
  dest.position_covariance_type =
    static_cast<foxglove_position_covariance_type>(src.position_covariance_type);
}

void logToC(foxglove_log& dest, const Log& src, [[maybe_unused]] Arena& arena) {
  dest.timestamp =
    src.timestamp ? reinterpret_cast<const foxglove_timestamp*>(&*src.timestamp) : nullptr;
  dest.level = static_cast<foxglove_log_level>(src.level);
  dest.message = {src.message.data(), src.message.size()};
  dest.name = {src.name.data(), src.name.size()};
  dest.file = {src.file.data(), src.file.size()};
  dest.line = src.line;
}

void modelPrimitiveToC(
  foxglove_model_primitive& dest, const ModelPrimitive& src, [[maybe_unused]] Arena& arena
) {
  dest.pose = src.pose ? arena.map_one<foxglove_pose>(src.pose.value(), poseToC) : nullptr;
  dest.scale = src.scale ? reinterpret_cast<const foxglove_vector3*>(&*src.scale) : nullptr;
  dest.color = src.color ? reinterpret_cast<const foxglove_color*>(&*src.color) : nullptr;
  dest.override_color = src.override_color;
  dest.url = {src.url.data(), src.url.size()};
  dest.media_type = {src.media_type.data(), src.media_type.size()};
  dest.data = reinterpret_cast<const unsigned char*>(src.data.data());
  dest.data_len = src.data.size();
}

void packedElementFieldToC(
  foxglove_packed_element_field& dest, const PackedElementField& src, [[maybe_unused]] Arena& arena
) {
  dest.name = {src.name.data(), src.name.size()};
  dest.offset = src.offset;
  dest.type = static_cast<foxglove_numeric_type>(src.type);
}

void pointCloudToC(
  foxglove_point_cloud& dest, const PointCloud& src, [[maybe_unused]] Arena& arena
) {
  dest.timestamp =
    src.timestamp ? reinterpret_cast<const foxglove_timestamp*>(&*src.timestamp) : nullptr;
  dest.frame_id = {src.frame_id.data(), src.frame_id.size()};
  dest.pose = src.pose ? arena.map_one<foxglove_pose>(src.pose.value(), poseToC) : nullptr;
  dest.point_stride = src.point_stride;
  dest.fields = arena.map<foxglove_packed_element_field>(src.fields, packedElementFieldToC);
  dest.fields_count = src.fields.size();
  dest.data = reinterpret_cast<const unsigned char*>(src.data.data());
  dest.data_len = src.data.size();
}

void pointsAnnotationToC(
  foxglove_points_annotation& dest, const PointsAnnotation& src, [[maybe_unused]] Arena& arena
) {
  dest.timestamp =
    src.timestamp ? reinterpret_cast<const foxglove_timestamp*>(&*src.timestamp) : nullptr;
  dest.type = static_cast<foxglove_points_annotation_type>(src.type);
  dest.points = reinterpret_cast<const foxglove_point2*>(src.points.data());
  dest.points_count = src.points.size();
  dest.outline_color =
    src.outline_color ? reinterpret_cast<const foxglove_color*>(&*src.outline_color) : nullptr;
  dest.outline_colors = reinterpret_cast<const foxglove_color*>(src.outline_colors.data());
  dest.outline_colors_count = src.outline_colors.size();
  dest.fill_color =
    src.fill_color ? reinterpret_cast<const foxglove_color*>(&*src.fill_color) : nullptr;
  dest.thickness = src.thickness;
}

void poseToC(foxglove_pose& dest, const Pose& src, [[maybe_unused]] Arena& arena) {
  dest.position =
    src.position ? reinterpret_cast<const foxglove_vector3*>(&*src.position) : nullptr;
  dest.orientation =
    src.orientation ? reinterpret_cast<const foxglove_quaternion*>(&*src.orientation) : nullptr;
}

void poseInFrameToC(
  foxglove_pose_in_frame& dest, const PoseInFrame& src, [[maybe_unused]] Arena& arena
) {
  dest.timestamp =
    src.timestamp ? reinterpret_cast<const foxglove_timestamp*>(&*src.timestamp) : nullptr;
  dest.frame_id = {src.frame_id.data(), src.frame_id.size()};
  dest.pose = src.pose ? arena.map_one<foxglove_pose>(src.pose.value(), poseToC) : nullptr;
}

void posesInFrameToC(
  foxglove_poses_in_frame& dest, const PosesInFrame& src, [[maybe_unused]] Arena& arena
) {
  dest.timestamp =
    src.timestamp ? reinterpret_cast<const foxglove_timestamp*>(&*src.timestamp) : nullptr;
  dest.frame_id = {src.frame_id.data(), src.frame_id.size()};
  dest.poses = arena.map<foxglove_pose>(src.poses, poseToC);
  dest.poses_count = src.poses.size();
}

void rawAudioToC(foxglove_raw_audio& dest, const RawAudio& src, [[maybe_unused]] Arena& arena) {
  dest.timestamp =
    src.timestamp ? reinterpret_cast<const foxglove_timestamp*>(&*src.timestamp) : nullptr;
  dest.data = reinterpret_cast<const unsigned char*>(src.data.data());
  dest.data_len = src.data.size();
  dest.format = {src.format.data(), src.format.size()};
  dest.sample_rate = src.sample_rate;
  dest.number_of_channels = src.number_of_channels;
}

void rawImageToC(foxglove_raw_image& dest, const RawImage& src, [[maybe_unused]] Arena& arena) {
  dest.timestamp =
    src.timestamp ? reinterpret_cast<const foxglove_timestamp*>(&*src.timestamp) : nullptr;
  dest.frame_id = {src.frame_id.data(), src.frame_id.size()};
  dest.width = src.width;
  dest.height = src.height;
  dest.encoding = {src.encoding.data(), src.encoding.size()};
  dest.step = src.step;
  dest.data = reinterpret_cast<const unsigned char*>(src.data.data());
  dest.data_len = src.data.size();
}

void sceneEntityToC(
  foxglove_scene_entity& dest, const SceneEntity& src, [[maybe_unused]] Arena& arena
) {
  dest.timestamp =
    src.timestamp ? reinterpret_cast<const foxglove_timestamp*>(&*src.timestamp) : nullptr;
  dest.frame_id = {src.frame_id.data(), src.frame_id.size()};
  dest.id = {src.id.data(), src.id.size()};
  dest.lifetime =
    src.lifetime ? reinterpret_cast<const foxglove_duration*>(&*src.lifetime) : nullptr;
  dest.frame_locked = src.frame_locked;
  dest.metadata = arena.map<foxglove_key_value_pair>(src.metadata, keyValuePairToC);
  dest.metadata_count = src.metadata.size();
  dest.arrows = arena.map<foxglove_arrow_primitive>(src.arrows, arrowPrimitiveToC);
  dest.arrows_count = src.arrows.size();
  dest.cubes = arena.map<foxglove_cube_primitive>(src.cubes, cubePrimitiveToC);
  dest.cubes_count = src.cubes.size();
  dest.spheres = arena.map<foxglove_sphere_primitive>(src.spheres, spherePrimitiveToC);
  dest.spheres_count = src.spheres.size();
  dest.cylinders = arena.map<foxglove_cylinder_primitive>(src.cylinders, cylinderPrimitiveToC);
  dest.cylinders_count = src.cylinders.size();
  dest.lines = arena.map<foxglove_line_primitive>(src.lines, linePrimitiveToC);
  dest.lines_count = src.lines.size();
  dest.triangles =
    arena.map<foxglove_triangle_list_primitive>(src.triangles, triangleListPrimitiveToC);
  dest.triangles_count = src.triangles.size();
  dest.texts = arena.map<foxglove_text_primitive>(src.texts, textPrimitiveToC);
  dest.texts_count = src.texts.size();
  dest.models = arena.map<foxglove_model_primitive>(src.models, modelPrimitiveToC);
  dest.models_count = src.models.size();
}

void sceneEntityDeletionToC(
  foxglove_scene_entity_deletion& dest, const SceneEntityDeletion& src,
  [[maybe_unused]] Arena& arena
) {
  dest.timestamp =
    src.timestamp ? reinterpret_cast<const foxglove_timestamp*>(&*src.timestamp) : nullptr;
  dest.type = static_cast<foxglove_scene_entity_deletion_type>(src.type);
  dest.id = {src.id.data(), src.id.size()};
}

void sceneUpdateToC(
  foxglove_scene_update& dest, const SceneUpdate& src, [[maybe_unused]] Arena& arena
) {
  dest.deletions = arena.map<foxglove_scene_entity_deletion>(src.deletions, sceneEntityDeletionToC);
  dest.deletions_count = src.deletions.size();
  dest.entities = arena.map<foxglove_scene_entity>(src.entities, sceneEntityToC);
  dest.entities_count = src.entities.size();
}

void spherePrimitiveToC(
  foxglove_sphere_primitive& dest, const SpherePrimitive& src, [[maybe_unused]] Arena& arena
) {
  dest.pose = src.pose ? arena.map_one<foxglove_pose>(src.pose.value(), poseToC) : nullptr;
  dest.size = src.size ? reinterpret_cast<const foxglove_vector3*>(&*src.size) : nullptr;
  dest.color = src.color ? reinterpret_cast<const foxglove_color*>(&*src.color) : nullptr;
}

void textAnnotationToC(
  foxglove_text_annotation& dest, const TextAnnotation& src, [[maybe_unused]] Arena& arena
) {
  dest.timestamp =
    src.timestamp ? reinterpret_cast<const foxglove_timestamp*>(&*src.timestamp) : nullptr;
  dest.position = src.position ? reinterpret_cast<const foxglove_point2*>(&*src.position) : nullptr;
  dest.text = {src.text.data(), src.text.size()};
  dest.font_size = src.font_size;
  dest.text_color =
    src.text_color ? reinterpret_cast<const foxglove_color*>(&*src.text_color) : nullptr;
  dest.background_color = src.background_color
                            ? reinterpret_cast<const foxglove_color*>(&*src.background_color)
                            : nullptr;
}

void textPrimitiveToC(
  foxglove_text_primitive& dest, const TextPrimitive& src, [[maybe_unused]] Arena& arena
) {
  dest.pose = src.pose ? arena.map_one<foxglove_pose>(src.pose.value(), poseToC) : nullptr;
  dest.billboard = src.billboard;
  dest.font_size = src.font_size;
  dest.scale_invariant = src.scale_invariant;
  dest.color = src.color ? reinterpret_cast<const foxglove_color*>(&*src.color) : nullptr;
  dest.text = {src.text.data(), src.text.size()};
}

void triangleListPrimitiveToC(
  foxglove_triangle_list_primitive& dest, const TriangleListPrimitive& src,
  [[maybe_unused]] Arena& arena
) {
  dest.pose = src.pose ? arena.map_one<foxglove_pose>(src.pose.value(), poseToC) : nullptr;
  dest.points = reinterpret_cast<const foxglove_point3*>(src.points.data());
  dest.points_count = src.points.size();
  dest.color = src.color ? reinterpret_cast<const foxglove_color*>(&*src.color) : nullptr;
  dest.colors = reinterpret_cast<const foxglove_color*>(src.colors.data());
  dest.colors_count = src.colors.size();
  dest.indices = src.indices.data();
  dest.indices_count = src.indices.size();
}

}  // namespace foxglove::schemas