From 489b2a8887c6cec47b498606b9a367bd0794228a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr>
Date: Wed, 10 Jun 2020 09:14:21 +0200
Subject: [PATCH] [dome] optional fallback in settings

---
 ivette/src/dome/src/renderer/data/states.ts | 49 ++++++++++++++++-----
 1 file changed, 38 insertions(+), 11 deletions(-)

diff --git a/ivette/src/dome/src/renderer/data/states.ts b/ivette/src/dome/src/renderer/data/states.ts
index 0fa2e25f110..5fbf00dc837 100644
--- a/ivette/src/dome/src/renderer/data/states.ts
+++ b/ivette/src/dome/src/renderer/data/states.ts
@@ -150,14 +150,25 @@ abstract class Settings<A> {
   protected readonly encoder: JSON.Encoder<A>;
 
   /**
+     Encoders shall be protected against exception.
+     Use [[JSON.jTry]] and [[JSON.jCatch]] in case of uncertainty.
+     Decoders are automatically protected internally to the Settings class.
      @param role - Debugging name of instance roles (each instance has its unique role, though)
      @param decoder - JSON decoder for the setting values
      @param encoder - JSON encoder for the setting values
+     @param fallback -
+     If provided, used to automatically protect your encoders against exceptions.
    */
-  constructor(role: string, decoder: JSON.Safe<A>, encoder: JSON.Encoder<A>) {
+  constructor(
+    role: string,
+    decoder: JSON.Safe<A>,
+    encoder: JSON.Encoder<A>,
+    fallback?: A,
+  ) {
     this.role = Symbol(role);
-    this.decoder = decoder;
     this.encoder = encoder;
+    this.decoder =
+      fallback !== undefined ? JSON.jCatch(decoder, fallback) : decoder;
   }
 
   /**
@@ -201,7 +212,13 @@ abstract class Settings<A> {
       You only use validated keys otherwise further loads
       might fail and fallback to defaults. */
   saveValue(dataKey: string, value: A) {
-    this.saveData(dataKey, this.encoder(value));
+    try { this.saveData(dataKey, this.encoder(value)); }
+    catch (err) {
+      if (DEVEL) console.error(
+        '[Dome.settings] error while encoding value',
+        dataKey, value, err,
+      );
+    }
   }
 
 }
@@ -247,8 +264,13 @@ export function useSettings<A>(
     You can use a [[JSON.Loose]] decoder for optional values. */
 export class WindowSettingsData<A> extends Settings<A> {
 
-  constructor(role: string, decoder: JSON.Safe<A>, encoder: JSON.Encoder<A>) {
-    super(role, decoder, encoder);
+  constructor(
+    role: string,
+    decoder: JSON.Safe<A>,
+    encoder: JSON.Encoder<A>,
+    fallback?: A,
+  ) {
+    super(role, decoder, encoder, fallback);
   }
 
   event = Symbol('dome.settings');
@@ -262,8 +284,13 @@ export class WindowSettingsData<A> extends Settings<A> {
     You can use a [[JSON.Loose]] decoder for optional values. */
 export class GlobalSettingsData<A> extends Settings<A> {
 
-  constructor(role: string, decoder: JSON.Safe<A>, encoder: JSON.Encoder<A>) {
-    super(role, decoder, encoder);
+  constructor(
+    role: string,
+    decoder: JSON.Safe<A>,
+    encoder: JSON.Encoder<A>,
+    fallback?: A,
+  ) {
+    super(role, decoder, encoder, fallback);
   }
 
   event = Symbol('dome.globals');
@@ -277,8 +304,8 @@ export class GlobalSettingsData<A> extends Settings<A> {
     You can use a [[JSON.Loose]] decoder for optional values. */
 export class WindowSettings<A extends JSON.json> extends WindowSettingsData<A> {
 
-  constructor(role: string, decoder: JSON.Safe<A>) {
-    super(role, decoder, JSON.identity);
+  constructor(role: string, decoder: JSON.Safe<A>, fallback?: A) {
+    super(role, decoder, JSON.identity, fallback);
   }
 
 }
@@ -288,8 +315,8 @@ export class WindowSettings<A extends JSON.json> extends WindowSettingsData<A> {
     You can use a [[JSON.Loose]] decoder for optional values. */
 export class GlobalSettings<A extends JSON.json> extends GlobalSettingsData<A> {
 
-  constructor(role: string, decoder: JSON.Safe<A>) {
-    super(role, decoder, JSON.identity);
+  constructor(role: string, decoder: JSON.Safe<A>, fallback?: A) {
+    super(role, decoder, JSON.identity, fallback);
   }
 
 }
-- 
GitLab