Skip to main content

UnsavedFs

Struct UnsavedFs 

Source
pub struct UnsavedFs {
    pub meta: WorldMeta,
    pub worlds: HashMap<usize, UnsavedWorld>,
    pub prefabs: IndexMap<String, Vec<u8>>,
}
Expand description

All of the dynamic data needed to serialize a world

Fields§

§meta: WorldMeta

Meta/

§worlds: HashMap<usize, UnsavedWorld>

World/

§prefabs: IndexMap<String, Vec<u8>>

Prefabs/ - embedded prefab archives, root-relative path → raw bytes.

Implementations§

Source§

impl UnsavedFs

Source

pub fn to_pending(self) -> Result<BrPendingFs, BrError>

Examples found in repository?
examples/write_fixtures.rs (line 380)
365fn spawner_world() -> World {
366    // Prefab-embedding fixture: an outer prefab whose spawner gate references
367    // an inner single-brick prefab embedded at Prefabs/Uploads/<BLAKE3>.brz.
368    // Single grid, single chunk, one insertion-ordered prefab map entry —
369    // fully deterministic. The inner archive is written raw (no zstd) so the
370    // embedded bytes are cross-language reproducible.
371    let mut inner = World::new();
372    inner.meta.bundle.description = "Inner prefab".to_string();
373    inner.bricks.push(Brick {
374        position: (0, 0, 6).into(),
375        color: (255, 0, 0).into(),
376        ..Default::default()
377    });
378    inner.make_prefab();
379    let inner_bytes = {
380        let pending = inner.to_unsaved().unwrap().to_pending().unwrap();
381        let mut buf = Vec::new();
382        pending
383            .to_brz_data(None)
384            .unwrap()
385            .write(&mut buf, None)
386            .unwrap();
387        buf
388    };
389
390    let mut world = World::new();
391    world.register_all_components();
392    world.meta.bundle.description = "Spawner fixture".to_string();
393    let prefab_path = world.add_prefab(inner_bytes);
394    world.bricks.push(
395        Brick {
396            asset: brdb::BrickType::str("B_1x1_Gate_Exec_PrefabSpawner"),
397            position: (0, 0, 1).into(),
398            ..Default::default()
399        }
400        .with_component(
401            assets::LiteralComponent::new("BrickComponentType_WireGraph_Exec_PrefabSpawner")
402                .with_data([(
403                    "Prefab",
404                    Box::new(prefab_path) as Box<dyn AsBrdbValue>,
405                )]),
406        ),
407    );
408    world.make_prefab();
409    world
410}
411
412fn hash_archive(path: &PathBuf) -> Result<BTreeMap<String, serde_json::Value>, Box<dyn std::error::Error>> {
413    fn collect(fs: &BrFs, prefix: &str, out: &mut Vec<(String, Option<i64>)>) {
414        match fs {
415            BrFs::Root(children) => for (n, c) in children { collect(c, n, out); },
416            BrFs::Folder(_, children) => for (n, c) in children {
417                collect(c, &format!("{prefix}/{n}"), out);
418            },
419            BrFs::File(f) => out.push((prefix.to_string(), f.content_id)),
420        }
421    }
422    let reader = Brz::open(path)?.into_reader();
423    let reader = &*reader;
424    let mut files = Vec::new();
425    collect(&reader.get_fs()?, "", &mut files);
426    let mut out = BTreeMap::new();
427    for (p, content_id) in files {
428        let content = match content_id {
429            Some(id) => reader.find_blob(id)?.read()?,
430            None => Vec::new(),
431        };
432        out.insert(p, serde_json::json!({
433            "blake3": blake3::hash(&content).to_hex().to_string(),
434            "len": content.len(),
435        }));
436    }
437    Ok(out)
438}
439
440fn main() -> Result<(), Box<dyn std::error::Error>> {
441    let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("fixtures");
442    fs::create_dir_all(dir.join("schemas"))?;
443
444    let mut hashes = BTreeMap::new();
445    for (name, world) in [
446        ("brick", brick_world()),
447        ("features", features_world()),
448        ("chunks", chunks_world()),
449        ("wires", wires_world()),
450        ("components", components_world()),
451        ("entities", entities_world()),
452        ("spawner", spawner_world()),
453    ] {
454        let pending = world.to_unsaved()?.to_pending()?;
455        // raw variant: no zstd anywhere — byte-comparable across languages
456        let raw_path = dir.join(format!("{name}_raw.brz"));
457        let mut f = fs::File::create(&raw_path)?;
458        pending.clone().to_brz_data(None)?.write(&mut f, None)?;
459        // compressed variant: zstd level 14 (matches Brz::save)
460        let mut f = fs::File::create(dir.join(format!("{name}.brz")))?;
461        pending.to_brz_data(Some(14))?.write(&mut f, Some(14))?;
462
463        // .brdb variant: content parity only (the .brdb container is not
464        // byte-deterministic across runs).
465        let db_path = dir.join(format!("{name}.brdb"));
466        let _ = fs::remove_file(&db_path);
467        Brdb::create(&db_path)?.save("Fixture", &world)?;
468
469        hashes.insert(name.to_string(), hash_archive(&raw_path)?);
470    }
471    fs::write(dir.join("hashes.json"), serde_json::to_string_pretty(&hashes)?)?;
472
473    // The nine embedded schemas as binary msgpack (the exact bytes the
474    // writer embeds as *.schema files inside archives).
475    for (name, schema) in [
476        ("BRSavedGlobalDataSoA", schemas::global_data_schema()),
477        ("BRSavedOwnerTableSoA", schemas::owners_schema()),
478        ("BRSavedBrickChunkIndexSoA", schemas::bricks_chunk_index_schema()),
479        ("BRSavedBrickChunkSoA", schemas::bricks_chunks_schema()),
480        ("BRSavedWireChunkSoA", schemas::bricks_wires_schema()),
481        ("BRSavedComponentChunkSoA", schemas::bricks_components_schema_min()),
482        ("BRSavedComponentChunkSoA_max", schemas::bricks_components_schema_max()),
483        ("BRSavedEntityChunkIndexSoA", schemas::entities_chunk_index_schema()),
484        ("BRSavedEntityChunkSoA", schemas::entities_chunks_schema()),
485    ] {
486        fs::write(dir.join(format!("schemas/{name}.bin")), schema.to_bytes()?)?;
487    }
488    eprintln!("fixtures written to {}", dir.display());
489    Ok(())
490}

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.