#fortran #input #parser #group #derive-deserialize #format #namelist

nml

Fortran Namelist 格式的解析器和 Serde 实现

2 个不稳定版本

0.2.0 2024年2月18日
0.1.0 2023年11月1日

#1500 in 编码

MIT/Apache

84KB
2K SLoC

nml

使用 Rust 和 serde 框架序列化和反序列化 Fortran namelist 输入。

用法

use serde::Deserialize;

#[derive(Deserialize, Debug)]
struct Particle {
    index: i32,
    position: [f32; 3],
    velocity: [f32; 3]
}

fn main() -> Result<(), nml::NamelistError>{
    let s = r#"
      &particle
       index = 0,
       position = 0.0, 0.0, 0.0,
       velocity = 1.0, 0.0, 0.0,
      /"#;

  let particle: Particle = nml::group_from_str(s)?.1;
  println!("{:#?}", particle);

  Ok(())
}

lib.rs:

Fortran Namelist 输入的 serde 库。

Namelist 是 Fortran 90 的一种特性,用于以键值赋值格式输入和输出变量组。

&particle
 timestep = 0,
 mass = 1.0
 position = 1.0, 1.0, 1.0,
 velocity = -1.0, 0.0, 0.0
/

此 namelist 组分配一个整型变量 timestep,一个浮点型/实型变量 masss 和两个实型数组 positionvelocity。namelist 输入格式支持的进一步数据类型包括布尔值/逻辑值(用 .TRUE..FALSE. 赋值)和字符串(由单引号 'hello' 或双引号 "hello" 表示)

用法

要将 Rust 结构体(或映射)序列化和反序列化为 Namelist 组,可以使用 group_from_strgroup_to_string 方法

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Particle {
    timestep: i32,
    mass: f32,
    position: [f32; 3],
    velocity: [f32; 3]
}

fn main() -> Result<(), nml::NamelistError> {
    let p = Particle {
        timestep: 0,
        mass: 1.0,
        position: [0.0, 0.0, 0.0],
        velocity: [-1.0, 0.0, 0.0]
    };

    let serialized = nml::group_to_string(p)?;
    let deserialized = nml::group_from_str(&serialized)?;

    assert_eq!(p, deserialized);
    Ok(())
}

要从单个输入中反序列化多个 Namelist 组(具有相同或不同的组名)到 Rust 结构体或映射,可以使用 NamelistInput 类型

use serde::Deserialize;
#[derive(Deserialize, Debug)]
struct Simulation {
    start_time: i32,
    timesteps: i32
}

#[derive(Deserialize, Debug)]
struct Particle {
   index: i32,
   position: [f32; 3],
   velocity: [f32; 3]
}

fn main() -> Result<(), nml::NamelistError>{
   let s = r#"
       &simulation
         start_time: 0,
         timesteps: 10,
       /
       &particle
        index = 0,
        position = 0.0, 0.0, 0.0,
        velocity = 1.0, 0.0, 0.0,
       /
       &particle
        index = 1,
        position = 1.0, 0.0, 0.0,
        velocity = -1.0, 0.0, 0.0,
       /"#;

   let input = NamelistInput::try_from_str(s)?;
   let mut simulation = None;
   let mut particles = Vec::new();

   for group in &input {
       if group.name() == "particle" {
           let particle = Particle::deserialize(group)?;
           particles.push(particle);
       } else if group.name() == "simulation" {
           simulation = Some(Simulation::deserialize(group)?);
       }
   }
   Ok(())
}

如你所见,NamelistInput 类型可以解析多个 namelist 组,并且可以被转换为迭代器,每次产生一个 GroupRefDeserializer 实例,对应输入中的每个 namelist 组。此类型可用于将 namelist 组反序列化为 Rust 结构体或映射。

支持的 Namelist 语法

支持

  • 所有基本数据类型,整数逻辑字符串实数
  • 数组:使用下标分配序列和单个元素
  • 派生类型

不支持:

  • 涉及切片操作符 : 的任何内容,例如:var(1:3) = 1, 2, 3,
  • 将序列赋值给下标变量,即 var(1) = 1, 2, 3

依赖关系

~110–350KB