[go: up one dir, main page]

sdl2/
joystick.rs

1use crate::sys;
2use crate::sys::SDL_JoystickPowerLevel;
3
4use crate::clear_error;
5use crate::common::{validate_int, IntegerOrSdlError};
6use crate::get_error;
7use crate::JoystickSubsystem;
8use libc::c_char;
9use std::ffi::{CStr, CString, NulError};
10use std::fmt::{Display, Error, Formatter};
11
12impl JoystickSubsystem {
13    /// Retrieve the total number of attached joysticks *and* controllers identified by SDL.
14    #[doc(alias = "SDL_NumJoysticks")]
15    pub fn num_joysticks(&self) -> Result<u32, String> {
16        let result = unsafe { sys::SDL_NumJoysticks() };
17
18        if result >= 0 {
19            Ok(result as u32)
20        } else {
21            Err(get_error())
22        }
23    }
24
25    /// Attempt to open the joystick at index `joystick_index` and return it.
26    #[doc(alias = "SDL_JoystickOpen")]
27    pub fn open(&self, joystick_index: u32) -> Result<Joystick, IntegerOrSdlError> {
28        use crate::common::IntegerOrSdlError::*;
29        let joystick_index = validate_int(joystick_index, "joystick_index")?;
30
31        let joystick = unsafe { sys::SDL_JoystickOpen(joystick_index) };
32
33        if joystick.is_null() {
34            Err(SdlError(get_error()))
35        } else {
36            Ok(Joystick {
37                subsystem: self.clone(),
38                raw: joystick,
39            })
40        }
41    }
42
43    /// Return the name of the joystick at index `joystick_index`.
44    #[doc(alias = "SDL_JoystickNameForIndex")]
45    pub fn name_for_index(&self, joystick_index: u32) -> Result<String, IntegerOrSdlError> {
46        use crate::common::IntegerOrSdlError::*;
47        let joystick_index = validate_int(joystick_index, "joystick_index")?;
48
49        let c_str = unsafe { sys::SDL_JoystickNameForIndex(joystick_index) };
50
51        if c_str.is_null() {
52            Err(SdlError(get_error()))
53        } else {
54            Ok(unsafe {
55                CStr::from_ptr(c_str as *const _)
56                    .to_str()
57                    .unwrap()
58                    .to_string()
59            })
60        }
61    }
62
63    /// Return the player index of the joystick with index `device_index`.
64    #[doc(alias = "SDL_JoystickGetDevicePlayerIndex")]
65    pub fn player_index_for_device_id(
66        &self,
67        device_index: u32,
68    ) -> Result<Option<u32>, IntegerOrSdlError> {
69        let device_index = validate_int(device_index, "device_index")?;
70
71        let player_index = unsafe { sys::SDL_JoystickGetDevicePlayerIndex(device_index) };
72
73        // if index is -1 (or less than 0), joystick has no player
74        if player_index < 0 {
75            Ok(None)
76        } else {
77            Ok(Some(player_index as u32))
78        }
79    }
80
81    /// Return the instance ID of the joystick with player index `player_index`.
82    #[doc(alias = "SDL_JoystickFromPlayerIndex")]
83    pub fn instance_id_for_player_index(
84        &self,
85        player_index: u32,
86    ) -> Result<Option<u32>, IntegerOrSdlError> {
87        let player_index = validate_int(player_index, "player_index")?;
88
89        let joystick = unsafe { sys::SDL_JoystickFromPlayerIndex(player_index) };
90
91        if joystick.is_null() {
92            Ok(None)
93        } else {
94            let result = unsafe { sys::SDL_JoystickInstanceID(joystick) };
95
96            if result < 0 {
97                // Should only fail if the joystick is NULL.
98                panic!("{}", get_error())
99            } else {
100                Ok(Some(result as u32))
101            }
102        }
103    }
104
105    /// Get the GUID for the joystick at index `joystick_index`
106    #[doc(alias = "SDL_JoystickGetDeviceGUID")]
107    pub fn device_guid(&self, joystick_index: u32) -> Result<Guid, IntegerOrSdlError> {
108        use crate::common::IntegerOrSdlError::*;
109        let joystick_index = validate_int(joystick_index, "joystick_index")?;
110
111        let raw = unsafe { sys::SDL_JoystickGetDeviceGUID(joystick_index) };
112
113        let guid = Guid { raw };
114
115        if guid.is_zero() {
116            Err(SdlError(get_error()))
117        } else {
118            Ok(guid)
119        }
120    }
121
122    /// If state is `true` joystick events are processed, otherwise
123    /// they're ignored.
124    #[doc(alias = "SDL_JoystickEventState")]
125    pub fn set_event_state(&self, state: bool) {
126        unsafe { sys::SDL_JoystickEventState(state as i32) };
127    }
128
129    /// Return `true` if joystick events are processed.
130    #[doc(alias = "SDL_JoystickEventState")]
131    pub fn event_state(&self) -> bool {
132        unsafe { sys::SDL_JoystickEventState(sys::SDL_QUERY) == sys::SDL_ENABLE as i32 }
133    }
134
135    /// Force joystick update when not using the event loop
136    #[inline]
137    #[doc(alias = "SDL_JoystickUpdate")]
138    pub fn update(&self) {
139        unsafe { sys::SDL_JoystickUpdate() };
140    }
141}
142
143#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
144#[repr(i32)]
145pub enum PowerLevel {
146    Unknown = SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_UNKNOWN as i32,
147    Empty = SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_EMPTY as i32,
148    Low = SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_LOW as i32,
149    Medium = SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_MEDIUM as i32,
150    Full = SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_FULL as i32,
151    Wired = SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_WIRED as i32,
152}
153
154impl PowerLevel {
155    pub fn from_ll(raw: SDL_JoystickPowerLevel) -> PowerLevel {
156        match raw {
157            SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_UNKNOWN => PowerLevel::Unknown,
158            SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_EMPTY => PowerLevel::Empty,
159            SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_LOW => PowerLevel::Low,
160            SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_MEDIUM => PowerLevel::Medium,
161            SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_FULL => PowerLevel::Full,
162            SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_WIRED => PowerLevel::Wired,
163            _ => panic!("Unexpected power level: {}", raw as i32),
164        }
165    }
166
167    pub fn to_ll(self) -> SDL_JoystickPowerLevel {
168        match self {
169            PowerLevel::Unknown => SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_UNKNOWN,
170            PowerLevel::Empty => SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_EMPTY,
171            PowerLevel::Low => SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_LOW,
172            PowerLevel::Medium => SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_MEDIUM,
173            PowerLevel::Full => SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_FULL,
174            PowerLevel::Wired => SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_WIRED,
175        }
176    }
177}
178
179/// Wrapper around the `SDL_Joystick` object
180pub struct Joystick {
181    subsystem: JoystickSubsystem,
182    raw: *mut sys::SDL_Joystick,
183}
184
185impl Joystick {
186    #[inline]
187    pub const fn subsystem(&self) -> &JoystickSubsystem {
188        &self.subsystem
189    }
190
191    /// Return the name of the joystick or an empty string if no name
192    /// is found.
193    #[doc(alias = "SDL_JoystickName")]
194    pub fn name(&self) -> String {
195        let name = unsafe { sys::SDL_JoystickName(self.raw) };
196
197        c_str_to_string(name)
198    }
199
200    /// Return true if the joystick has been opened and currently
201    /// connected.
202    #[doc(alias = "SDL_JoystickGetAttached")]
203    pub fn attached(&self) -> bool {
204        unsafe { sys::SDL_JoystickGetAttached(self.raw) != sys::SDL_bool::SDL_FALSE }
205    }
206
207    #[doc(alias = "SDL_JoystickInstanceID")]
208    pub fn instance_id(&self) -> u32 {
209        let result = unsafe { sys::SDL_JoystickInstanceID(self.raw) };
210
211        if result < 0 {
212            // Should only fail if the joystick is NULL.
213            panic!("{}", get_error())
214        } else {
215            result as u32
216        }
217    }
218
219    /// Retrieve the joystick's GUID
220    #[doc(alias = "SDL_JoystickGetGUID")]
221    pub fn guid(&self) -> Guid {
222        let raw = unsafe { sys::SDL_JoystickGetGUID(self.raw) };
223
224        let guid = Guid { raw };
225
226        if guid.is_zero() {
227            // Should only fail if the joystick is NULL.
228            panic!("{}", get_error())
229        } else {
230            guid
231        }
232    }
233
234    /// Retrieve the battery level of this joystick
235    #[doc(alias = "SDL_JoystickCurrentPowerLevel")]
236    pub fn power_level(&self) -> Result<PowerLevel, IntegerOrSdlError> {
237        use crate::common::IntegerOrSdlError::*;
238        clear_error();
239
240        let result = unsafe { sys::SDL_JoystickCurrentPowerLevel(self.raw) };
241
242        let state = PowerLevel::from_ll(result);
243
244        if result != SDL_JoystickPowerLevel::SDL_JOYSTICK_POWER_UNKNOWN {
245            Ok(state)
246        } else {
247            let err = get_error();
248
249            if err.is_empty() {
250                Ok(state)
251            } else {
252                Err(SdlError(err))
253            }
254        }
255    }
256
257    /// Retrieve the number of axes for this joystick
258    #[doc(alias = "SDL_JoystickNumAxes")]
259    pub fn num_axes(&self) -> u32 {
260        let result = unsafe { sys::SDL_JoystickNumAxes(self.raw) };
261
262        if result < 0 {
263            // Should only fail if the joystick is NULL.
264            panic!("{}", get_error())
265        } else {
266            result as u32
267        }
268    }
269
270    /// Gets the position of the given `axis`.
271    ///
272    /// The function will fail if the joystick doesn't have the provided axis.
273    #[doc(alias = "SDL_JoystickGetAxis")]
274    pub fn axis(&self, axis: u32) -> Result<i16, IntegerOrSdlError> {
275        use crate::common::IntegerOrSdlError::*;
276        // This interface is a bit messed up: 0 is a valid position
277        // but can also mean that an error occured. As far as I can
278        // tell the only way to know if an error happened is to see if
279        // get_error() returns a non-empty string.
280        clear_error();
281
282        let axis = validate_int(axis, "axis")?;
283        let pos = unsafe { sys::SDL_JoystickGetAxis(self.raw, axis) };
284
285        if pos != 0 {
286            Ok(pos)
287        } else {
288            let err = get_error();
289
290            if err.is_empty() {
291                Ok(pos)
292            } else {
293                Err(SdlError(err))
294            }
295        }
296    }
297
298    /// Retrieve the number of buttons for this joystick
299    #[doc(alias = "SDL_JoystickNumButtons")]
300    pub fn num_buttons(&self) -> u32 {
301        let result = unsafe { sys::SDL_JoystickNumButtons(self.raw) };
302
303        if result < 0 {
304            // Should only fail if the joystick is NULL.
305            panic!("{}", get_error())
306        } else {
307            result as u32
308        }
309    }
310
311    /// Return `Ok(true)` if `button` is pressed.
312    ///
313    /// The function will fail if the joystick doesn't have the provided button.
314    #[doc(alias = "SDL_JoystickGetButton")]
315    pub fn button(&self, button: u32) -> Result<bool, IntegerOrSdlError> {
316        use crate::common::IntegerOrSdlError::*;
317        // Same deal as axis, 0 can mean both unpressed or
318        // error...
319        clear_error();
320
321        let button = validate_int(button, "button")?;
322        let pressed = unsafe { sys::SDL_JoystickGetButton(self.raw, button) };
323
324        match pressed {
325            1 => Ok(true),
326            0 => {
327                let err = get_error();
328
329                if err.is_empty() {
330                    // Button is not pressed
331                    Ok(false)
332                } else {
333                    Err(SdlError(err))
334                }
335            }
336            // Should be unreachable
337            _ => unreachable!(),
338        }
339    }
340
341    /// Retrieve the number of balls for this joystick
342    #[doc(alias = "SDL_JoystickNumBalls")]
343    pub fn num_balls(&self) -> u32 {
344        let result = unsafe { sys::SDL_JoystickNumBalls(self.raw) };
345
346        if result < 0 {
347            // Should only fail if the joystick is NULL.
348            panic!("{}", get_error())
349        } else {
350            result as u32
351        }
352    }
353
354    /// Return a pair `(dx, dy)` containing the difference in axis
355    /// position since the last poll
356    #[doc(alias = "SDL_JoystickGetBall")]
357    pub fn ball(&self, ball: u32) -> Result<(i32, i32), IntegerOrSdlError> {
358        use crate::common::IntegerOrSdlError::*;
359        let mut dx = 0;
360        let mut dy = 0;
361
362        let ball = validate_int(ball, "ball")?;
363        let result = unsafe { sys::SDL_JoystickGetBall(self.raw, ball, &mut dx, &mut dy) };
364
365        if result == 0 {
366            Ok((dx, dy))
367        } else {
368            Err(SdlError(get_error()))
369        }
370    }
371
372    /// Retrieve the number of balls for this joystick
373    #[doc(alias = "SDL_JoystickNumHats")]
374    pub fn num_hats(&self) -> u32 {
375        let result = unsafe { sys::SDL_JoystickNumHats(self.raw) };
376
377        if result < 0 {
378            // Should only fail if the joystick is NULL.
379            panic!("{}", get_error())
380        } else {
381            result as u32
382        }
383    }
384
385    /// Return the position of `hat` for this joystick
386    #[doc(alias = "SDL_JoystickGetHat")]
387    pub fn hat(&self, hat: u32) -> Result<HatState, IntegerOrSdlError> {
388        use crate::common::IntegerOrSdlError::*;
389        // Guess what? This function as well uses 0 to report an error
390        // but 0 is also a valid value (HatState::Centered). So we
391        // have to use the same hack as `axis`...
392        clear_error();
393
394        let hat = validate_int(hat, "hat")?;
395        let result = unsafe { sys::SDL_JoystickGetHat(self.raw, hat) };
396
397        let state = HatState::from_raw(result as u8);
398
399        if result != 0 {
400            Ok(state)
401        } else {
402            let err = get_error();
403
404            if err.is_empty() {
405                Ok(state)
406            } else {
407                Err(SdlError(err))
408            }
409        }
410    }
411
412    /// Set the rumble motors to their specified intensities, if supported.
413    /// Automatically resets back to zero after `duration_ms` milliseconds have passed.
414    ///
415    /// # Notes
416    ///
417    /// The value range for the intensities is 0 to 0xFFFF.
418    ///
419    /// Do *not* use `std::u32::MAX` or similar for `duration_ms` if you want
420    /// the rumble effect to keep playing for a long time, as this results in
421    /// the effect ending immediately after starting due to an overflow.
422    /// Use some smaller, "huge enough" number instead.
423    #[doc(alias = "SDL_JoystickRumble")]
424    pub fn set_rumble(
425        &mut self,
426        low_frequency_rumble: u16,
427        high_frequency_rumble: u16,
428        duration_ms: u32,
429    ) -> Result<(), IntegerOrSdlError> {
430        let result = unsafe {
431            sys::SDL_JoystickRumble(
432                self.raw,
433                low_frequency_rumble,
434                high_frequency_rumble,
435                duration_ms,
436            )
437        };
438
439        if result != 0 {
440            Err(IntegerOrSdlError::SdlError(get_error()))
441        } else {
442            Ok(())
443        }
444    }
445
446    /// Start a rumble effect in the joystick's triggers.
447    #[doc(alias = "SDL_JoystickRumbleTriggers")]
448    pub fn set_rumble_triggers(
449        &mut self,
450        left_rumble: u16,
451        right_rumble: u16,
452        duration_ms: u32,
453    ) -> Result<(), IntegerOrSdlError> {
454        let result = unsafe {
455            sys::SDL_JoystickRumbleTriggers(self.raw, left_rumble, right_rumble, duration_ms)
456        };
457
458        if result != 0 {
459            Err(IntegerOrSdlError::SdlError(get_error()))
460        } else {
461            Ok(())
462        }
463    }
464
465    /// Query whether a joystick has an LED.
466    #[doc(alias = "SDL_JoystickHasLED")]
467    pub fn has_led(&self) -> bool {
468        let result = unsafe { sys::SDL_JoystickHasLED(self.raw) };
469
470        match result {
471            sys::SDL_bool::SDL_FALSE => false,
472            sys::SDL_bool::SDL_TRUE => true,
473        }
474    }
475
476    /// Query whether a joystick has rumble support.
477    #[doc(alias = "SDL_JoystickHasRumble")]
478    pub fn has_rumble(&self) -> bool {
479        let result = unsafe { sys::SDL_JoystickHasRumble(self.raw) };
480
481        match result {
482            sys::SDL_bool::SDL_FALSE => false,
483            sys::SDL_bool::SDL_TRUE => true,
484        }
485    }
486
487    /// Query whether a joystick has rumble support on triggers.
488    #[doc(alias = "SDL_JoystickHasRumbleTriggers")]
489    pub fn has_rumble_triggers(&self) -> bool {
490        let result = unsafe { sys::SDL_JoystickHasRumbleTriggers(self.raw) };
491
492        match result {
493            sys::SDL_bool::SDL_FALSE => false,
494            sys::SDL_bool::SDL_TRUE => true,
495        }
496    }
497
498    /// Update a joystick's LED color.
499    #[doc(alias = "SDL_JoystickSetLED")]
500    pub fn set_led(&mut self, red: u8, green: u8, blue: u8) -> Result<(), IntegerOrSdlError> {
501        let result = unsafe { sys::SDL_JoystickSetLED(self.raw, red, green, blue) };
502
503        if result != 0 {
504            Err(IntegerOrSdlError::SdlError(get_error()))
505        } else {
506            Ok(())
507        }
508    }
509
510    /// Send a joystick specific effect packet.
511    #[doc(alias = "SDL_JoystickSendEffect")]
512    pub fn send_effect(&mut self, data: &[u8]) -> Result<(), IntegerOrSdlError> {
513        let result = unsafe {
514            sys::SDL_JoystickSendEffect(
515                self.raw,
516                data.as_ptr() as *const libc::c_void,
517                data.len() as i32,
518            )
519        };
520
521        if result != 0 {
522            Err(IntegerOrSdlError::SdlError(get_error()))
523        } else {
524            Ok(())
525        }
526    }
527
528    /// Set player index for joystick or `None` to clear the player index and turn off player LEDs.
529    #[doc(alias = "SDL_JoystickSetPlayerIndex")]
530    pub fn set_player_index(&mut self, player_index: Option<u32>) -> Result<(), IntegerOrSdlError> {
531        let player_index = match player_index {
532            None => -1,
533            Some(player_index) => validate_int(player_index, "player_index")?,
534        };
535
536        unsafe { sys::SDL_JoystickSetPlayerIndex(self.raw, player_index) };
537
538        Ok(())
539    }
540
541    /// Get player index for joystick or `None` if it's not available.
542    #[doc(alias = "SDL_JoystickGetPlayerIndex")]
543    pub fn get_player_index(&self) -> Option<u32> {
544        let player_index = unsafe { sys::SDL_JoystickGetPlayerIndex(self.raw) };
545
546        // if index is -1 (or less than 0), joystick has no player
547        if player_index < 0 {
548            None
549        } else {
550            Some(player_index as u32)
551        }
552    }
553}
554
555impl Drop for Joystick {
556    #[doc(alias = "SDL_JoystickClose")]
557    fn drop(&mut self) {
558        if self.attached() {
559            unsafe { sys::SDL_JoystickClose(self.raw) }
560        }
561    }
562}
563
564/// Wrapper around a `SDL_JoystickGUID`, a globally unique identifier
565/// for a joystick.
566#[derive(Copy, Clone)]
567pub struct Guid {
568    raw: sys::SDL_JoystickGUID,
569}
570
571impl PartialEq for Guid {
572    fn eq(&self, other: &Guid) -> bool {
573        self.raw.data == other.raw.data
574    }
575}
576
577impl Eq for Guid {}
578
579impl Guid {
580    /// Create a GUID from a string representation.
581    #[doc(alias = "SDL_JoystickGetGUIDFromString")]
582    pub fn from_string(guid: &str) -> Result<Guid, NulError> {
583        let guid = CString::new(guid)?;
584
585        let raw = unsafe { sys::SDL_JoystickGetGUIDFromString(guid.as_ptr() as *const c_char) };
586
587        Ok(Guid { raw })
588    }
589
590    /// Return `true` if GUID is full 0s
591    pub fn is_zero(&self) -> bool {
592        for &i in &self.raw.data {
593            if i != 0 {
594                return false;
595            }
596        }
597
598        true
599    }
600
601    /// Return a String representation of GUID
602    #[doc(alias = "SDL_JoystickGetGUIDString")]
603    pub fn string(&self) -> String {
604        // Doc says "buf should supply at least 33bytes". I took that
605        // to mean that 33bytes should be enough in all cases, but
606        // maybe I'm wrong?
607        let mut buf = [0; 33];
608
609        let len = buf.len() as i32;
610        let c_str = buf.as_mut_ptr();
611
612        unsafe {
613            sys::SDL_JoystickGetGUIDString(self.raw, c_str, len);
614        }
615
616        // The buffer should always be NUL terminated (the
617        // documentation doesn't explicitly say it but I checked the
618        // code)
619        if c_str.is_null() {
620            String::new()
621        } else {
622            unsafe {
623                CStr::from_ptr(c_str as *const _)
624                    .to_str()
625                    .unwrap()
626                    .to_string()
627            }
628        }
629    }
630
631    /// Return a copy of the internal SDL_JoystickGUID
632    pub fn raw(self) -> sys::SDL_JoystickGUID {
633        self.raw
634    }
635}
636
637impl Display for Guid {
638    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
639        write!(f, "{}", self.string())
640    }
641}
642
643/// This is represented in SDL2 as a bitfield but obviously not all
644/// combinations make sense: 5 for instance would mean up and down at
645/// the same time... To simplify things I turn it into an enum which
646/// is how the SDL2 docs present it anyway (using macros).
647#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
648pub enum HatState {
649    Centered = 0,
650    Up = 0x01,
651    Right = 0x02,
652    Down = 0x04,
653    Left = 0x08,
654    RightUp = 0x02 | 0x01,
655    RightDown = 0x02 | 0x04,
656    LeftUp = 0x08 | 0x01,
657    LeftDown = 0x08 | 0x04,
658}
659
660impl HatState {
661    pub fn from_raw(raw: u8) -> HatState {
662        match raw {
663            0 => HatState::Centered,
664            1 => HatState::Up,
665            2 => HatState::Right,
666            4 => HatState::Down,
667            8 => HatState::Left,
668            3 => HatState::RightUp,
669            6 => HatState::RightDown,
670            9 => HatState::LeftUp,
671            12 => HatState::LeftDown,
672
673            // The Xinput driver on Windows can report hat states on certain hardware that don't
674            // make any sense from a gameplay perspective, and so aren't worth putting in the
675            // HatState enumeration.
676            _ => HatState::Centered,
677        }
678    }
679
680    pub fn to_raw(self) -> u8 {
681        match self {
682            HatState::Centered => 0,
683            HatState::Up => 1,
684            HatState::Right => 2,
685            HatState::Down => 4,
686            HatState::Left => 8,
687            HatState::RightUp => 3,
688            HatState::RightDown => 6,
689            HatState::LeftUp => 9,
690            HatState::LeftDown => 12,
691        }
692    }
693}
694
695/// Convert C string `c_str` to a String. Return an empty string if
696/// `c_str` is NULL.
697fn c_str_to_string(c_str: *const c_char) -> String {
698    if c_str.is_null() {
699        String::new()
700    } else {
701        let bytes = unsafe { CStr::from_ptr(c_str as *const _).to_bytes() };
702
703        String::from_utf8_lossy(bytes).to_string()
704    }
705}