pub use crate::from_instance_lock_error;
pub use std::os::unix::net::UnixStream;
+type SE = SpecError;
type CSE = anyhow::Error;
use MgmtCommand::*;
let (ig_g, modperm, _) = cs.check_acl_modify_pieces(ag, ig)?;
let ig = &mut **ig_g;
let gs = &mut ig.gs;
- let count = count.unwrap_or(1);
- if count > CREATE_PIECES_MAX { throw!(ME::LimitExceeded) }
+ let implicit : u32 = info.count()
+ .try_into().map_err(
+ |_| SE::InternalError(format!("implicit item count out of range"))
+ )?;
+ let count : Box<dyn ExactSizeIterator<Item=u32>> = match count {
+ Some(explicit) if implicit == 1 => {
+ Box::new((0..explicit).map(|_| 0))
+ },
+ Some(explicit) if implicit != explicit => {
+ throw!(SpecError::InconsistentPieceCount)
+ },
+ None | Some(_) => {
+ Box::new(0..implicit)
+ },
+ };
+
+ let count_len = count.len();
+ if count.len() > CREATE_PIECES_MAX as usize { throw!(ME::LimitExceeded) }
let posd = posd.unwrap_or(DEFAULT_POS_DELTA);
- let mut updates = Vec::with_capacity(count as usize);
+ let mut updates = Vec::with_capacity(count_len);
let mut pos = pos.unwrap_or(DEFAULT_POS_START);
let mut z = gs.max_z.clone_mut();
- for _ in 0..count {
- let p = info.load()?;
+ for piece_i in count {
+ let p = info.load(piece_i as usize)?;
let face = face.unwrap_or_default();
if p.nfaces() <= face.into() {
throw!(SpecError::FaceNotFound);
(U{ pcs: updates,
log: vec![ LogEntry {
- html: Html(format!("{} added {} pieces", &who.0, count)),
+ html: Html(format!("{} added {} pieces", &who.0, count_len)),
}],
raw: None },
Fine, ig_g)
#[typetag::serde(tag="type")]
pub trait PieceSpec : Debug {
- fn load(&self) -> Result<Box<dyn Piece>,SpecError>;
+ fn count(&self) -> usize { 1 }
+ fn load(&self, i: usize) -> Result<Box<dyn Piece>,SpecError>;
}
// ========== implementations ==========
#[typetag::serde]
impl PieceSpec for piece_specs::Disc {
#[throws(SpecError)]
- fn load(&self) -> Box<dyn Piece> {
+ fn load(&self, _: usize) -> Box<dyn Piece> {
let outline = Box::new(shapelib::Circle { diam: self.diam as f64 });
let path = svg_circle_path(self.diam as f64)?;
let itemname = self.itemname.clone()
#[typetag::serde]
impl PieceSpec for piece_specs::Square {
#[throws(SpecError)]
- fn load(&self) -> Box<dyn Piece> {
+ fn load(&self, _: usize) -> Box<dyn Piece> {
let xy = match *self.size.as_slice() {
[s,] => PosC([s,s]),
[x,y] => PosC([x,y]),
pub item: String,
}
+#[derive(Debug,Clone,Serialize,Deserialize)]
+pub struct MultiSpec {
+ pub lib: String,
+ pub items: Vec<String>,
+}
+
define_index_type!{ pub struct DescId = u8; }
define_index_type!{ pub struct SvgId = u8; }
#[typetag::serde(name="Lib")]
impl PieceSpec for ItemSpec {
- fn load(&self) -> Result<Box<dyn Piece>,SpecError> {
+ fn load(&self, _: usize) -> Result<Box<dyn Piece>,SpecError> {
self.load()
}
}
+#[typetag::serde(name="LibList")]
+impl PieceSpec for MultiSpec {
+ fn count(&self) -> usize { self.items.len() }
+ fn load(&self, i: usize) -> Result<Box<dyn Piece>,SpecError> {
+ let item = self.items.get(i).ok_or_else(
+ || SE::InternalError(format!("item {:?} from {:?}", i, &self))
+ )?.clone();
+ let lib = self.lib.clone();
+ ItemSpec { lib, item }.load()
+ }
+}
+
#[throws(LibraryLoadError)]
fn resolve_inherit<'r>(depth: u8, groups: &toml::value::Table,
group_name: &str, group: &'r toml::Value)
LibraryItemNotFound,
AclInvalidAccountGlob,
AclEntryOverlappingAllowDeny,
+ InconsistentPieceCount,
}
display_as_debug!{SpecError}