NameIdMap, error handling clean-up
This commit is contained in:
parent
0f5bfc4971
commit
21ee17db58
@ -1,5 +1,7 @@
|
|||||||
# MapEditr
|
# MapEditr
|
||||||
|
|
||||||
|
TODO: Add a license.
|
||||||
|
|
||||||
MapEditr is a command-line tool for relatively fast manipulation of Minetest
|
MapEditr is a command-line tool for relatively fast manipulation of Minetest
|
||||||
worlds. It can replace nodes, fill areas, combine parts of different worlds,
|
worlds. It can replace nodes, fill areas, combine parts of different worlds,
|
||||||
and much more.
|
and much more.
|
||||||
|
@ -14,6 +14,9 @@ fn block_parts_valid(a: &Area, b: &Area) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Copy an area of nodes from one mapblock to another.
|
||||||
|
///
|
||||||
|
/// Will not remove duplicate/unused name IDs.
|
||||||
pub fn merge_blocks(
|
pub fn merge_blocks(
|
||||||
src_block: &MapBlock,
|
src_block: &MapBlock,
|
||||||
dst_block: &mut MapBlock,
|
dst_block: &mut MapBlock,
|
||||||
@ -24,14 +27,14 @@ pub fn merge_blocks(
|
|||||||
|
|
||||||
let src_nd = src_block.node_data.get_ref();
|
let src_nd = src_block.node_data.get_ref();
|
||||||
let dst_nd = dst_block.node_data.get_mut();
|
let dst_nd = dst_block.node_data.get_mut();
|
||||||
|
|
||||||
let offset = dst_area.min - src_area.min;
|
let offset = dst_area.min - src_area.min;
|
||||||
// Warning: diff can be negative!
|
// Warning: diff can be negative!
|
||||||
let diff = offset.x + offset.y * 16 + offset.z * 256;
|
let diff = offset.x + offset.y * 16 + offset.z * 256;
|
||||||
|
|
||||||
|
// Copy name-ID mappings
|
||||||
let nimap_diff = dst_block.nimap.get_max_id().unwrap() + 1;
|
let nimap_diff = dst_block.nimap.get_max_id().unwrap() + 1;
|
||||||
for (&id, name) in &src_block.nimap.map {
|
for (id, name) in &src_block.nimap.0 {
|
||||||
dst_block.nimap.insert(id + nimap_diff, name)
|
dst_block.nimap.0.insert(id + nimap_diff, name.to_vec());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy node IDs
|
// Copy node IDs
|
||||||
@ -65,6 +68,7 @@ pub fn merge_blocks(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Copy an area of node metadata from one mapblock to another.
|
||||||
pub fn merge_metadata(
|
pub fn merge_metadata(
|
||||||
src_meta: &NodeMetadataList,
|
src_meta: &NodeMetadataList,
|
||||||
dst_meta: &mut NodeMetadataList,
|
dst_meta: &mut NodeMetadataList,
|
||||||
@ -119,7 +123,7 @@ pub fn clean_name_id_map(block: &mut MapBlock) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = &block.nimap.map[&(id as u16)];
|
let name = &block.nimap.0[&(id as u16)];
|
||||||
if let Some(first_id) = new_nimap.iter().position(|(_, v)| v == name) {
|
if let Some(first_id) = new_nimap.iter().position(|(_, v)| v == name) {
|
||||||
// Name is already in the map; map old, duplicate ID to the
|
// Name is already in the map; map old, duplicate ID to the
|
||||||
// existing ID.
|
// existing ID.
|
||||||
@ -131,7 +135,7 @@ pub fn clean_name_id_map(block: &mut MapBlock) {
|
|||||||
map[id] = new_nimap.len() as u16 - 1;
|
map[id] = new_nimap.len() as u16 - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
block.nimap.map = new_nimap;
|
block.nimap.0 = new_nimap;
|
||||||
|
|
||||||
// Re-assign node IDs.
|
// Re-assign node IDs.
|
||||||
for id in &mut nd.nodes {
|
for id in &mut nd.nodes {
|
||||||
|
@ -60,10 +60,10 @@ fn clone(inst: &mut InstBundle) {
|
|||||||
opt_unwrap_or!(
|
opt_unwrap_or!(
|
||||||
get_cached(&mut inst.db, &mut block_cache, dst_key),
|
get_cached(&mut inst.db, &mut block_cache, dst_key),
|
||||||
continue
|
continue
|
||||||
).and_then(|b|
|
).and_then(|b| -> Result<_, MapBlockError> {
|
||||||
NodeMetadataList::deserialize(b.metadata.get_ref())
|
let m = NodeMetadataList::deserialize(b.metadata.get_ref())?;
|
||||||
.map(|m| (b, m))
|
Ok((b, m))
|
||||||
),
|
}),
|
||||||
{ inst.status.inc_failed(); continue; }
|
{ inst.status.inc_failed(); continue; }
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -79,12 +79,13 @@ fn clone(inst: &mut InstBundle) {
|
|||||||
}
|
}
|
||||||
let src_key = src_pos.to_block_key();
|
let src_key = src_pos.to_block_key();
|
||||||
let (src_block, src_meta) = opt_unwrap_or!(
|
let (src_block, src_meta) = opt_unwrap_or!(
|
||||||
get_cached(&mut inst.db, &mut block_cache, src_key)
|
|| -> Option<_> {
|
||||||
.map(Result::ok).flatten()
|
let b = get_cached(
|
||||||
.and_then(|b|
|
&mut inst.db, &mut block_cache, src_key)?.ok()?;
|
||||||
NodeMetadataList::deserialize(b.metadata.get_ref())
|
let m = NodeMetadataList::deserialize(b.metadata.get_ref())
|
||||||
.ok().map(|m| (b, m))
|
.ok()?;
|
||||||
),
|
Some((b, m))
|
||||||
|
}(),
|
||||||
continue
|
continue
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ use super::Command;
|
|||||||
use crate::unwrap_or;
|
use crate::unwrap_or;
|
||||||
use crate::spatial::{Vec3, Area, area_rel_block_overlap, area_contains_block};
|
use crate::spatial::{Vec3, Area, area_rel_block_overlap, area_contains_block};
|
||||||
use crate::instance::{ArgType, InstBundle};
|
use crate::instance::{ArgType, InstBundle};
|
||||||
use crate::map_block::{MapBlock};
|
use crate::map_block::MapBlock;
|
||||||
use crate::block_utils::clean_name_id_map;
|
use crate::block_utils::clean_name_id_map;
|
||||||
use crate::utils::{query_keys, to_bytes, fmt_big_num};
|
use crate::utils::{query_keys, to_bytes, fmt_big_num};
|
||||||
|
|
||||||
@ -47,14 +47,14 @@ fn fill(inst: &mut InstBundle) {
|
|||||||
for x in &mut nd.nodes {
|
for x in &mut nd.nodes {
|
||||||
*x = 0;
|
*x = 0;
|
||||||
}
|
}
|
||||||
block.nimap.map.clear();
|
block.nimap.0.clear();
|
||||||
block.nimap.insert(0, &node);
|
block.nimap.0.insert(0, node.to_vec());
|
||||||
count += nd.nodes.len() as u64;
|
count += nd.nodes.len() as u64;
|
||||||
} else {
|
} else {
|
||||||
let slice = area_rel_block_overlap(&area, pos).unwrap();
|
let slice = area_rel_block_overlap(&area, pos).unwrap();
|
||||||
let fill_id = block.nimap.get_id(&node).unwrap_or_else(|| {
|
let fill_id = block.nimap.get_id(&node).unwrap_or_else(|| {
|
||||||
let next = block.nimap.get_max_id().unwrap() + 1;
|
let next = block.nimap.get_max_id().unwrap() + 1;
|
||||||
block.nimap.insert(next, &node);
|
block.nimap.0.insert(next, node.to_vec());
|
||||||
next
|
next
|
||||||
});
|
});
|
||||||
fill_area(&mut block, slice, fill_id);
|
fill_area(&mut block, slice, fill_id);
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
use super::{Command, BLOCK_CACHE_SIZE};
|
use super::{Command, BLOCK_CACHE_SIZE};
|
||||||
|
|
||||||
use crate::opt_unwrap_or;
|
use crate::{unwrap_or, opt_unwrap_or};
|
||||||
use crate::spatial::{Vec3, Area, area_rel_block_overlap,
|
use crate::spatial::{Vec3, Area, area_rel_block_overlap,
|
||||||
area_abs_block_overlap, area_contains_block, area_touches_block};
|
area_abs_block_overlap, area_contains_block, area_touches_block};
|
||||||
use crate::instance::{ArgType, InstArgs, InstBundle};
|
use crate::instance::{ArgType, InstArgs, InstBundle};
|
||||||
use crate::map_database::MapDatabase;
|
use crate::map_database::MapDatabase;
|
||||||
use crate::map_block::{MapBlock, MapBlockError, NodeMetadataList,
|
use crate::map_block::{MapBlock, NodeMetadataList, is_valid_generated,
|
||||||
is_valid_generated};
|
MapBlockError};
|
||||||
use crate::block_utils::{merge_blocks, merge_metadata, clean_name_id_map};
|
use crate::block_utils::{merge_blocks, merge_metadata, clean_name_id_map};
|
||||||
use crate::utils::{query_keys, CacheMap};
|
use crate::utils::{query_keys, CacheMap};
|
||||||
|
|
||||||
@ -29,11 +29,12 @@ fn verify_args(args: &InstArgs) -> anyhow::Result<()> {
|
|||||||
/// - Area + Invert
|
/// - Area + Invert
|
||||||
#[inline]
|
#[inline]
|
||||||
fn overlay_no_offset(inst: &mut InstBundle) {
|
fn overlay_no_offset(inst: &mut InstBundle) {
|
||||||
let mut idb = inst.idb.as_mut().unwrap();
|
let db = &mut inst.db;
|
||||||
|
let idb = inst.idb.as_mut().unwrap();
|
||||||
let invert = inst.args.invert;
|
let invert = inst.args.invert;
|
||||||
|
|
||||||
// Get keys from input database.
|
// Get keys from input database.
|
||||||
let keys = query_keys(&mut idb, &inst.status,
|
let keys = query_keys(idb, &inst.status,
|
||||||
&[], inst.args.area, invert, true);
|
&[], inst.args.area, invert, true);
|
||||||
inst.status.begin_editing();
|
inst.status.begin_editing();
|
||||||
|
|
||||||
@ -48,50 +49,54 @@ fn overlay_no_offset(inst: &mut InstBundle) {
|
|||||||
{ // If possible, copy whole map block.
|
{ // If possible, copy whole map block.
|
||||||
let data = idb.get_block(key).unwrap();
|
let data = idb.get_block(key).unwrap();
|
||||||
if is_valid_generated(&data) {
|
if is_valid_generated(&data) {
|
||||||
inst.db.set_block(key, &data).unwrap();
|
db.set_block(key, &data).unwrap();
|
||||||
}
|
}
|
||||||
} else { // Copy part of map block
|
} else { // Copy part of map block
|
||||||
let dst_data = match inst.db.get_block(key) {
|
let res = || -> Result<(), MapBlockError> {
|
||||||
Ok(d) => if is_valid_generated(&d) {
|
let dst_data = opt_unwrap_or!(
|
||||||
d
|
db.get_block(key).ok()
|
||||||
|
.filter(|d| is_valid_generated(&d)),
|
||||||
|
return Ok(()));
|
||||||
|
let src_data = idb.get_block(key).unwrap();
|
||||||
|
|
||||||
|
let mut src_block = MapBlock::deserialize(&src_data)?;
|
||||||
|
let mut dst_block = MapBlock::deserialize(&dst_data)?;
|
||||||
|
let mut src_meta = NodeMetadataList::deserialize(
|
||||||
|
&src_block.metadata.get_ref())?;
|
||||||
|
let mut dst_meta = NodeMetadataList::deserialize(
|
||||||
|
&dst_block.metadata.get_ref())?;
|
||||||
|
|
||||||
|
let block_part = area_rel_block_overlap(&area, pos)
|
||||||
|
.unwrap();
|
||||||
|
if invert {
|
||||||
|
// For inverted selections, reverse the order of the
|
||||||
|
// overlay operations.
|
||||||
|
merge_blocks(&dst_block, &mut src_block,
|
||||||
|
block_part, block_part);
|
||||||
|
merge_metadata(&dst_meta, &mut src_meta,
|
||||||
|
block_part, block_part);
|
||||||
|
clean_name_id_map(&mut src_block);
|
||||||
|
db.set_block(key, &src_block.serialize()).unwrap();
|
||||||
} else {
|
} else {
|
||||||
continue;
|
merge_blocks(&src_block, &mut dst_block,
|
||||||
},
|
block_part, block_part);
|
||||||
Err(_) => continue
|
merge_metadata(&src_meta, &mut dst_meta,
|
||||||
};
|
block_part, block_part);
|
||||||
let src_data = idb.get_block(key).unwrap();
|
clean_name_id_map(&mut dst_block);
|
||||||
|
db.set_block(key, &dst_block.serialize()).unwrap();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}();
|
||||||
|
|
||||||
let mut src_block = MapBlock::deserialize(&src_data).unwrap();
|
if res.is_err() {
|
||||||
let mut dst_block = MapBlock::deserialize(&dst_data).unwrap();
|
inst.status.inc_failed()
|
||||||
let mut src_meta = NodeMetadataList::deserialize(
|
|
||||||
&src_block.metadata.get_ref()).unwrap();
|
|
||||||
let mut dst_meta = NodeMetadataList::deserialize(
|
|
||||||
&dst_block.metadata.get_ref()).unwrap();
|
|
||||||
|
|
||||||
let block_part = area_rel_block_overlap(&area, pos).unwrap();
|
|
||||||
if invert {
|
|
||||||
// For inverted selections, reverse the order of the
|
|
||||||
// overlay operations.
|
|
||||||
merge_blocks(&dst_block, &mut src_block,
|
|
||||||
block_part, block_part);
|
|
||||||
merge_metadata(&dst_meta, &mut src_meta,
|
|
||||||
block_part, block_part);
|
|
||||||
clean_name_id_map(&mut src_block);
|
|
||||||
inst.db.set_block(key, &src_block.serialize()).unwrap();
|
|
||||||
} else {
|
|
||||||
merge_blocks(&src_block, &mut dst_block,
|
|
||||||
block_part, block_part);
|
|
||||||
merge_metadata(&src_meta, &mut dst_meta,
|
|
||||||
block_part, block_part);
|
|
||||||
clean_name_id_map(&mut dst_block);
|
|
||||||
inst.db.set_block(key, &dst_block.serialize()).unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No area; copy whole map block.
|
// No area; copy whole map block.
|
||||||
let data = idb.get_block(key).unwrap();
|
let data = idb.get_block(key).unwrap();
|
||||||
if is_valid_generated(&data) {
|
if is_valid_generated(&data) {
|
||||||
inst.db.set_block(key, &data).unwrap();
|
db.set_block(key, &data).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,19 +105,17 @@ fn overlay_no_offset(inst: &mut InstBundle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type BlockResult = Option<Result<MapBlock, MapBlockError>>;
|
|
||||||
|
|
||||||
fn get_cached(
|
fn get_cached(
|
||||||
db: &mut MapDatabase,
|
db: &mut MapDatabase,
|
||||||
cache: &mut CacheMap<i64, BlockResult>,
|
cache: &mut CacheMap<i64, Option<MapBlock>>,
|
||||||
key: i64
|
key: i64
|
||||||
) -> BlockResult {
|
) -> Option<MapBlock> {
|
||||||
match cache.get(&key) {
|
match cache.get(&key) {
|
||||||
Some(data) => data.clone(),
|
Some(data) => data.clone(),
|
||||||
None => {
|
None => {
|
||||||
let block = db.get_block(key).ok()
|
let block = db.get_block(key).ok()
|
||||||
.filter(|d| is_valid_generated(d))
|
.filter(|d| is_valid_generated(d))
|
||||||
.map(|d| MapBlock::deserialize(&d));
|
.and_then(|d| MapBlock::deserialize(&d).ok());
|
||||||
cache.insert(key, block.clone());
|
cache.insert(key, block.clone());
|
||||||
block
|
block
|
||||||
}
|
}
|
||||||
@ -143,11 +146,12 @@ fn overlay_with_offset(inst: &mut InstBundle) {
|
|||||||
inst.db.get_block(dst_key).ok().filter(|d| is_valid_generated(d)),
|
inst.db.get_block(dst_key).ok().filter(|d| is_valid_generated(d)),
|
||||||
continue
|
continue
|
||||||
);
|
);
|
||||||
let (mut dst_block, mut dst_meta) = opt_unwrap_or!(
|
let (mut dst_block, mut dst_meta) = unwrap_or!(
|
||||||
MapBlock::deserialize(&dst_data).ok().and_then(|b|
|
|| -> Result<_, MapBlockError> {
|
||||||
NodeMetadataList::deserialize(b.metadata.get_ref())
|
let b = MapBlock::deserialize(&dst_data)?;
|
||||||
.ok().map(|m| (b, m))
|
let m = NodeMetadataList::deserialize(b.metadata.get_ref())?;
|
||||||
),
|
Ok((b, m))
|
||||||
|
}(),
|
||||||
{ inst.status.inc_failed(); continue; }
|
{ inst.status.inc_failed(); continue; }
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -164,12 +168,12 @@ fn overlay_with_offset(inst: &mut InstBundle) {
|
|||||||
}
|
}
|
||||||
let src_key = src_pos.to_block_key();
|
let src_key = src_pos.to_block_key();
|
||||||
let (src_block, src_meta) = opt_unwrap_or!(
|
let (src_block, src_meta) = opt_unwrap_or!(
|
||||||
get_cached(idb, &mut src_block_cache, src_key)
|
|| -> Option<_> {
|
||||||
.map(Result::ok).flatten()
|
let b = get_cached(idb, &mut src_block_cache, src_key)?;
|
||||||
.and_then(|b|
|
let m = NodeMetadataList::deserialize(b.metadata.get_ref())
|
||||||
NodeMetadataList::deserialize(b.metadata.get_ref())
|
.ok()?;
|
||||||
.ok().map(|m| (b, m))
|
Some((b, m))
|
||||||
),
|
}(),
|
||||||
continue
|
continue
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ fn do_replace(
|
|||||||
|
|
||||||
// Replacement node not yet in name-ID map; insert it.
|
// Replacement node not yet in name-ID map; insert it.
|
||||||
if new_replace_id && new_node_present {
|
if new_replace_id && new_node_present {
|
||||||
block.nimap.insert(replace_id, new_node);
|
block.nimap.0.insert(replace_id, new_node.to_vec());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search node was completely eliminated; shift IDs down.
|
// Search node was completely eliminated; shift IDs down.
|
||||||
@ -72,7 +72,7 @@ fn do_replace(
|
|||||||
nd.nodes[i] -= 1;
|
nd.nodes[i] -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
block.nimap.remove(search_id);
|
block.nimap.remove_shift(search_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Replace nodes in whole map block.
|
// Replace nodes in whole map block.
|
||||||
@ -81,7 +81,7 @@ fn do_replace(
|
|||||||
if let Some(mut replace_id) = block.nimap.get_id(new_node) {
|
if let Some(mut replace_id) = block.nimap.get_id(new_node) {
|
||||||
let _t = tk.get_timer("replace (non-unique replacement)");
|
let _t = tk.get_timer("replace (non-unique replacement)");
|
||||||
// Delete unused ID from name-ID map and shift IDs down.
|
// Delete unused ID from name-ID map and shift IDs down.
|
||||||
block.nimap.remove(search_id);
|
block.nimap.remove_shift(search_id);
|
||||||
// Shift replacement ID, if necessary.
|
// Shift replacement ID, if necessary.
|
||||||
replace_id -= (replace_id > search_id) as u16;
|
replace_id -= (replace_id > search_id) as u16;
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ fn do_replace(
|
|||||||
for id in &nd.nodes {
|
for id in &nd.nodes {
|
||||||
count += (*id == search_id) as u64;
|
count += (*id == search_id) as u64;
|
||||||
}
|
}
|
||||||
block.nimap.insert(search_id, new_node);
|
block.nimap.0.insert(search_id, new_node.to_vec());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
count
|
count
|
||||||
|
@ -2,7 +2,7 @@ use super::Command;
|
|||||||
|
|
||||||
use crate::spatial::{Vec3, Area, area_rel_block_overlap, area_contains_block};
|
use crate::spatial::{Vec3, Area, area_rel_block_overlap, area_contains_block};
|
||||||
use crate::instance::{ArgType, InstArgs, InstBundle};
|
use crate::instance::{ArgType, InstArgs, InstBundle};
|
||||||
use crate::map_block::{MapBlock};
|
use crate::map_block::MapBlock;
|
||||||
use crate::utils::{query_keys, to_bytes, to_slice, fmt_big_num};
|
use crate::utils::{query_keys, to_bytes, to_slice, fmt_big_num};
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,6 +12,8 @@ pub fn is_valid_generated(data: &[u8]) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Allocation limit for everything to prevent crashes with bad data.
|
||||||
|
// TODO: Make sure all data structures are the best choice.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MapBlock {
|
pub struct MapBlock {
|
||||||
pub version: u8,
|
pub version: u8,
|
||||||
|
@ -4,12 +4,10 @@ use super::*;
|
|||||||
|
|
||||||
|
|
||||||
/// Maps 16-bit node IDs to actual node names.
|
/// Maps 16-bit node IDs to actual node names.
|
||||||
|
///
|
||||||
/// Relevant Minetest source file: /src/nameidmapping.cpp
|
/// Relevant Minetest source file: /src/nameidmapping.cpp
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct NameIdMap {
|
pub struct NameIdMap(pub BTreeMap<u16, Vec<u8>>);
|
||||||
// Use a BTreeMap instead of a HashMap to preserve the order of IDs.
|
|
||||||
pub map: BTreeMap<u16, Vec<u8>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NameIdMap {
|
impl NameIdMap {
|
||||||
pub fn deserialize(data: &mut Cursor<&[u8]>)
|
pub fn deserialize(data: &mut Cursor<&[u8]>)
|
||||||
@ -29,14 +27,14 @@ impl NameIdMap {
|
|||||||
map.insert(id, name);
|
map.insert(id, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {map})
|
Ok(Self(map))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serialize(&self, out: &mut Cursor<Vec<u8>>) {
|
pub fn serialize(&self, out: &mut Cursor<Vec<u8>>) {
|
||||||
out.write_u8(0).unwrap();
|
out.write_u8(0).unwrap();
|
||||||
out.write_u16::<BigEndian>(self.map.len() as u16).unwrap();
|
out.write_u16::<BigEndian>(self.0.len() as u16).unwrap();
|
||||||
|
|
||||||
for (id, name) in &self.map {
|
for (id, name) in &self.0 {
|
||||||
out.write_u16::<BigEndian>(*id).unwrap();
|
out.write_u16::<BigEndian>(*id).unwrap();
|
||||||
write_string16(out, name);
|
write_string16(out, name);
|
||||||
}
|
}
|
||||||
@ -44,29 +42,24 @@ impl NameIdMap {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_id(&self, name: &[u8]) -> Option<u16> {
|
pub fn get_id(&self, name: &[u8]) -> Option<u16> {
|
||||||
self.map.iter().find_map(|(&k, v)|
|
self.0.iter().find_map(|(&k, v)|
|
||||||
if v.as_slice() == name { Some(k) } else { None }
|
if v.as_slice() == name { Some(k) } else { None }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_max_id(&self) -> Option<u16> {
|
pub fn get_max_id(&self) -> Option<u16> {
|
||||||
self.map.iter().next_back().map(|k| *(k.0))
|
self.0.iter().next_back().map(|(&k, _)| k)
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn insert(&mut self, id: u16, name: &[u8]) {
|
|
||||||
self.map.insert(id, name.to_owned());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove the name at a given ID and shift down values above it.
|
/// Remove the name at a given ID and shift down values above it.
|
||||||
pub fn remove(&mut self, id: u16) {
|
pub fn remove_shift(&mut self, id: u16) {
|
||||||
self.map.remove(&id);
|
self.0.remove(&id);
|
||||||
let mut next_id = id + 1;
|
let mut next_id = id + 1;
|
||||||
|
|
||||||
while self.map.contains_key(&next_id) {
|
while self.0.contains_key(&next_id) {
|
||||||
let name = self.map.remove(&next_id).unwrap();
|
let name = self.0.remove(&next_id).unwrap();
|
||||||
self.map.insert(next_id - 1, name);
|
self.0.insert(next_id - 1, name);
|
||||||
next_id += 1;
|
next_id += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user