Как я могу использовать формат! макрос в среде no_std? - PullRequest
0 голосов
/ 06 мая 2018

Как реализовать следующий пример без использования std?

let text = format!("example {:.1} test {:x} words {}", num1, num2, num3);

text имеет тип &str, а num1, num2 и num3 имеют любой числовой тип.

Я пытался использовать numtoa и itoa/dtoa для отображения чисел, но numtoa не поддерживает числа с плавающей запятой и itoa не поддерживает no_std.Мне кажется, что отображение числа в строке довольно распространено, и я, вероятно, упускаю что-то очевидное.

Ответы [ 2 ]

0 голосов
/ 06 мая 2018

В дополнение к Ответ Шепмастера вы также можете форматировать строки без распределителя.

В core::fmt::Write вам нужно только реализовать write_str, и тогда вы получите write_fmt бесплатно.

С помощью format_args!(...) (тот же синтаксис, что и format!), вы можете подготовить значение core::fmt::Arguments, которое можно передать в core::fmt::write.

См. Детская площадка :

#![crate_type = "dylib"]
#![no_std]

pub mod write_to {
    use core::cmp::min;
    use core::fmt;

    pub struct WriteTo<'a> {
        buffer: &'a mut [u8],
        // on write error (i.e. not enough space in buffer) this grows beyond
        // `buffer.len()`.
        used: usize,
    }

    impl<'a> WriteTo<'a> {
        pub fn new(buffer: &'a mut [u8]) -> Self {
            WriteTo { buffer, used: 0 }
        }

        pub fn as_str(self) -> Option<&'a str> {
            if self.used <= self.buffer.len() {
                // only successful concats of str - must be a valid str.
                use core::str::from_utf8_unchecked;
                Some(unsafe { from_utf8_unchecked(&self.buffer[..self.used]) })
            } else {
                None
            }
        }
    }

    impl<'a> fmt::Write for WriteTo<'a> {
        fn write_str(&mut self, s: &str) -> fmt::Result {
            if self.used > self.buffer.len() {
                return Err(fmt::Error);
            }
            let remaining_buf = &mut self.buffer[self.used..];
            let raw_s = s.as_bytes();
            let write_num = min(raw_s.len(), remaining_buf.len());
            remaining_buf[..write_num].copy_from_slice(&raw_s[..write_num]);
            self.used += raw_s.len();
            if write_num < raw_s.len() {
                Err(fmt::Error)
            } else {
                Ok(())
            }
        }
    }

    pub fn show<'a>(buffer: &'a mut [u8], args: fmt::Arguments) -> Result<&'a str, fmt::Error> {
        let mut w = WriteTo::new(buffer);
        fmt::write(&mut w, args)?;
        w.as_str().ok_or(fmt::Error)
    }
}

pub fn test() {
    let mut buf = [0u8; 64];
    let _s: &str = write_to::show(
        &mut buf,
        format_args!("write some stuff {:?}: {}", "foo", 42),
    ).unwrap();
}
0 голосов
/ 06 мая 2018

В общем, вы не . format! выделяет String, а среда no_std не имеет распределителя.

Если у вас есть распределитель, вы можете использовать alloc crate . Этот ящик содержит макрос format!.

Этот ящик не стабилизирован, поэтому вам нужно использовать ночные ржавчины:

#![feature(alloc)]
#![crate_type = "dylib"]
#![no_std]

#[macro_use]
extern crate alloc;

fn thing() {
    let text = format!("example {:.1} test {:x} words {}", 1, 2, 3);
}

Смотри также:

...