Browse Source

replace sdl2 with sdl2-sys and HAL, begin rewriting error code

master
Alison Watson 3 years ago
parent
commit
d33ff130ee
  1. 2
      Cargo.toml
  2. 49
      source/conf.rs
  3. 7
      source/hal.rs
  4. 26
      source/hal/context.rs
  5. 25
      source/hal/err.rs
  6. 94
      source/hal/window.rs
  7. 76
      source/main.rs
  8. 36
      source/render.rs
  9. 5
      source/render/cmd.rs
  10. 6
      source/render/device.rs
  11. 3
      source/render/framebuffer.rs
  12. 13
      source/render/instance.rs
  13. 17
      source/render/pipeline.rs
  14. 35
      source/render/properties.rs
  15. 4
      source/render/queue.rs
  16. 11
      source/render/surface.rs
  17. 3
      source/render/swapchain.rs
  18. 60
      source/util.rs
  19. 7
      source/util/err.rs
  20. 11
      source/util/ffi.rs
  21. 47
      source/util/log.rs

2
Cargo.toml

@ -17,7 +17,7 @@ color-log = ["termcolor"]
[dependencies]
ash = "0.29"
sdl2 = "0.32"
sdl2-sys = "0.32"
serde_yaml = "0.8"
[dependencies.failure]

49
source/conf.rs

@ -0,0 +1,49 @@
serialize! {
conf:
#[derive(Default)]
pub struct Conf {
pub log: crate::log::Conf,
pub render: crate::render::Conf,
}
}
#[derive(Debug)]
pub enum ErrConfLoad {
NoFile,
File(std::io::Error),
Parse(serde_yaml::Error),
}
impl std::fmt::Display for ErrConfLoad {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NoFile => write!(f, "No existing conf file"),
Self::File(e) => write!(f, "Couldn't open conf file: {}", e),
Self::Parse(e) => write!(f, "Couldn't parse conf file: {}", e),
}
}
}
impl From<std::io::Error> for ErrConfLoad {
fn from(err: std::io::Error) -> Self {
match err.kind() {
std::io::ErrorKind::NotFound => Self::NoFile,
_ => Self::File(err),
}
}
}
impl From<serde_yaml::Error> for ErrConfLoad {
fn from(err: serde_yaml::Error) -> Self {
Self::Parse(err)
}
}
impl Conf {
pub fn read(filename: &'static str) -> Result<Conf, ErrConfLoad> {
let file = std::fs::File::open(filename)?;
Ok(serde_yaml::from_reader(file)?)
}
}
// EOF

7
source/hal.rs

@ -0,0 +1,7 @@
mod context;
mod err;
mod window;
pub use self::{context::Context, err::ErrSdl, window::Window};
// EOF

26
source/hal/context.rs

@ -0,0 +1,26 @@
use crate::hal::ErrSdl;
use sdl2_sys as sdl;
pub struct Context;
impl Context {
pub fn new() -> Result<Self, ErrSdl> {
let init_flags = sdl::SDL_INIT_VIDEO;
unsafe { sdl::SDL_SetMainReady(); }
if unsafe { sdl::SDL_Init(init_flags) } == 0 {
Ok(Self)
} else {
Err(unsafe { ErrSdl::new() })
}
}
}
impl Drop for Context {
fn drop(&mut self) {
unsafe {
sdl::SDL_Quit();
}
}
}
// EOF

25
source/hal/err.rs

@ -0,0 +1,25 @@
use sdl2_sys as sdl;
#[derive(Debug)]
pub struct ErrSdl {
contents: std::borrow::Cow<'static, str>,
}
impl std::error::Error for ErrSdl {}
impl std::fmt::Display for ErrSdl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "SDL error: {}", self.contents)
}
}
impl ErrSdl {
pub unsafe fn new() -> Self {
let contents =
std::ffi::CStr::from_ptr(sdl::SDL_GetError())
.to_string_lossy();
Self { contents }
}
}
// EOF

94
source/hal/window.rs

@ -0,0 +1,94 @@
use ash::{version::InstanceV1_0, vk::{self, Handle}};
use crate::hal::{Context, ErrSdl};
use std::{marker::PhantomData, os::raw::{c_char, c_int}};
use sdl2_sys as sdl;
pub struct Window<'a> {
hal: PhantomData<&'a Context>,
handle: *mut sdl::SDL_Window,
}
impl<'a> Window<'a> {
pub fn new(
_hal: &'a Context,
title: *const c_char,
w: i16,
h: i16,
) -> Result<Self, ErrSdl> {
let handle = unsafe {
sdl::SDL_CreateWindow(
title,
sdl::SDL_WINDOWPOS_UNDEFINED_MASK as c_int,
sdl::SDL_WINDOWPOS_UNDEFINED_MASK as c_int,
w.into(),
h.into(),
sdl::SDL_WindowFlags::SDL_WINDOW_SHOWN as u32 |
sdl::SDL_WindowFlags::SDL_WINDOW_VULKAN as u32,
)
};
if handle != std::ptr::null_mut() {
Ok(Self { hal: PhantomData, handle })
} else {
Err(unsafe { ErrSdl::new() })
}
}
pub fn vulkan_instance_extensions(
&self,
) -> Result<Vec<*const c_char>, ErrSdl> {
let mut count = 0;
let res = unsafe {
sdl::SDL_Vulkan_GetInstanceExtensions(
self.handle,
&mut count,
std::ptr::null_mut(),
)
};
if res != sdl::SDL_bool::SDL_FALSE {
let mut names = vec![std::ptr::null(); count as usize];
let res = unsafe {
sdl::SDL_Vulkan_GetInstanceExtensions(
self.handle,
&mut count,
names.as_mut_ptr(),
)
};
if res != sdl::SDL_bool::SDL_FALSE {
Ok(names)
} else {
Err(unsafe { ErrSdl::new() })
}
} else {
Err(unsafe { ErrSdl::new() })
}
}
pub fn vulkan_create_surface(
&self,
instance: &crate::render::Instance,
) -> Result<vk::SurfaceKHR, ErrSdl> {
let mut surface = 0;
let res = unsafe {
sdl::SDL_Vulkan_CreateSurface(
self.handle,
(**instance).handle().as_raw() as usize,
&mut surface,
)
};
if res != sdl::SDL_bool::SDL_FALSE {
Ok(vk::SurfaceKHR::from_raw(surface))
} else {
Err(unsafe { ErrSdl::new() })
}
}
}
impl Drop for Window<'_> {
fn drop(&mut self) {
unsafe {
sdl::SDL_DestroyWindow(self.handle);
}
}
}
// EOF

76
source/main.rs

@ -1,20 +1,12 @@
#[macro_use]
mod util;
mod conf;
mod hal;
mod render;
use ash::{version::DeviceV1_0, vk};
use crate::{render::*, util::{err, log, meta}};
use std::convert::TryInto;
serialize! {
conf:
#[derive(Default)]
struct Conf {
log: log::Conf,
render: render::Conf,
}
}
use crate::{render::*, util::{log, meta}};
const MAIN_VERT: &'static [u8] =
include_bytes!(concat!(env!("OUT_DIR"), "/main.vert.o"));
@ -29,7 +21,7 @@ fn draw_frame(
cmd_buffers: &[CommandBuffer],
queue_graphics: &Queue,
queue_surface: &Queue,
) -> err::Result<()> {
) -> Result<(), vk::Result> {
let image_index = unsafe {
device.swapchain_ext.acquire_next_image(
**swapchain,
@ -48,12 +40,12 @@ fn draw_frame(
let submit_info = [
vk::SubmitInfo {
wait_semaphore_count: wait_semaphores.len().try_into()?,
wait_semaphore_count: wait_semaphores.len() as u32,
p_wait_semaphores: wait_semaphores.as_ptr(),
p_wait_dst_stage_mask: wait_stages.as_ptr(),
command_buffer_count: submit_cmd_buffers.len().try_into()?,
command_buffer_count: submit_cmd_buffers.len() as u32,
p_command_buffers: submit_cmd_buffers.as_ptr(),
signal_semaphore_count: signal_semaphores.len().try_into()?,
signal_semaphore_count: signal_semaphores.len() as u32,
p_signal_semaphores: signal_semaphores.as_ptr(),
..Default::default()
}
@ -67,9 +59,9 @@ fn draw_frame(
let image_indices = [image_index];
let present_info = vk::PresentInfoKHR {
wait_semaphore_count: signal_semaphores.len().try_into()?,
wait_semaphore_count: signal_semaphores.len() as u32,
p_wait_semaphores: signal_semaphores.as_ptr(),
swapchain_count: swapchains.len().try_into()?,
swapchain_count: swapchains.len() as u32,
p_swapchains: swapchains.as_ptr(),
p_image_indices: image_indices.as_ptr(),
..Default::default()
@ -82,11 +74,13 @@ fn draw_frame(
Ok(())
}
fn fallback_main(conf: &Conf, lg: &log::Log) -> err::Result<()> {
let sdl_context = err::from_s(sdl2::init())?;
let sdl_video = err::from_s(sdl_context.video())?;
fn fallback_main(
conf: &conf::Conf,
lg: &log::Log,
) -> Result<(), Box<dyn std::error::Error>> {
let hal = hal::Context::new()?;
let window = sdl_video.window(meta::name(), 640, 480).vulkan().build()?;
let window = hal::Window::new(&hal, meta::ffi::name(), 640, 480)?;
let entry = ash::Entry::new()?;
@ -175,14 +169,14 @@ fn fallback_main(conf: &Conf, lg: &log::Log) -> err::Result<()> {
&queue_surface,
);
if let Err(e) = frame {
lg!(lg, Error, "Error rendering frame: {}", e);
lg!(lg, Level::Error, "Error rendering frame: {}", e);
}
std::thread::sleep(std::time::Duration::from_secs(3));
let seize = unsafe { device.device_wait_idle() };
if let Err(e) = seize {
lg!(lg, Error, "Error seizing renderer state: {}", e);
lg!(lg, Level::Error, "Error seizing renderer state: {}", e);
}
Ok(())
@ -194,28 +188,24 @@ fn main() {
.insert_mode("Std", log::Std);
#[cfg(feature = "color-log")]
let lg = lg.insert_mode("Color", log::Color).set_mode("Color").unwrap();
trace!(&lg);
let (conf, lg) = if let Ok(file) = std::fs::File::open("blonkus.yaml") {
let conf: Result<Conf, _> = serde_yaml::from_reader(file);
match conf {
Ok(conf) => {
(conf, lg)
}
Err(e) => {
lg!(&lg, Error, "Error loading configuration: {}", e);
(Conf::default(), lg)
}
}
} else {
lg!(&lg, Info, "No configuration file available. Using defaults.");
(Conf::default(), lg)
};
let lg =
lg
.insert_mode("Color", log::Color)
.set_mode("Color")
.unwrap();
let conf = conf::Conf::read("blonkus.yaml").unwrap_or_else(|err| {
let level = match err {
conf::ErrConfLoad::NoFile => log::Level::Notice,
_ => log::Level::Error,
};
lg!(&lg, level, "{}", err);
lg!(&lg, Level::Notice, "Using default configuration.");
conf::Conf::default()
});
if let Err(e) = fallback_main(&conf, &lg) {
lg!(&lg, Critical, "Uncaught error: {}", e);
lg!(&lg, Level::Critical, "Uncaught error: {}", e);
}
}

36
source/render.rs

@ -5,6 +5,7 @@ mod framebuffer;
mod imageview;
mod instance;
mod pipeline;
mod properties;
mod queue;
mod semaphore;
mod shader;
@ -20,6 +21,7 @@ pub use self::{
imageview::ImageView,
instance::Instance,
pipeline::{PipelineLayout, Pipeline, RenderPass},
properties::{ErrNoProperty, ensure_properties},
queue::{Queue, QueueFamilyInfo},
semaphore::Semaphore,
shader::ShaderModule,
@ -28,38 +30,4 @@ pub use self::{
swapchain::Swapchain,
};
use std::{ffi::CStr, os::raw::c_char};
#[derive(Debug)]
pub struct ErrNoProperty {
name: String,
}
impl std::fmt::Display for ErrNoProperty {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} not available", self.name)
}
}
impl std::error::Error for ErrNoProperty {}
pub fn ensure_properties<T, F>(
props: &[T],
names: &[*const c_char],
func: F,
) -> Result<(), ErrNoProperty>
where
F: Fn(&T) -> *const c_char,
{
for name in names {
let name = unsafe { CStr::from_ptr(*name) };
if !props.iter().any(|x| unsafe { CStr::from_ptr(func(x)) == name }) {
return Err(ErrNoProperty { name: name.to_string_lossy().to_string() });
}
}
Ok(())
}
// EOF

5
source/render/cmd.rs

@ -1,6 +1,5 @@
use ash::{version::DeviceV1_0, vk};
use crate::{render::{Device, Framebuffer, Pipeline, RenderPass}, util::err};
use std::convert::TryInto;
pub struct CommandPool<'a, 'b> {
device: &'a Device<'b>,
@ -33,7 +32,7 @@ impl<'a, 'b> CommandPool<'a, 'b> {
let alloc_info = vk::CommandBufferAllocateInfo {
command_pool: **self,
level: vk::CommandBufferLevel::PRIMARY,
command_buffer_count: framebuffers.len().try_into()?,
command_buffer_count: framebuffers.len() as u32,
..Default::default()
};
@ -79,7 +78,7 @@ impl CommandBuffer<'_, '_, '_> {
offset: vk::Offset2D::default(),
extent: image_extent,
},
clear_value_count: clear_values.len().try_into()?,
clear_value_count: clear_values.len() as u32,
p_clear_values: clear_values.as_ptr(),
..Default::default()
};

6
source/render/device.rs

@ -3,7 +3,7 @@ use crate::{
render::{Conf, Instance, ensure_properties, QueueFamilyInfo},
util::err
};
use std::{convert::TryInto, marker::PhantomData, os::raw::c_char};
use std::{marker::PhantomData, os::raw::c_char};
pub struct Device<'a> {
instance: PhantomData<&'a Instance>,
@ -31,7 +31,7 @@ fn enable_device_extensions(
}
Ok(vk::DeviceCreateInfo {
enabled_extension_count: extensions.len().try_into()?,
enabled_extension_count: extensions.len() as u32,
pp_enabled_extension_names: extensions.as_ptr(),
..Default::default()
})
@ -65,7 +65,7 @@ impl<'a> Device<'a> {
let extensions = [c_str!("VK_KHR_swapchain")];
let create_info = vk::DeviceCreateInfo {
queue_create_info_count: queue_create_info.len().try_into()?,
queue_create_info_count: queue_create_info.len() as u32,
p_queue_create_infos: queue_create_info.as_ptr(),
p_enabled_features: &device_features,
..enable_device_extensions(instance, phys_device, &extensions)?

3
source/render/framebuffer.rs

@ -1,6 +1,5 @@
use ash::{version::DeviceV1_0, vk};
use crate::{render::{Device, ImageView, RenderPass}, util::err};
use std::convert::TryInto;
pub struct Framebuffer<'a, 'b> {
device: &'a Device<'b>,
@ -18,7 +17,7 @@ impl<'a, 'b> Framebuffer<'a, 'b> {
let create_info = vk::FramebufferCreateInfo {
render_pass: **render_pass,
attachment_count: attachments.len().try_into()?,
attachment_count: attachments.len() as u32,
p_attachments: attachments.as_ptr(),
width: image_extent.width,
height: image_extent.height,

13
source/render/instance.rs

@ -4,8 +4,8 @@ use ash::{
vk,
vk_make_version
};
use crate::{render::{Conf, ensure_properties}, util::{err, ffi, meta}};
use std::{convert::TryInto, os::raw::c_char};
use crate::{render::{Conf, ensure_properties}, util::{err, meta}};
use std::os::raw::c_char;
pub struct Instance {
handle: ash::Instance,
@ -23,7 +23,7 @@ fn enable_instance_layers(
}
Ok(vk::InstanceCreateInfo {
enabled_layer_count: layers.len().try_into()?,
enabled_layer_count: layers.len() as u32,
pp_enabled_layer_names: layers.as_ptr(),
..Default::default()
})
@ -33,10 +33,9 @@ impl Instance {
pub fn create(
conf: &Conf,
entry: &ash::Entry,
window: &sdl2::video::Window,
window: &crate::hal::Window,
) -> err::Result<Self> {
let exts = err::from_s(window.vulkan_instance_extensions())?;
let exts = ffi::CStringVec::new_from_iter(exts.into_iter())?;
let exts = window.vulkan_instance_extensions()?;
let app_info = vk::ApplicationInfo {
p_engine_name: meta::ffi::name(),
@ -52,7 +51,7 @@ impl Instance {
let create_info = vk::InstanceCreateInfo {
p_application_info: &app_info,
enabled_extension_count: exts.len().try_into()?,
enabled_extension_count: exts.len() as u32,
pp_enabled_extension_names: exts.as_ptr(),
..enable_instance_layers(&layers, &entry)?
};

17
source/render/pipeline.rs

@ -1,6 +1,5 @@
use ash::{version::DeviceV1_0, vk};
use crate::{render::{Device, ShaderModule}, util::err};
use std::convert::TryInto;
pub struct PipelineLayout<'a, 'b> {
device: &'a Device<'b>,
@ -57,7 +56,7 @@ impl<'a, 'b> RenderPass<'a, 'b> {
let subpasses = [
vk::SubpassDescription {
pipeline_bind_point: vk::PipelineBindPoint::GRAPHICS,
color_attachment_count: attachment_references.len().try_into()?,
color_attachment_count: attachment_references.len() as u32,
p_color_attachments: attachment_references.as_ptr(),
..Default::default()
}
@ -78,11 +77,11 @@ impl<'a, 'b> RenderPass<'a, 'b> {
];
let create_info = vk::RenderPassCreateInfo {
attachment_count: attachments.len().try_into()?,
attachment_count: attachments.len() as u32,
p_attachments: attachments.as_ptr(),
subpass_count: subpasses.len().try_into()?,
subpass_count: subpasses.len() as u32,
p_subpasses: subpasses.as_ptr(),
dependency_count: dependencies.len().try_into()?,
dependency_count: dependencies.len() as u32,
p_dependencies: dependencies.as_ptr(),
..Default::default()
};
@ -144,9 +143,9 @@ impl<'a, 'b> Pipeline<'a, 'b> {
];
let viewport_state = vk::PipelineViewportStateCreateInfo {
viewport_count: viewports.len().try_into()?,
viewport_count: viewports.len() as u32,
p_viewports: viewports.as_ptr(),
scissor_count: scissors.len().try_into()?,
scissor_count: scissors.len() as u32,
p_scissors: scissors.as_ptr(),
..Default::default()
};
@ -174,7 +173,7 @@ impl<'a, 'b> Pipeline<'a, 'b> {
];
let color_blend_state = vk::PipelineColorBlendStateCreateInfo {
attachment_count: color_blend_attachments.len().try_into()?,
attachment_count: color_blend_attachments.len() as u32,
p_attachments: color_blend_attachments.as_ptr(),
..Default::default()
};
@ -182,7 +181,7 @@ impl<'a, 'b> Pipeline<'a, 'b> {
let create_info = vk::GraphicsPipelineCreateInfo {
layout: **layout,
render_pass: **render_pass,
stage_count: shader_stages.len().try_into()?,
stage_count: shader_stages.len() as u32,
p_stages: shader_stages.as_ptr(),
p_vertex_input_state: &vertex_input_state,
p_input_assembly_state: &input_assembly_state,

35
source/render/properties.rs

@ -0,0 +1,35 @@
use std::{ffi::CStr, os::raw::c_char};
#[derive(Debug)]
pub struct ErrNoProperty {
name: String,
}
impl std::fmt::Display for ErrNoProperty {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} not available", self.name)
}
}
impl std::error::Error for ErrNoProperty {}
pub fn ensure_properties<T, F>(
props: &[T],
names: &[*const c_char],
func: F,
) -> Result<(), ErrNoProperty>
where
F: Fn(&T) -> *const c_char,
{
for name in names {
let name = unsafe { CStr::from_ptr(*name) };
if !props.iter().any(|x| unsafe { CStr::from_ptr(func(x)) == name }) {
return Err(ErrNoProperty { name: name.to_string_lossy().to_string() });
}
}
Ok(())
}
// EOF

4
source/render/queue.rs

@ -1,6 +1,6 @@
use ash::{version::{DeviceV1_0, InstanceV1_0}, vk};
use crate::{render::{Device, Instance, PhysicalDevice, Surface}, util::err};
use std::{convert::TryInto, marker::PhantomData};
use std::marker::PhantomData;
pub struct QueueFamilyInfo {
pub gfx_index: u32,
@ -26,7 +26,7 @@ impl QueueFamilyInfo {
};
for (i, queue) in queues.iter().enumerate() {
let i = i.try_into()?;
let i = i as u32;
let surface_support = unsafe {
instance.surface_ext.get_physical_device_surface_support(

11
source/render/surface.rs

@ -1,6 +1,5 @@
use ash::{version::InstanceV1_0, vk::{self, Handle}};
use ash::vk;
use crate::{render::Instance, util::err};
use std::convert::TryInto;
pub struct Surface<'a> {
instance: &'a Instance,
@ -10,13 +9,9 @@ pub struct Surface<'a> {
impl<'a> Surface<'a> {
pub fn create(
instance: &'a Instance,
window: &sdl2::video::Window,
window: &crate::hal::Window,
) -> err::Result<Self> {
let handle = {
let instance = instance.handle().as_raw().try_into()?;
let handle = err::from_s(window.vulkan_create_surface(instance))?;
vk::SurfaceKHR::from_raw(handle)
};
let handle = window.vulkan_create_surface(instance)?;
Ok(Self { instance, handle })
}
}

3
source/render/swapchain.rs

@ -3,7 +3,6 @@ use crate::{
render::{Conf, Device, Instance, PhysicalDevice, QueueFamilyInfo, Surface},
util::err
};
use std::convert::TryInto;
pub struct Swapchain<'a, 'b> {
device: &'a Device<'b>,
@ -103,7 +102,7 @@ impl<'a, 'b> Swapchain<'a, 'b> {
} else {
vk::SharingMode::EXCLUSIVE
},
queue_family_index_count: queue_family_indices.len().try_into()?,
queue_family_index_count: queue_family_indices.len() as u32,
p_queue_family_indices: queue_family_indices.as_ptr(),
pre_transform: capabilities.current_transform,
composite_alpha: vk::CompositeAlphaFlagsKHR::OPAQUE,

60
source/util.rs

@ -1,50 +1,5 @@
#![allow(dead_code)]
#[macro_export]
macro_rules! lg {
($to:expr, $level:ident, $($args:tt)+) => {
{
let level = $crate::util::log::Level::$level;
let to = $to;
if to.enabled(level) {
let record = $crate::util::log::Record {
level,
module: std::module_path!(),
file: std::file!(),
line: std::line!(),
column: std::column!(),
};
to.log(std::format_args!($($args)+), record);
}
}
};
}
#[macro_export]
macro_rules! trace {
($to:expr) => {
#[cfg(debug_assertions)]
{
$crate::lg!($to, Trace, "");
}
};
($to:expr, $val:expr) => {
#[cfg(debug_assertions)]
{
let val = $val;
$crate::lg!($to, Trace, "{} = {:#?}", std::stringify!($val), &val);
val
}
};
($to:expr, $($val:expr),+ $(,)?) => {
($($crate::trace!($to, $val)),+,)
};
}
/// Macro-izes `#[doc = x]`.
#[macro_export]
macro_rules! doc_comment {
@ -54,14 +9,6 @@ macro_rules! doc_comment {
};
}
/// Creates a C string from a literal.
#[macro_export]
macro_rules! c_str {
($s:expr) => {
std::concat!($s, "\0").as_ptr() as *const std::os::raw::c_char
};
}
#[macro_export]
macro_rules! serialize {
(conf_enum: $($tt:tt)*) => {
@ -77,9 +24,12 @@ macro_rules! serialize {
};
}
pub mod err;
#[macro_use]
pub mod ffi;
pub mod meta;
#[macro_use]
pub mod log;
pub mod err;
pub mod meta;
// EOF

7
source/util/err.rs

@ -3,10 +3,3 @@ pub use failure::err_msg as static_msg;
use failure::Error;
pub type Result<T> = std::result::Result<T, Error>;
pub fn from_s<T>(v: std::result::Result<T, String>) -> Result<T> {
match v {
Ok(v) => Ok(v),
Err(e) => Err(static_msg(e)),
}
}

11
source/util/ffi.rs

@ -1,6 +1,13 @@
use crate::util::err;
use std::{ffi::CString, os::raw::c_char, ptr::null};
/// Creates a C string from a literal.
#[macro_export]
macro_rules! c_str {
($s:expr) => {
std::concat!($s, "\0").as_ptr() as *const std::os::raw::c_char
};
}
/// An owned null-terminated string vector.
#[derive(Debug)]
pub struct CStringVec {
@ -23,7 +30,7 @@ impl Default for CStringVec {
impl CStringVec {
/// Creates a new `CStringVec` from an iterator.
#[inline]
pub fn new_from_iter<'a, I>(it: I) -> err::Result<Self>
pub fn new_from_iter<'a, I>(it: I) -> Result<Self, std::ffi::NulError>
where
I: Iterator<Item = &'a str>,
{

47
source/util/log.rs

@ -7,6 +7,53 @@ pub use self::{color::Color, conf::Conf, level::Level, standard::Std};
use std::collections::HashMap;
#[macro_export]
macro_rules! lg {
($to:expr, $level:expr, $($args:tt)+) => {
{
#[allow(unused_imports)]
use $crate::util::log::Level;
let (level, to) = ($level, $to);
if to.enabled(level) {
let record = $crate::util::log::Record {
level: level,
module: std::module_path!(),
file: std::file!(),
line: std::line!(),
column: std::column!(),
};
to.log(std::format_args!($($args)+), record);
}
}
};
}
#[macro_export]
macro_rules! trace {
($to:expr) => {
#[cfg(debug_assertions)]
{
$crate::lg!($to, Trace, "");
}
};
($to:expr, $val:expr) => {
#[cfg(debug_assertions)]
{
let val = $val;
$crate::lg!($to, Trace, "{} = {:#?}", std::stringify!($val), &val);
val
}
};
($to:expr, $($val:expr),+ $(,)?) => {
($($crate::trace!($to, $val)),+,)
};
}
pub struct Record {
pub level: Level,
pub module: &'static str,

Loading…
Cancel
Save