chiark / gitweb /
shapelib: Add "extra fields" feature
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Tue, 6 Apr 2021 18:56:26 +0000 (19:56 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Tue, 6 Apr 2021 19:22:04 +0000 (20:22 +0100)
We'll define one of these in a moment.

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
media-scraper
src/shapelib-toml.rs
src/shapelib.rs

index ab6d39d8b41d0312f4eafc5e507035ea12a33b65..b1db5f40b1e6b81a4e3a7c5232679220452fa18e 100755 (executable)
@@ -223,7 +223,7 @@ foreach my $groupname (sort keys %$groups) {
   my $method_impl = $method_fn->($scraper, $method);
   foreach (split(/\n/, $gcfg->('files'))) {
     s/^\s+//;
-    next if m/^\#/ || m/^$/;
+    next if m/^\#/ || m/^$/ || m/^\:/;
     m/^(\S+)\s+(\S+)/ or die "bad line in files: \`$_'";
     my $lministem = $1;
     my $rministem = $2;
index b57362925f34ff8e76dad5292d0f78253b8c119b..99e180b2b85a57e394da79ce904f284ba0dd0c9e 100644 (file)
@@ -54,9 +54,10 @@ pub struct LibraryTomlFile {
 // `GroupDefn` is processed.
 #[derive(Debug,Deserialize)]
 pub struct GroupDefn {
-  /// `files` is a multi-line string, each line of which has three
-  /// fields (the first two terminated by whitespace).  The fields
-  /// are those in [`FileData`].  `#` comments are supported.
+  /// `files` is a multi-line string, each line of which has
+  /// (normally) three fields (the leading ones terminated by
+  /// whitespace).  The fields are those in [`FileData`].  `#`
+  /// comments are supported.
   ///
   /// Each non-empty non-comment line in `files` specifies a single
   /// SVG to be made aavailable as a piece.
@@ -73,6 +74,16 @@ pub struct GroupDefn {
   /// Item names are conventionally structured using a hierarchical
   /// name with `-` between the components.  Do not put `/` or `_` in
   /// item names.
+  ///
+  /// It is also possible to specify additional data for each item by
+  /// adding fields to each line.  This is done by adding a line at
+  /// the start starting with `:` and then additing one additional
+  /// whitespace separated value on each data line.  Unknown
+  /// `fieldname` values are ignored.
+  ///
+  /// The values for these extra fields come just before the
+  /// dwscription, after the other whitespace-delimited fields, in the
+  /// same order as specified in the `:` heading line.
   pub files: FileList,
 
   /// See the discussioin of the item name.
@@ -202,7 +213,7 @@ pub struct FileList(pub Vec<FileData>);
 
 /// Contents of each line in [`files`](GroupDefn::files)
 ///
-/// This is not a key value list.  The first two fields are found by
+/// This is not a key value list.  The leading fields are found by
 /// splitting on whitespace, and the final field is the rest of the
 /// line.
 #[derive(Deserialize,Debug)]
@@ -219,6 +230,9 @@ pub struct FileData {
   #[cfg(doc)] pub r_file_spec: String,
   #[cfg(not(doc))] pub r_file_spec: (),
 
+  /// Extra fields, normally not present.
+  pub extra_fields: HashMap<String, String>,
+
   /// Desscription.  (Shown hn the game log, for example.)
   /// Will be HTML-escaped.
   pub desc: String,
index c07d0f35a25aa8d99704ca3c1d8bf08cc5bdae32..1f0443d1253c9bc7af1e0201ae72f632af313c92 100644 (file)
@@ -105,6 +105,8 @@ pub enum LibraryLoadError {
   #[error("{:?}",&self)]
   FilesListLineMissingWhitespace(usize),
   #[error("{:?}",&self)]
+  FilesListFieldsMustBeAtStart(usize),
+  #[error("{:?}",&self)]
   MissingSubstituionToken(&'static str),
   #[error("{:?}",&self)]
   RepeatedSubstituionToken(&'static str),
@@ -885,9 +887,20 @@ impl TryFrom<String> for FileList {
 //  #[throws(LLE)]
   fn try_from(s: String) -> Result<FileList,LLE> {
     let mut o = Vec::new();
+    let mut xfields = Vec::new();
     for (lno,l) in s.lines().enumerate() {
       let l = l.trim();
       if l=="" || l.starts_with("#") { continue }
+      if let Some(xfields_spec) = l.strip_prefix(':') {
+        if ! (o.is_empty() && xfields.is_empty()) {
+          throw!(LLE::FilesListFieldsMustBeAtStart(lno));
+        }
+        xfields = xfields_spec.split_ascii_whitespace()
+          .filter(|s| !s.is_empty())
+          .map(|s| s.to_owned())
+          .collect::<Vec<_>>();
+        continue;
+      }
       let mut remain = &*l;
       let mut n = ||{
         let ws = remain.find(char::is_whitespace)
@@ -898,8 +911,11 @@ impl TryFrom<String> for FileList {
       };
       let item_spec = n()?;
       let _r_file_spec = n()?;
+      let extra_fields = xfields.iter()
+        .map(|field| Ok::<_,LLE>((field.to_owned(), n()?.to_owned())))
+        .collect::<Result<_,_>>()?;
       let desc = remain.to_owned();
-      o.push(FileData{ item_spec, r_file_spec: (), desc });
+      o.push(FileData{ item_spec, r_file_spec: (), extra_fields, desc });
     }
     Ok(FileList(o))
   }