LINUX.ORG.RU

Форматированный вывод в строку без аллокации

 


0

3

Собственно, всё, до чего додумался:

use std::str;
use std::mem;
use std::io::Write;
use std::ffi::CStr;

fn main() {
    let mut buffer = unsafe { mem::uninitialized::<[u8; 100]>() };
    if write!(&mut buffer[..], "{}\0", 42).is_err() {
        *buffer.last_mut().unwrap() = 0;
    }
    let string = unsafe {
        str::from_utf8_unchecked(
            CStr::from_ptr(buffer.as_ptr() as *const i8).to_bytes())
    };
    println!("{}", string);
}

Кто-нибудь может подсказать более лаконичный/менее костыльный способ с аналогичной производительностью?

Олсо, интересует способ конвертации числа в строку без аллокации и вовлечения всей этой форматирующей машинерии. Ясно, что она работает большей частью в компайл-тайме и оверхэд небольшой, но всё же он есть.


Кто-нибудь может подсказать более лаконичный/менее костыльный способ с аналогичной производительностью?

В стандартной библиотеке я его не вижу, но можно написать обёртку над массивом, которая будет реализовывать core::fmt::Write и которая будет возвращать &str.

Олсо, интересует способ конвертации числа в строку без аллокации и вовлечения всей этой форматирующей машинерии.

Судя по всему, преобразования в строку завязаны на Display/Debug, т.е без форматирования не обойтись.

А для каких задач тебе всё это нужно?

quantum-troll ★★★★★ ()
Последнее исправление: quantum-troll (всего исправлений: 1)
Ответ на: комментарий от quantum-troll

можно написать обёртку над массивом, которая будет реализовывать core::fmt::Write

«This trait should generally not be implemented by consumers of the standard library.»

Может, ты имел в виду std::io::Write?

которая будет возвращать &str

Не вижу, как это поможет мне избавиться от костыля с "{}\0" и CStr.

А для каких задач тебе всё это нужно?

Пока ни для каких. Просто тыкаю руст на предмет удобства писать на нём под эмбед.

Esper ()
Ответ на: комментарий от Esper

Строку можно получить с помощью str::from_utf8_unchecked, но для этого нужно знать размер строки. Этот размер можно узнать, инкрементируя счётчик при каждом вызове `write_str()`. Тогда CStr будет не нужен.

std

Ты скорее всего сделаешь `#![no_std]`, так что нет.

quantum-troll ★★★★★ ()
Ответ на: комментарий от quantum-troll

Этот размер можно узнать, инкрементируя счётчик при каждом вызове `write_str()`.

Я уже думал об этом. Мне не нравится возможность такой стрельбы по ногам:

let buffer = MyBuffer<[u8; 100]>::new();
write!(buffer, "{}", 42);
println!("{}", buffer.as_str());
write!(buffer, "{}", 24); // Тут буфер перезапишется, а счётчик будет инкрементироваться дальше

Ты скорее всего сделаешь `#![no_std]`

Да пофиг, оно и в core есть. Но write_str в io::Write нету, да.

Esper ()
Ответ на: комментарий от Esper

Мне не нравится возможность такой стрельбы по ногам

Upd: я сразу не подумал, что данные буфера можно не тупо перезаписывать, а добавлять к ним результат очередной записи.

Такое поведение мне несколько неочевидно, но можно привыкнуть.

Если интересно, вот к чему я в итоге пришёл:

https://is.gd/tMytTA

В принципе, годный вариант, спасибо quantum-troll.

Esper ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.