При попытке найти более простой способ обработки приведения к типам ржавчины при чтении бинарного файла с использованием его XML-описания было предложено использовать перечисление с типами единиц измерения вместо десериализации строки или &str, чтобы получить больше гарантий от компилятор и избежать времени жизни; однако получение XML для десериализации непосредственно в варианты единиц перечисления вызывает некоторые проблемы.
<Records>
<Record>
<name>Single</name>
<number>1</number>
<location>0</location>
<data_type>IEEE754LSBSingle</data_type>
<length>4</length>
</Record>
<Record>
<name>Double</name>
<number>2</number>
<location>4</location>
<data_type>IEEE754LSBDouble</data_type>
<length>8</length>
</Record>
<Record>
<name>SingleArr</name>
<number>3</number>
<location>11</location>
<data_type>IEEE754LSBSingleArr</data_type>
<length>8</length>
</Record>
<Record>
<name>DoubleArr</name>
<number>4</number>
<location>18</location>
<data_type>IEEE754LSBDoubleArr</data_type>
<length>16</length>
</Record>
</Records>
use binary_type_cast::PrettyPrint;
use quick_xml::{de::from_reader, DeError};
use serde::{Deserialize};
use std::{fs::File, io::BufReader};
#[derive(Clone, Copy, Debug, Deserialize)]
//#[serde(tag = "data_type")]
//#[serde(untagged)]
pub enum DataTypes {
// 4 bytes
IEEE754LSBSingle,
// 8 bytes
IEEE754LSBDouble,
// [4 bytes, 4 bytes]
IEEE754LSBSingleArr,
// [8 bytes, 8 bytes]
IEEE754LSBDoubleArr,
// Include ASCIIString just to make sure records are still gathered even if none of them use this
ASCIIString,
}
#[derive(Debug, Deserialize)]
pub struct Records {
#[serde(rename = "Record")]
pub records: Vec<Record>,
}
#[derive(Debug, Deserialize)]
pub struct Record {
pub name: String,
pub number: u32,
pub location: u32,
//#[serde(flatten)]
pub data_type: DataTypes,
pub length: u32
}
pub fn get_xml_record(file: &File) -> Result<Records, DeError> {
let reader = BufReader::new(file);
let records: Records = from_reader(reader).unwrap();
Ok(records)
}
fn main() {
let description = "./data/desc.xml";
if let Ok(file) = File::open(description) {
if let Ok(records) = get_xml_record(&file) {
println!("{:#?}",records);
}
}
}
Я попытался реализовать различные комбинации закомментированных атрибутов serde, которые можно увидеть в представленном коде. Похоже, что создание пользовательского десериализатора, который будет сопоставлять строку из XML, а затем выводить связанный вариант DataTypes, будет по существу повторять поведение исходного сообщения в другой проблеме, где строки сопоставлялись и преобразовывались вручную.
Похоже, это ошибка в quick-xml
Я заставил его работать без особой суеты, используя вместо этого serde-xml-rs:
use serde_xml_rs::from_str;
use serde::Deserialize;
#[derive(Clone, Copy, Debug, Deserialize)]
pub enum DataTypes {
// 4 bytes
IEEE754LSBSingle,
// 8 bytes
IEEE754LSBDouble,
// [4 bytes, 4 bytes]
IEEE754LSBSingleArr,
// [8 bytes, 8 bytes]
IEEE754LSBDoubleArr,
// Include ASCIIString just to make sure records are still gathered even if none of them use this
ASCIIString,
}
#[derive(Debug, Deserialize)]
pub struct Records {
#[serde(rename = "$value")]
pub records: Vec<Record>,
}
#[derive(Debug, Deserialize)]
pub struct Record {
pub name: String,
pub number: u32,
pub location: u32,
pub data_type: DataTypes,
pub length: u32
}
fn main() {
let source = r##"
<Records>
<Record>
<name>Single</name>
<number>1</number>
<location>0</location>
<data_type>IEEE754LSBSingle</data_type>
<length>4</length>
</Record>
<Record>
<name>Double</name>
<number>2</number>
<location>4</location>
<data_type>IEEE754LSBDouble</data_type>
<length>8</length>
</Record>
<Record>
<name>SingleArr</name>
<number>3</number>
<location>11</location>
<data_type>IEEE754LSBSingleArr</data_type>
<length>8</length>
</Record>
<Record>
<name>DoubleArr</name>
<number>4</number>
<location>18</location>
<data_type>IEEE754LSBDoubleArr</data_type>
<length>16</length>
</Record>
</Records>
"##;
let records: Records = from_str(source).unwrap();
dbg!(records);
}
Вывод:
[src\main.rs:71] records = Records {
records: [
Record {
name: "Single",
number: 1,
location: 0,
data_type: IEEE754LSBSingle,
length: 4,
},
Record {
name: "Double",
number: 2,
location: 4,
data_type: IEEE754LSBDouble,
length: 8,
},
Record {
name: "SingleArr",
number: 3,
location: 11,
data_type: IEEE754LSBSingleArr,
length: 8,
},
Record {
name: "DoubleArr",
number: 4,
location: 18,
data_type: IEEE754LSBDoubleArr,
length: 16,
},
],
}
Спасибо. Это также работает с
from_reader