From cf587e4de4cbbdeedb2e94a06332bb8a698bba2e Mon Sep 17 00:00:00 2001 From: Joonas Javanainen Date: Fri, 30 Dec 2016 09:01:38 +0200 Subject: [PATCH] Split ImStr to ImStr and ImString It might be better to use the utf8-cstr crate, but it doesn't have the owned<->borrowed duality, so it would be used as an implementation detail only. --- .../examples/test_window_impl.rs | 14 +- src/input.rs | 34 ++--- src/lib.rs | 133 ++++++++---------- src/menus.rs | 12 +- src/plothistogram.rs | 8 +- src/plotlines.rs | 8 +- src/progressbar.rs | 4 +- src/sliders.rs | 32 ++--- src/string.rs | 122 ++++++++++++++++ src/trees.rs | 12 +- src/window.rs | 4 +- 11 files changed, 239 insertions(+), 144 deletions(-) create mode 100644 src/string.rs diff --git a/imgui-glium-renderer/examples/test_window_impl.rs b/imgui-glium-renderer/examples/test_window_impl.rs index fb67030..e8ce5e2 100644 --- a/imgui-glium-renderer/examples/test_window_impl.rs +++ b/imgui-glium-renderer/examples/test_window_impl.rs @@ -4,7 +4,6 @@ extern crate imgui; extern crate imgui_glium_renderer; use imgui::*; -use std::iter::repeat; use self::support::Support; @@ -31,10 +30,10 @@ struct State { no_menu: bool, bg_alpha: f32, wrap_width: f32, - buf: String, + buf: ImString, item: i32, item2: i32, - text: String, + text: ImString, i0: i32, f0: f32, vec2f: [f32; 2], @@ -50,13 +49,10 @@ struct State { impl Default for State { fn default() -> Self { - let mut buf = "日本語".to_owned(); - buf.extend(repeat('\0').take(32)); - buf.truncate(32); - let mut text = String::with_capacity(128); + let mut buf = ImString::with_capacity(32); + buf.push_str("日本語"); + let mut text = ImString::with_capacity(128); text.push_str("Hello, world!"); - let remaining = text.capacity() - text.len(); - text.extend(repeat('\0').take(remaining)); State { clear_color: (114.0 / 255.0, 144.0 / 255.0, 154.0 / 255.0, 1.0), show_app_metrics: false, diff --git a/src/input.rs b/src/input.rs index 977703d..a0fa03e 100644 --- a/src/input.rs +++ b/src/input.rs @@ -10,7 +10,7 @@ use super::{ImGuiInputTextFlags, ImGuiInputTextFlags_CharsDecimal, ImGuiInputTextFlags_CharsHexadecimal, ImGuiInputTextFlags_CharsNoBlank, ImGuiInputTextFlags_CharsUppercase, ImGuiInputTextFlags_EnterReturnsTrue, ImGuiInputTextFlags_NoHorizontalScroll, ImStr, - Ui}; + ImString, Ui}; macro_rules! impl_text_flags { ($InputType:ident) => { @@ -128,14 +128,14 @@ macro_rules! impl_precision_params { #[must_use] pub struct InputText<'ui, 'p> { - label: ImStr<'p>, - buf: &'p mut str, + label: &'p ImStr, + buf: &'p mut ImString, flags: ImGuiInputTextFlags, _phantom: PhantomData<&'ui Ui<'ui>>, } impl<'ui, 'p> InputText<'ui, 'p> { - pub fn new(label: ImStr<'p>, buf: &'p mut str) -> Self { + pub fn new(label: &'p ImStr, buf: &'p mut ImString) -> Self { InputText { label: label, buf: buf, @@ -155,7 +155,7 @@ impl<'ui, 'p> InputText<'ui, 'p> { // TODO: this is evil. // Perhaps something else than &mut str is better self.buf.as_ptr() as *mut i8, - self.buf.len() as usize, + self.buf.capacity() + 1, self.flags, None, ptr::null_mut()) @@ -165,7 +165,7 @@ impl<'ui, 'p> InputText<'ui, 'p> { #[must_use] pub struct InputInt<'ui, 'p> { - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut i32, step: i32, step_fast: i32, @@ -174,7 +174,7 @@ pub struct InputInt<'ui, 'p> { } impl<'ui, 'p> InputInt<'ui, 'p> { - pub fn new(label: ImStr<'p>, value: &'p mut i32) -> Self { + pub fn new(label: &'p ImStr, value: &'p mut i32) -> Self { InputInt { label: label, value: value, @@ -201,7 +201,7 @@ impl<'ui, 'p> InputInt<'ui, 'p> { #[must_use] pub struct InputFloat<'ui, 'p> { - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut f32, step: f32, step_fast: f32, @@ -211,7 +211,7 @@ pub struct InputFloat<'ui, 'p> { } impl<'ui, 'p> InputFloat<'ui, 'p> { - pub fn new(label: ImStr<'p>, value: &'p mut f32) -> Self { + pub fn new(label: &'p ImStr, value: &'p mut f32) -> Self { InputFloat { label: label, value: value, @@ -243,7 +243,7 @@ macro_rules! impl_input_floatn { ($InputFloatN:ident, $N:expr, $igInputFloatN:ident) => { #[must_use] pub struct $InputFloatN<'ui, 'p> { - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut [f32;$N], decimal_precision: i32, flags: ImGuiInputTextFlags, @@ -251,7 +251,7 @@ macro_rules! impl_input_floatn { } impl<'ui, 'p> $InputFloatN<'ui, 'p> { - pub fn new(label: ImStr<'p>, value: &'p mut [f32;$N]) -> Self { + pub fn new(label: &'p ImStr, value: &'p mut [f32;$N]) -> Self { $InputFloatN { label: label, value: value, @@ -285,14 +285,14 @@ macro_rules! impl_input_intn { ($InputIntN:ident, $N:expr, $igInputIntN:ident) => { #[must_use] pub struct $InputIntN<'ui, 'p> { - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut [i32;$N], flags: ImGuiInputTextFlags, _phantom: PhantomData<&'ui Ui<'ui>> } impl<'ui, 'p> $InputIntN<'ui, 'p> { - pub fn new(label: ImStr<'p>, value: &'p mut [i32;$N]) -> Self { + pub fn new(label: &'p ImStr, value: &'p mut [i32;$N]) -> Self { $InputIntN { label: label, value: value, @@ -321,13 +321,13 @@ impl_input_intn!(InputInt4, 4, igInputInt4); #[must_use] pub struct ColorEdit3<'ui, 'p> { - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut [f32; 3], _phantom: PhantomData<&'ui Ui<'ui>>, } impl<'ui, 'p> ColorEdit3<'ui, 'p> { - pub fn new(label: ImStr<'p>, value: &'p mut [f32; 3]) -> Self { + pub fn new(label: &'p ImStr, value: &'p mut [f32; 3]) -> Self { ColorEdit3 { label: label, value: value, @@ -342,14 +342,14 @@ impl<'ui, 'p> ColorEdit3<'ui, 'p> { #[must_use] pub struct ColorEdit4<'ui, 'p> { - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut [f32; 4], show_alpha: bool, _phantom: PhantomData<&'ui Ui<'ui>>, } impl<'ui, 'p> ColorEdit4<'ui, 'p> { - pub fn new(label: ImStr<'p>, value: &'p mut [f32; 4]) -> Self { + pub fn new(label: &'p ImStr, value: &'p mut [f32; 4]) -> Self { ColorEdit4 { label: label, value: value, diff --git a/src/lib.rs b/src/lib.rs index 4a143d5..14a6dd2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,5 @@ extern crate imgui_sys; -use std::borrow::Cow; -use std::convert::From; use std::ffi::CStr; use std::mem; use std::os::raw::{c_char, c_float, c_int, c_uchar, c_void}; @@ -45,6 +43,7 @@ pub use plotlines::PlotLines; pub use progressbar::ProgressBar; pub use sliders::{SliderFloat, SliderFloat2, SliderFloat3, SliderFloat4, SliderInt, SliderInt2, SliderInt3, SliderInt4}; +pub use string::{ImStr, ImString}; pub use trees::{CollapsingHeader, TreeNode}; pub use window::Window; @@ -54,54 +53,32 @@ mod plothistogram; mod plotlines; mod progressbar; mod sliders; +mod string; mod trees; mod window; pub struct ImGui { // We need to keep ownership of the ImStr values to ensure the *const char pointer // lives long enough in case the ImStr contains a Cow::Owned - ini_filename: Option>, - log_filename: Option>, + ini_filename: Option, + log_filename: Option, } #[macro_export] macro_rules! im_str { ($e:tt) => ({ + debug_assert!(!($e).as_bytes().contains(&0)); let value = concat!($e, "\0"); unsafe { ::imgui::ImStr::from_bytes_unchecked(value.as_bytes()) } }); ($e:tt, $($arg:tt)*) => ({ - ::imgui::ImStr::from(format!($e, $($arg)*)) + let mut bytes: Vec = format!($e, $($arg)*).into(); + debug_assert!(!bytes.contains(&0)); + bytes.push(b'\0'); + unsafe { &::imgui::ImString::from_vec_unchecked(bytes) } }) } -#[derive(Clone)] -pub struct ImStr<'a> { - bytes: Cow<'a, [u8]>, -} - -impl<'a> ImStr<'a> { - pub unsafe fn from_bytes_unchecked(bytes: &'a [u8]) -> ImStr<'a> { - ImStr { bytes: Cow::Borrowed(bytes) } - } - pub fn as_ptr(&self) -> *const c_char { self.bytes.as_ptr() as *const c_char } -} - -impl<'a> From<&'a str> for ImStr<'a> { - fn from(value: &'a str) -> ImStr<'a> { - let mut bytes: Vec = value.bytes().collect(); - bytes.push(0); - ImStr { bytes: Cow::Owned(bytes) } - } -} - -impl From for ImStr<'static> { - fn from(mut value: String) -> ImStr<'static> { - value.push('\0'); - ImStr { bytes: Cow::Owned(value.into_bytes()) } - } -} - pub struct TextureHandle<'a> { pub width: u32, pub height: u32, @@ -153,7 +130,7 @@ impl ImGui { (*self.io_mut().fonts).tex_id = value as *mut c_void; } } - pub fn set_ini_filename(&mut self, value: Option>) { + pub fn set_ini_filename(&mut self, value: Option) { { let io = self.io_mut(); io.ini_filename = match value { @@ -163,7 +140,7 @@ impl ImGui { } self.ini_filename = value; } - pub fn set_log_filename(&mut self, value: Option>) { + pub fn set_log_filename(&mut self, value: Option) { { let io = self.io_mut(); io.log_filename = match value { @@ -394,7 +371,7 @@ impl<'a> Ui<'a> { // Window impl<'ui> Ui<'ui> { - pub fn window<'p>(&self, name: ImStr<'p>) -> Window<'ui, 'p> { Window::new(name) } + pub fn window<'p>(&self, name: &'p ImStr) -> Window<'ui, 'p> { Window::new(name) } } // Layout @@ -424,7 +401,7 @@ impl<'ui> Ui<'ui> { } pub fn spacing(&self) { unsafe { imgui_sys::igSpacing() }; } - pub fn columns<'p>(&self, count: i32, id: ImStr<'p>, border: bool) { + pub fn columns<'p>(&self, count: i32, id: &'p ImStr, border: bool) { unsafe { imgui_sys::igColumns(count, id.as_ptr(), border) } } @@ -470,30 +447,30 @@ impl<'ui> Ui<'ui> { // Widgets impl<'ui> Ui<'ui> { - pub fn text<'p>(&self, text: ImStr<'p>) { + pub fn text>(&self, text: P) { // TODO: use igTextUnformatted unsafe { - imgui_sys::igText(fmt_ptr(), text.as_ptr()); + imgui_sys::igText(fmt_ptr(), text.as_ref().as_ptr()); } } - pub fn text_colored<'p, A>(&self, col: A, text: ImStr<'p>) + pub fn text_colored<'p, A>(&self, col: A, text: &'p ImStr) where A: Into { unsafe { imgui_sys::igTextColored(col.into(), fmt_ptr(), text.as_ptr()); } } - pub fn text_disabled<'p>(&self, text: ImStr<'p>) { + pub fn text_disabled<'p>(&self, text: &'p ImStr) { unsafe { imgui_sys::igTextDisabled(fmt_ptr(), text.as_ptr()); } } - pub fn text_wrapped<'p>(&self, text: ImStr<'p>) { + pub fn text_wrapped<'p>(&self, text: &'p ImStr) { unsafe { imgui_sys::igTextWrapped(fmt_ptr(), text.as_ptr()); } } - pub fn label_text<'p>(&self, label: ImStr<'p>, text: ImStr<'p>) { + pub fn label_text<'p>(&self, label: &'p ImStr, text: &'p ImStr) { unsafe { imgui_sys::igLabelText(label.as_ptr(), fmt_ptr(), text.as_ptr()); } @@ -503,18 +480,18 @@ impl<'ui> Ui<'ui> { imgui_sys::igBullet(); } } - pub fn bullet_text<'p>(&self, text: ImStr<'p>) { + pub fn bullet_text<'p>(&self, text: &'p ImStr) { unsafe { imgui_sys::igBulletText(fmt_ptr(), text.as_ptr()); } } - pub fn button<'p>(&self, label: ImStr<'p>, size: ImVec2) -> bool { + pub fn button<'p>(&self, label: &'p ImStr, size: ImVec2) -> bool { unsafe { imgui_sys::igButton(label.as_ptr(), size) } } - pub fn small_button<'p>(&self, label: ImStr<'p>) -> bool { + pub fn small_button<'p>(&self, label: &'p ImStr) -> bool { unsafe { imgui_sys::igSmallButton(label.as_ptr()) } } - pub fn checkbox<'p>(&self, label: ImStr<'p>, value: &'p mut bool) -> bool { + pub fn checkbox<'p>(&self, label: &'p ImStr, value: &'p mut bool) -> bool { unsafe { imgui_sys::igCheckbox(label.as_ptr(), value) } } } @@ -522,51 +499,51 @@ impl<'ui> Ui<'ui> { // Widgets: Input impl<'ui> Ui<'ui> { pub fn color_edit3<'p>(&self, - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut [f32; 3]) -> ColorEdit3<'ui, 'p> { ColorEdit3::new(label, value) } pub fn color_edit4<'p>(&self, - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut [f32; 4]) -> ColorEdit4<'ui, 'p> { ColorEdit4::new(label, value) } - pub fn input_text<'p>(&self, label: ImStr<'p>, buf: &'p mut str) -> InputText<'ui, 'p> { + pub fn input_text<'p>(&self, label: &'p ImStr, buf: &'p mut ImString) -> InputText<'ui, 'p> { InputText::new(label, buf) } - pub fn input_float<'p>(&self, label: ImStr<'p>, value: &'p mut f32) -> InputFloat<'ui, 'p> { + pub fn input_float<'p>(&self, label: &'p ImStr, value: &'p mut f32) -> InputFloat<'ui, 'p> { InputFloat::new(label, value) } pub fn input_float2<'p>(&self, - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut [f32; 2]) -> InputFloat2<'ui, 'p> { InputFloat2::new(label, value) } pub fn input_float3<'p>(&self, - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut [f32; 3]) -> InputFloat3<'ui, 'p> { InputFloat3::new(label, value) } pub fn input_float4<'p>(&self, - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut [f32; 4]) -> InputFloat4<'ui, 'p> { InputFloat4::new(label, value) } - pub fn input_int<'p>(&self, label: ImStr<'p>, value: &'p mut i32) -> InputInt<'ui, 'p> { + pub fn input_int<'p>(&self, label: &'p ImStr, value: &'p mut i32) -> InputInt<'ui, 'p> { InputInt::new(label, value) } - pub fn input_int2<'p>(&self, label: ImStr<'p>, value: &'p mut [i32; 2]) -> InputInt2<'ui, 'p> { + pub fn input_int2<'p>(&self, label: &'p ImStr, value: &'p mut [i32; 2]) -> InputInt2<'ui, 'p> { InputInt2::new(label, value) } - pub fn input_int3<'p>(&self, label: ImStr<'p>, value: &'p mut [i32; 3]) -> InputInt3<'ui, 'p> { + pub fn input_int3<'p>(&self, label: &'p ImStr, value: &'p mut [i32; 3]) -> InputInt3<'ui, 'p> { InputInt3::new(label, value) } - pub fn input_int4<'p>(&self, label: ImStr<'p>, value: &'p mut [i32; 4]) -> InputInt4<'ui, 'p> { + pub fn input_int4<'p>(&self, label: &'p ImStr, value: &'p mut [i32; 4]) -> InputInt4<'ui, 'p> { InputInt4::new(label, value) } } @@ -574,7 +551,7 @@ impl<'ui> Ui<'ui> { // Widgets: Sliders impl<'ui> Ui<'ui> { pub fn slider_float<'p>(&self, - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut f32, min: f32, max: f32) @@ -582,7 +559,7 @@ impl<'ui> Ui<'ui> { SliderFloat::new(label, value, min, max) } pub fn slider_float2<'p>(&self, - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut [f32; 2], min: f32, max: f32) @@ -590,7 +567,7 @@ impl<'ui> Ui<'ui> { SliderFloat2::new(label, value, min, max) } pub fn slider_float3<'p>(&self, - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut [f32; 3], min: f32, max: f32) @@ -598,7 +575,7 @@ impl<'ui> Ui<'ui> { SliderFloat3::new(label, value, min, max) } pub fn slider_float4<'p>(&self, - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut [f32; 4], min: f32, max: f32) @@ -606,7 +583,7 @@ impl<'ui> Ui<'ui> { SliderFloat4::new(label, value, min, max) } pub fn slider_int<'p>(&self, - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut i32, min: i32, max: i32) @@ -614,7 +591,7 @@ impl<'ui> Ui<'ui> { SliderInt::new(label, value, min, max) } pub fn slider_int2<'p>(&self, - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut [i32; 2], min: i32, max: i32) @@ -622,7 +599,7 @@ impl<'ui> Ui<'ui> { SliderInt2::new(label, value, min, max) } pub fn slider_int3<'p>(&self, - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut [i32; 3], min: i32, max: i32) @@ -630,7 +607,7 @@ impl<'ui> Ui<'ui> { SliderInt3::new(label, value, min, max) } pub fn slider_int4<'p>(&self, - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut [i32; 4], min: i32, max: i32) @@ -641,8 +618,8 @@ impl<'ui> Ui<'ui> { // Widgets: Trees impl<'ui> Ui<'ui> { - pub fn tree_node<'p>(&self, id: ImStr<'p>) -> TreeNode<'ui, 'p> { TreeNode::new(id) } - pub fn collapsing_header<'p>(&self, label: ImStr<'p>) -> CollapsingHeader<'ui, 'p> { + pub fn tree_node<'p>(&self, id: &'p ImStr) -> TreeNode<'ui, 'p> { TreeNode::new(id) } + pub fn collapsing_header<'p>(&self, label: &'p ImStr) -> CollapsingHeader<'ui, 'p> { CollapsingHeader::new(label) } } @@ -650,7 +627,7 @@ impl<'ui> Ui<'ui> { // Widgets: Selectable / Lists impl<'ui> Ui<'ui> { pub fn selectable<'p>(&self, - label: ImStr<'p>, + label: &'p ImStr, selected: bool, flags: ImGuiSelectableFlags, size: ImVec2) @@ -679,16 +656,16 @@ impl<'ui> Ui<'ui> { unsafe { imgui_sys::igEndMenuBar() }; } } - pub fn menu<'p>(&self, label: ImStr<'p>) -> Menu<'ui, 'p> { Menu::new(label) } - pub fn menu_item<'p>(&self, label: ImStr<'p>) -> MenuItem<'ui, 'p> { MenuItem::new(label) } + pub fn menu<'p>(&self, label: &'p ImStr) -> Menu<'ui, 'p> { Menu::new(label) } + pub fn menu_item<'p>(&self, label: &'p ImStr) -> MenuItem<'ui, 'p> { MenuItem::new(label) } } // Widgets: Popups impl<'ui> Ui<'ui> { - pub fn open_popup<'p>(&self, str_id: ImStr<'p>) { + pub fn open_popup<'p>(&self, str_id: &'p ImStr) { unsafe { imgui_sys::igOpenPopup(str_id.as_ptr()) }; } - pub fn popup<'p, F>(&self, str_id: ImStr<'p>, f: F) + pub fn popup<'p, F>(&self, str_id: &'p ImStr, f: F) where F: FnOnce() { let render = unsafe { imgui_sys::igBeginPopup(str_id.as_ptr()) }; @@ -703,9 +680,9 @@ impl<'ui> Ui<'ui> { // Widgets: Combos impl<'ui> Ui<'ui> { pub fn combo<'p>(&self, - label: ImStr<'p>, + label: &'p ImStr, current_item: &mut i32, - items: &'p [ImStr<'p>], + items: &'p [&'p ImStr], height_in_items: i32) -> bool { let items_inner: Vec<*const c_char> = items.into_iter().map(|item| item.as_ptr()).collect(); @@ -722,9 +699,9 @@ impl<'ui> Ui<'ui> { // Widgets: ListBox impl<'ui> Ui<'ui> { pub fn list_box<'p>(&self, - label: ImStr<'p>, + label: &'p ImStr, current_item: &mut i32, - items: &'p [ImStr<'p>], + items: &'p [&'p ImStr], height_in_items: i32) -> bool { let items_inner: Vec<*const c_char> = items.into_iter().map(|item| item.as_ptr()).collect(); @@ -739,13 +716,13 @@ impl<'ui> Ui<'ui> { } impl<'ui> Ui<'ui> { - pub fn plot_lines<'p>(&self, label: ImStr<'p>, values: &'p [f32]) -> PlotLines<'p> { + pub fn plot_lines<'p>(&self, label: &'p ImStr, values: &'p [f32]) -> PlotLines<'p> { PlotLines::new(label, values) } } impl<'ui> Ui<'ui> { - pub fn plot_histogram<'p>(&self, label: ImStr<'p>, values: &'p [f32]) -> PlotHistogram<'p> { + pub fn plot_histogram<'p>(&self, label: &'p ImStr, values: &'p [f32]) -> PlotHistogram<'p> { PlotHistogram::new(label, values) } } diff --git a/src/menus.rs b/src/menus.rs index 945c5c0..08e41ee 100644 --- a/src/menus.rs +++ b/src/menus.rs @@ -6,13 +6,13 @@ use super::{ImStr, Ui}; #[must_use] pub struct Menu<'ui, 'p> { - label: ImStr<'p>, + label: &'p ImStr, enabled: bool, _phantom: PhantomData<&'ui Ui<'ui>>, } impl<'ui, 'p> Menu<'ui, 'p> { - pub fn new(label: ImStr<'p>) -> Self { + pub fn new(label: &'p ImStr) -> Self { Menu { label: label, enabled: true, @@ -35,15 +35,15 @@ impl<'ui, 'p> Menu<'ui, 'p> { #[must_use] pub struct MenuItem<'ui, 'p> { - label: ImStr<'p>, - shortcut: Option>, + label: &'p ImStr, + shortcut: Option<&'p ImStr>, selected: Option<&'p mut bool>, enabled: bool, _phantom: PhantomData<&'ui Ui<'ui>>, } impl<'ui, 'p> MenuItem<'ui, 'p> { - pub fn new(label: ImStr<'p>) -> Self { + pub fn new(label: &'p ImStr) -> Self { MenuItem { label: label, shortcut: None, @@ -53,7 +53,7 @@ impl<'ui, 'p> MenuItem<'ui, 'p> { } } #[inline] - pub fn shortcut(mut self, shortcut: ImStr<'p>) -> Self { + pub fn shortcut(mut self, shortcut: &'p ImStr) -> Self { self.shortcut = Some(shortcut); self } diff --git a/src/plothistogram.rs b/src/plothistogram.rs index 7042ca5..a199625 100644 --- a/src/plothistogram.rs +++ b/src/plothistogram.rs @@ -6,17 +6,17 @@ use super::{ImStr, ImVec2}; #[must_use] pub struct PlotHistogram<'p> { - label: ImStr<'p>, + label: &'p ImStr, values: &'p [f32], values_offset: usize, - overlay_text: Option>, + overlay_text: Option<&'p ImStr>, scale_min: f32, scale_max: f32, graph_size: ImVec2, } impl<'p> PlotHistogram<'p> { - pub fn new(label: ImStr<'p>, values: &'p [f32]) -> Self { + pub fn new(label: &'p ImStr, values: &'p [f32]) -> Self { PlotHistogram { label: label, values: values, @@ -35,7 +35,7 @@ impl<'p> PlotHistogram<'p> { } #[inline] - pub fn overlay_text(mut self, overlay_text: ImStr<'p>) -> Self { + pub fn overlay_text(mut self, overlay_text: &'p ImStr) -> Self { self.overlay_text = Some(overlay_text); self } diff --git a/src/plotlines.rs b/src/plotlines.rs index 5f4c7d1..c3a0430 100644 --- a/src/plotlines.rs +++ b/src/plotlines.rs @@ -5,17 +5,17 @@ use std::os::raw::c_float; use super::{ImStr, ImVec2}; #[must_use] pub struct PlotLines<'p> { - label: ImStr<'p>, + label: &'p ImStr, values: &'p [f32], values_offset: usize, - overlay_text: Option>, + overlay_text: Option<&'p ImStr>, scale_min: f32, scale_max: f32, graph_size: ImVec2, } impl<'p> PlotLines<'p> { - pub fn new(label: ImStr<'p>, values: &'p [f32]) -> Self { + pub fn new(label: &'p ImStr, values: &'p [f32]) -> Self { PlotLines { label: label, values: values, @@ -34,7 +34,7 @@ impl<'p> PlotLines<'p> { } #[inline] - pub fn overlay_text(mut self, overlay_text: ImStr<'p>) -> Self { + pub fn overlay_text(mut self, overlay_text: &'p ImStr) -> Self { self.overlay_text = Some(overlay_text); self } diff --git a/src/progressbar.rs b/src/progressbar.rs index dab0db1..766a044 100644 --- a/src/progressbar.rs +++ b/src/progressbar.rs @@ -10,7 +10,7 @@ use super::{ImStr, ImVec2}; pub struct ProgressBar<'p> { fraction: f32, size: ImVec2, - overlay_text: Option>, + overlay_text: Option<&'p ImStr>, } impl<'p> ProgressBar<'p> { @@ -29,7 +29,7 @@ impl<'p> ProgressBar<'p> { /// Sets an optional text that will be drawn over the progress bar. #[inline] - pub fn overlay_text(mut self, overlay_text: ImStr<'p>) -> Self { + pub fn overlay_text(mut self, overlay_text: &'p ImStr) -> Self { self.overlay_text = Some(overlay_text); self } diff --git a/src/sliders.rs b/src/sliders.rs index 246052d..b7da3ee 100644 --- a/src/sliders.rs +++ b/src/sliders.rs @@ -7,16 +7,16 @@ use super::{ImStr, Ui}; #[must_use] pub struct SliderInt<'ui, 'p> { - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut i32, min: i32, max: i32, - display_format: ImStr<'p>, + display_format: &'p ImStr, _phantom: PhantomData<&'ui Ui<'ui>>, } impl<'ui, 'p> SliderInt<'ui, 'p> { - pub fn new(label: ImStr<'p>, value: &'p mut i32, min: i32, max: i32) -> Self { + pub fn new(label: &'p ImStr, value: &'p mut i32, min: i32, max: i32) -> Self { SliderInt { label: label, value: value, @@ -27,7 +27,7 @@ impl<'ui, 'p> SliderInt<'ui, 'p> { } } #[inline] - pub fn display_format(mut self, display_format: ImStr<'p>) -> Self { + pub fn display_format(mut self, display_format: &'p ImStr) -> Self { self.display_format = display_format; self } @@ -46,16 +46,16 @@ macro_rules! impl_slider_intn { ($SliderIntN:ident, $N:expr, $igSliderIntN:ident) => { #[must_use] pub struct $SliderIntN<'ui, 'p> { - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut [i32; $N], min: i32, max: i32, - display_format: ImStr<'p>, + display_format: &'p ImStr, _phantom: PhantomData<&'ui Ui<'ui>>, } impl<'ui, 'p> $SliderIntN<'ui, 'p> { - pub fn new(label: ImStr<'p>, value: &'p mut [i32; $N], min: i32, max: i32) -> Self { + pub fn new(label: &'p ImStr, value: &'p mut [i32; $N], min: i32, max: i32) -> Self { $SliderIntN { label: label, value: value, @@ -66,7 +66,7 @@ macro_rules! impl_slider_intn { } } #[inline] - pub fn display_format(mut self, display_format: ImStr<'p>) -> Self { + pub fn display_format(mut self, display_format: &'p ImStr) -> Self { self.display_format = display_format; self } @@ -90,17 +90,17 @@ impl_slider_intn!(SliderInt4, 4, igSliderInt4); #[must_use] pub struct SliderFloat<'ui, 'p> { - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut f32, min: f32, max: f32, - display_format: ImStr<'p>, + display_format: &'p ImStr, power: f32, _phantom: PhantomData<&'ui Ui<'ui>>, } impl<'ui, 'p> SliderFloat<'ui, 'p> { - pub fn new(label: ImStr<'p>, value: &'p mut f32, min: f32, max: f32) -> Self { + pub fn new(label: &'p ImStr, value: &'p mut f32, min: f32, max: f32) -> Self { SliderFloat { label: label, value: value, @@ -112,7 +112,7 @@ impl<'ui, 'p> SliderFloat<'ui, 'p> { } } #[inline] - pub fn display_format(mut self, display_format: ImStr<'p>) -> Self { + pub fn display_format(mut self, display_format: &'p ImStr) -> Self { self.display_format = display_format; self } @@ -137,17 +137,17 @@ macro_rules! impl_slider_floatn { ($SliderFloatN:ident, $N:expr, $igSliderFloatN:ident) => { #[must_use] pub struct $SliderFloatN<'ui, 'p> { - label: ImStr<'p>, + label: &'p ImStr, value: &'p mut [f32; $N], min: f32, max: f32, - display_format: ImStr<'p>, + display_format: &'p ImStr, power: f32, _phantom: PhantomData<&'ui Ui<'ui>>, } impl<'ui, 'p> $SliderFloatN<'ui, 'p> { - pub fn new(label: ImStr<'p>, value: &'p mut [f32; $N], min: f32, max: f32) -> Self { + pub fn new(label: &'p ImStr, value: &'p mut [f32; $N], min: f32, max: f32) -> Self { $SliderFloatN { label: label, value: value, @@ -159,7 +159,7 @@ macro_rules! impl_slider_floatn { } } #[inline] - pub fn display_format(mut self, display_format: ImStr<'p>) -> Self { + pub fn display_format(mut self, display_format: &'p ImStr) -> Self { self.display_format = display_format; self } diff --git a/src/string.rs b/src/string.rs new file mode 100644 index 0000000..1af1c5b --- /dev/null +++ b/src/string.rs @@ -0,0 +1,122 @@ +use std::borrow::Borrow; +use std::ffi::{CStr, CString, NulError}; +use std::fmt; +use std::mem; +use std::ops::Deref; +use std::os::raw::c_char; +use std::str; + +#[derive(Clone, Default, Hash, Ord, Eq, PartialOrd, PartialEq)] +pub struct ImString(Vec); + +impl ImString { + pub fn new>(t: T) -> Result { + CString::new(t.into()).map(|cstring| ImString(cstring.into_bytes_with_nul())) + } + pub fn with_capacity(capacity: usize) -> ImString { + let mut v = Vec::with_capacity(capacity + 1); + v.push(b'\0'); + ImString(v) + } + pub unsafe fn from_string_unchecked(s: String) -> ImString { + ImString::from_vec_unchecked(s.into()) + } + pub unsafe fn from_vec_unchecked(mut v: Vec) -> ImString { + v.push(b'\0'); + ImString(v) + } + pub fn clear(&mut self) { + self.0.clear(); + self.0.push(b'\0'); + } + pub fn push_str(&mut self, string: &str) { + self.0.pop(); + self.0.extend_from_slice(string.as_bytes()); + self.0.push(b'\0'); + } + pub fn capacity(&self) -> usize { self.0.capacity() - 1 } + pub fn reserve(&mut self, additional: usize) { + self.0.reserve(additional); + } + pub fn reserve_exact(&mut self, additional: usize) { + self.0.reserve_exact(additional); + } +} + +impl AsRef for ImString { + fn as_ref(&self) -> &ImStr { self } +} + +impl Borrow for ImString { + fn borrow(&self) -> &ImStr { self } +} + +impl fmt::Debug for ImString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s: &str = self; + fmt::Debug::fmt(s, f) + } +} + +impl Deref for ImString { + type Target = ImStr; + fn deref(&self) -> &ImStr { + // as_ptr() is used, because we need to look at the bytes to figure out the length + // self.0.len() is incorrect, because there might be more than one nul byte in the end + unsafe { mem::transmute(CStr::from_ptr(self.0.as_ptr() as *const c_char)) } + } +} + +impl<'a> From<&'a ImStr> for ImString { + fn from(value: &'a ImStr) -> ImString { value.to_owned() } +} + +#[derive(Hash)] +pub struct ImStr(CStr); + +impl<'a> Default for &'a ImStr { + fn default() -> &'a ImStr { + static SLICE: &'static [u8] = &[0]; + unsafe { ImStr::from_bytes_unchecked(SLICE) } + } +} + +impl fmt::Debug for ImStr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } +} + +impl ImStr { + pub unsafe fn from_bytes_unchecked<'a>(bytes: &'a [u8]) -> &'a ImStr { + mem::transmute(bytes) + } + pub fn as_ptr(&self) -> *const c_char { self.0.as_ptr() as *const c_char } + pub fn to_str(&self) -> &str { + unsafe { str::from_utf8_unchecked(&self.as_bytes()) } + } +} + +impl<'a> Into<&'a CStr> for &'a ImStr { + fn into(self) -> &'a CStr { &self.0 } +} + +impl AsRef for ImStr { + fn as_ref(&self) -> &CStr { &self.0 } +} + +impl AsRef for ImStr { + fn as_ref(&self) -> &ImStr { self } +} + +impl ToOwned for ImStr { + type Owned = ImString; + fn to_owned(&self) -> ImString { ImString(self.0.to_owned().into_bytes()) } +} + +impl Deref for ImStr { + type Target = str; + fn deref(&self) -> &str { + unsafe { str::from_utf8_unchecked(self.0.to_bytes()) } + } +} diff --git a/src/trees.rs b/src/trees.rs index 25f010f..7aa713b 100644 --- a/src/trees.rs +++ b/src/trees.rs @@ -8,15 +8,15 @@ use super::{ImGuiSetCond, ImGuiTreeNodeFlags, ImGuiTreeNodeFlags_Bullet, #[must_use] pub struct TreeNode<'ui, 'p> { - id: ImStr<'p>, - label: Option>, + id: &'p ImStr, + label: Option<&'p ImStr>, opened: bool, opened_cond: ImGuiSetCond, _phantom: PhantomData<&'ui Ui<'ui>>, } impl<'ui, 'p> TreeNode<'ui, 'p> { - pub fn new(id: ImStr<'p>) -> Self { + pub fn new(id: &'p ImStr) -> Self { TreeNode { id: id, label: None, @@ -26,7 +26,7 @@ impl<'ui, 'p> TreeNode<'ui, 'p> { } } #[inline] - pub fn label(mut self, label: ImStr<'p>) -> Self { + pub fn label(mut self, label: &'p ImStr) -> Self { self.label = Some(label); self } @@ -54,7 +54,7 @@ impl<'ui, 'p> TreeNode<'ui, 'p> { #[must_use] pub struct CollapsingHeader<'ui, 'p> { - label: ImStr<'p>, + label: &'p ImStr, // Some flags are automatically set in ImGui::CollapsingHeader, so // we only support a sensible subset here flags: ImGuiTreeNodeFlags, @@ -62,7 +62,7 @@ pub struct CollapsingHeader<'ui, 'p> { } impl<'ui, 'p> CollapsingHeader<'ui, 'p> { - pub fn new(label: ImStr<'p>) -> Self { + pub fn new(label: &'p ImStr) -> Self { CollapsingHeader { label: label, flags: ImGuiTreeNodeFlags::empty(), diff --git a/src/window.rs b/src/window.rs index 3aae581..03840fa 100644 --- a/src/window.rs +++ b/src/window.rs @@ -18,7 +18,7 @@ pub struct Window<'ui, 'p> { pos_cond: ImGuiSetCond, size: (f32, f32), size_cond: ImGuiSetCond, - name: ImStr<'p>, + name: &'p ImStr, opened: Option<&'p mut bool>, bg_alpha: f32, flags: ImGuiWindowFlags, @@ -26,7 +26,7 @@ pub struct Window<'ui, 'p> { } impl<'ui, 'p> Window<'ui, 'p> { - pub fn new(name: ImStr<'p>) -> Window<'ui, 'p> { + pub fn new(name: &'p ImStr) -> Window<'ui, 'p> { Window { pos: (0.0, 0.0), pos_cond: ImGuiSetCond::empty(),