diff --git a/examples/DemoRunner/Builds/Android/app/CMakeLists.txt b/examples/DemoRunner/Builds/Android/app/CMakeLists.txt
index 8906e61c2a..900c73c5a3 100644
--- a/examples/DemoRunner/Builds/Android/app/CMakeLists.txt
+++ b/examples/DemoRunner/Builds/Android/app/CMakeLists.txt
@@ -1014,6 +1014,8 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_core/javascript/juce_Javascript.h"
"../../../../../modules/juce_core/javascript/juce_JSON.cpp"
"../../../../../modules/juce_core/javascript/juce_JSON.h"
+ "../../../../../modules/juce_core/javascript/juce_JSONSerialisation.h"
+ "../../../../../modules/juce_core/javascript/juce_JSONSerialisation_test.cpp"
"../../../../../modules/juce_core/logging/juce_FileLogger.cpp"
"../../../../../modules/juce_core/logging/juce_FileLogger.h"
"../../../../../modules/juce_core/logging/juce_Logger.cpp"
@@ -1112,6 +1114,7 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_core/network/juce_URL.h"
"../../../../../modules/juce_core/network/juce_WebInputStream.cpp"
"../../../../../modules/juce_core/network/juce_WebInputStream.h"
+ "../../../../../modules/juce_core/serialisation/juce_Serialisation.h"
"../../../../../modules/juce_core/streams/juce_AndroidDocumentInputSource.h"
"../../../../../modules/juce_core/streams/juce_BufferedInputStream.cpp"
"../../../../../modules/juce_core/streams/juce_BufferedInputStream.h"
@@ -3077,6 +3080,8 @@ set_source_files_properties(
"../../../../../modules/juce_core/javascript/juce_Javascript.h"
"../../../../../modules/juce_core/javascript/juce_JSON.cpp"
"../../../../../modules/juce_core/javascript/juce_JSON.h"
+ "../../../../../modules/juce_core/javascript/juce_JSONSerialisation.h"
+ "../../../../../modules/juce_core/javascript/juce_JSONSerialisation_test.cpp"
"../../../../../modules/juce_core/logging/juce_FileLogger.cpp"
"../../../../../modules/juce_core/logging/juce_FileLogger.h"
"../../../../../modules/juce_core/logging/juce_Logger.cpp"
@@ -3175,6 +3180,7 @@ set_source_files_properties(
"../../../../../modules/juce_core/network/juce_URL.h"
"../../../../../modules/juce_core/network/juce_WebInputStream.cpp"
"../../../../../modules/juce_core/network/juce_WebInputStream.h"
+ "../../../../../modules/juce_core/serialisation/juce_Serialisation.h"
"../../../../../modules/juce_core/streams/juce_AndroidDocumentInputSource.h"
"../../../../../modules/juce_core/streams/juce_BufferedInputStream.cpp"
"../../../../../modules/juce_core/streams/juce_BufferedInputStream.h"
diff --git a/examples/DemoRunner/Builds/MacOSX/DemoRunner.xcodeproj/project.pbxproj b/examples/DemoRunner/Builds/MacOSX/DemoRunner.xcodeproj/project.pbxproj
index 453551f226..0eef468167 100644
--- a/examples/DemoRunner/Builds/MacOSX/DemoRunner.xcodeproj/project.pbxproj
+++ b/examples/DemoRunner/Builds/MacOSX/DemoRunner.xcodeproj/project.pbxproj
@@ -567,6 +567,7 @@
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK",
+ "$(HOME)/Developer/VSTSDK",
"$(SRCROOT)/../../JuceLibraryCode",
"$(SRCROOT)/../../../../modules",
"$(inherited)",
@@ -576,7 +577,7 @@
INSTALL_PATH = "$(HOME)/Applications";
LLVM_LTO = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13;
- MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
+ MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(HOME)/Developer/VSTSDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit";
@@ -658,6 +659,7 @@
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK",
+ "$(HOME)/Developer/VSTSDK",
"$(SRCROOT)/../../JuceLibraryCode",
"$(SRCROOT)/../../../../modules",
"$(inherited)",
@@ -666,7 +668,7 @@
INFOPLIST_PREPROCESS = NO;
INSTALL_PATH = "$(HOME)/Applications";
MACOSX_DEPLOYMENT_TARGET = 10.13;
- MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
+ MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(HOME)/Developer/VSTSDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit";
diff --git a/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj
index 3b82207f5f..a56f53e087 100644
--- a/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj
+++ b/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj
@@ -1310,6 +1310,9 @@
true
+
+ true
+
true
@@ -2764,7 +2767,9 @@
-
+
+ /bigobj %(AdditionalOptions)
+
@@ -3326,6 +3331,7 @@
+
@@ -3375,6 +3381,7 @@
+
diff --git a/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj.filters
index 9a2cae232a..c7f46a60be 100644
--- a/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj.filters
+++ b/examples/DemoRunner/Builds/VisualStudio2017/DemoRunner_App.vcxproj.filters
@@ -437,6 +437,9 @@
{0F70B1A9-BB50-23F5-2AE7-F95E51A00389}
+
+ {D4D9BC01-0DED-2577-4B99-2FF7B9C7EF8A}
+
{D4C8DC40-2CD2-04B6-05D0-1E7A88841390}
@@ -1924,6 +1927,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -5187,6 +5193,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -5334,6 +5343,9 @@
JUCE Modules\juce_core\network
+
+ JUCE Modules\juce_core\serialisation
+
JUCE Modules\juce_core\streams
diff --git a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj
index 2b01a6925e..ed44a0263b 100644
--- a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj
+++ b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj
@@ -1310,6 +1310,9 @@
true
+
+ true
+
true
@@ -2764,7 +2767,9 @@
-
+
+ /bigobj %(AdditionalOptions)
+
@@ -3326,6 +3331,7 @@
+
@@ -3375,6 +3381,7 @@
+
diff --git a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters
index 99e39fe0d0..8ea21b802c 100644
--- a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters
+++ b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters
@@ -437,6 +437,9 @@
{0F70B1A9-BB50-23F5-2AE7-F95E51A00389}
+
+ {D4D9BC01-0DED-2577-4B99-2FF7B9C7EF8A}
+
{D4C8DC40-2CD2-04B6-05D0-1E7A88841390}
@@ -1924,6 +1927,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -5187,6 +5193,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -5334,6 +5343,9 @@
JUCE Modules\juce_core\network
+
+ JUCE Modules\juce_core\serialisation
+
JUCE Modules\juce_core\streams
diff --git a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj
index 1069b83eca..bb93ee018a 100644
--- a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj
+++ b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj
@@ -1310,6 +1310,9 @@
true
+
+ true
+
true
@@ -2764,7 +2767,9 @@
-
+
+ /bigobj %(AdditionalOptions)
+
@@ -3326,6 +3331,7 @@
+
@@ -3375,6 +3381,7 @@
+
diff --git a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters
index b9b7836ad2..922f3319b5 100644
--- a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters
+++ b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters
@@ -437,6 +437,9 @@
{0F70B1A9-BB50-23F5-2AE7-F95E51A00389}
+
+ {D4D9BC01-0DED-2577-4B99-2FF7B9C7EF8A}
+
{D4C8DC40-2CD2-04B6-05D0-1E7A88841390}
@@ -1924,6 +1927,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -5187,6 +5193,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -5334,6 +5343,9 @@
JUCE Modules\juce_core\network
+
+ JUCE Modules\juce_core\serialisation
+
JUCE Modules\juce_core\streams
diff --git a/examples/DemoRunner/Builds/iOS/DemoRunner.xcodeproj/project.pbxproj b/examples/DemoRunner/Builds/iOS/DemoRunner.xcodeproj/project.pbxproj
index 08087f38d8..a7bcba72d1 100644
--- a/examples/DemoRunner/Builds/iOS/DemoRunner.xcodeproj/project.pbxproj
+++ b/examples/DemoRunner/Builds/iOS/DemoRunner.xcodeproj/project.pbxproj
@@ -571,6 +571,7 @@
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK",
+ "$(HOME)/Developer/VSTSDK",
"$(SRCROOT)/../../JuceLibraryCode",
"$(SRCROOT)/../../../../modules",
"$(inherited)",
@@ -579,7 +580,7 @@
INFOPLIST_PREPROCESS = NO;
INSTALL_PATH = "$(HOME)/Applications";
LLVM_LTO = YES;
- MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
+ MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(HOME)/Developer/VSTSDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit -weak_framework UserNotifications";
@@ -662,6 +663,7 @@
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK",
+ "$(HOME)/Developer/VSTSDK",
"$(SRCROOT)/../../JuceLibraryCode",
"$(SRCROOT)/../../../../modules",
"$(inherited)",
@@ -669,7 +671,7 @@
INFOPLIST_FILE = Info-App.plist;
INFOPLIST_PREPROCESS = NO;
INSTALL_PATH = "$(HOME)/Applications";
- MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
+ MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(HOME)/Developer/VSTSDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit -weak_framework UserNotifications";
diff --git a/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt b/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt
index ba48b78203..fd039e8652 100644
--- a/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt
+++ b/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt
@@ -890,6 +890,8 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_core/javascript/juce_Javascript.h"
"../../../../../modules/juce_core/javascript/juce_JSON.cpp"
"../../../../../modules/juce_core/javascript/juce_JSON.h"
+ "../../../../../modules/juce_core/javascript/juce_JSONSerialisation.h"
+ "../../../../../modules/juce_core/javascript/juce_JSONSerialisation_test.cpp"
"../../../../../modules/juce_core/logging/juce_FileLogger.cpp"
"../../../../../modules/juce_core/logging/juce_FileLogger.h"
"../../../../../modules/juce_core/logging/juce_Logger.cpp"
@@ -988,6 +990,7 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_core/network/juce_URL.h"
"../../../../../modules/juce_core/network/juce_WebInputStream.cpp"
"../../../../../modules/juce_core/network/juce_WebInputStream.h"
+ "../../../../../modules/juce_core/serialisation/juce_Serialisation.h"
"../../../../../modules/juce_core/streams/juce_AndroidDocumentInputSource.h"
"../../../../../modules/juce_core/streams/juce_BufferedInputStream.cpp"
"../../../../../modules/juce_core/streams/juce_BufferedInputStream.h"
@@ -2653,6 +2656,8 @@ set_source_files_properties(
"../../../../../modules/juce_core/javascript/juce_Javascript.h"
"../../../../../modules/juce_core/javascript/juce_JSON.cpp"
"../../../../../modules/juce_core/javascript/juce_JSON.h"
+ "../../../../../modules/juce_core/javascript/juce_JSONSerialisation.h"
+ "../../../../../modules/juce_core/javascript/juce_JSONSerialisation_test.cpp"
"../../../../../modules/juce_core/logging/juce_FileLogger.cpp"
"../../../../../modules/juce_core/logging/juce_FileLogger.h"
"../../../../../modules/juce_core/logging/juce_Logger.cpp"
@@ -2751,6 +2756,7 @@ set_source_files_properties(
"../../../../../modules/juce_core/network/juce_URL.h"
"../../../../../modules/juce_core/network/juce_WebInputStream.cpp"
"../../../../../modules/juce_core/network/juce_WebInputStream.h"
+ "../../../../../modules/juce_core/serialisation/juce_Serialisation.h"
"../../../../../modules/juce_core/streams/juce_AndroidDocumentInputSource.h"
"../../../../../modules/juce_core/streams/juce_BufferedInputStream.cpp"
"../../../../../modules/juce_core/streams/juce_BufferedInputStream.h"
diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj
index e3f292c89a..b30591fbc8 100644
--- a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj
+++ b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj
@@ -1150,6 +1150,9 @@
true
+
+ true
+
true
@@ -2383,7 +2386,9 @@
-
+
+ /bigobj %(AdditionalOptions)
+
@@ -2882,6 +2887,7 @@
+
@@ -2931,6 +2937,7 @@
+
diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters
index 6efb730b3a..2e0c11fcd1 100644
--- a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters
+++ b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters
@@ -392,6 +392,9 @@
{0F70B1A9-BB50-23F5-2AE7-F95E51A00389}
+
+ {D4D9BC01-0DED-2577-4B99-2FF7B9C7EF8A}
+
{D4C8DC40-2CD2-04B6-05D0-1E7A88841390}
@@ -1633,6 +1636,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -4467,6 +4473,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -4614,6 +4623,9 @@
JUCE Modules\juce_core\network
+
+ JUCE Modules\juce_core\serialisation
+
JUCE Modules\juce_core\streams
diff --git a/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt b/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt
index 31a752e6d3..3d86aba9be 100644
--- a/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt
+++ b/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt
@@ -923,6 +923,8 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_core/javascript/juce_Javascript.h"
"../../../../../modules/juce_core/javascript/juce_JSON.cpp"
"../../../../../modules/juce_core/javascript/juce_JSON.h"
+ "../../../../../modules/juce_core/javascript/juce_JSONSerialisation.h"
+ "../../../../../modules/juce_core/javascript/juce_JSONSerialisation_test.cpp"
"../../../../../modules/juce_core/logging/juce_FileLogger.cpp"
"../../../../../modules/juce_core/logging/juce_FileLogger.h"
"../../../../../modules/juce_core/logging/juce_Logger.cpp"
@@ -1021,6 +1023,7 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_core/network/juce_URL.h"
"../../../../../modules/juce_core/network/juce_WebInputStream.cpp"
"../../../../../modules/juce_core/network/juce_WebInputStream.h"
+ "../../../../../modules/juce_core/serialisation/juce_Serialisation.h"
"../../../../../modules/juce_core/streams/juce_AndroidDocumentInputSource.h"
"../../../../../modules/juce_core/streams/juce_BufferedInputStream.cpp"
"../../../../../modules/juce_core/streams/juce_BufferedInputStream.h"
@@ -2839,6 +2842,8 @@ set_source_files_properties(
"../../../../../modules/juce_core/javascript/juce_Javascript.h"
"../../../../../modules/juce_core/javascript/juce_JSON.cpp"
"../../../../../modules/juce_core/javascript/juce_JSON.h"
+ "../../../../../modules/juce_core/javascript/juce_JSONSerialisation.h"
+ "../../../../../modules/juce_core/javascript/juce_JSONSerialisation_test.cpp"
"../../../../../modules/juce_core/logging/juce_FileLogger.cpp"
"../../../../../modules/juce_core/logging/juce_FileLogger.h"
"../../../../../modules/juce_core/logging/juce_Logger.cpp"
@@ -2937,6 +2942,7 @@ set_source_files_properties(
"../../../../../modules/juce_core/network/juce_URL.h"
"../../../../../modules/juce_core/network/juce_WebInputStream.cpp"
"../../../../../modules/juce_core/network/juce_WebInputStream.h"
+ "../../../../../modules/juce_core/serialisation/juce_Serialisation.h"
"../../../../../modules/juce_core/streams/juce_AndroidDocumentInputSource.h"
"../../../../../modules/juce_core/streams/juce_BufferedInputStream.cpp"
"../../../../../modules/juce_core/streams/juce_BufferedInputStream.h"
diff --git a/extras/AudioPluginHost/Builds/MacOSX/AudioPluginHost.xcodeproj/project.pbxproj b/extras/AudioPluginHost/Builds/MacOSX/AudioPluginHost.xcodeproj/project.pbxproj
index 64841881c2..6256cbb5b2 100644
--- a/extras/AudioPluginHost/Builds/MacOSX/AudioPluginHost.xcodeproj/project.pbxproj
+++ b/extras/AudioPluginHost/Builds/MacOSX/AudioPluginHost.xcodeproj/project.pbxproj
@@ -499,6 +499,7 @@
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK",
+ "$(HOME)/Developer/VSTSDK",
"$(SRCROOT)/../../JuceLibraryCode",
"$(SRCROOT)/../../../../modules",
"$(inherited)",
@@ -508,7 +509,7 @@
INSTALL_PATH = "$(HOME)/Applications";
LLVM_LTO = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13;
- MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
+ MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(HOME)/Developer/VSTSDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit";
@@ -637,6 +638,7 @@
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK",
+ "$(HOME)/Developer/VSTSDK",
"$(SRCROOT)/../../JuceLibraryCode",
"$(SRCROOT)/../../../../modules",
"$(inherited)",
@@ -645,7 +647,7 @@
INFOPLIST_PREPROCESS = NO;
INSTALL_PATH = "$(HOME)/Applications";
MACOSX_DEPLOYMENT_TARGET = 10.13;
- MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
+ MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(HOME)/Developer/VSTSDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit";
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj
index e564f441dc..7f7009fed5 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj
+++ b/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj
@@ -1158,6 +1158,9 @@
true
+
+ true
+
true
@@ -2554,7 +2557,9 @@
-
+
+ /bigobj %(AdditionalOptions)
+
@@ -3062,6 +3067,7 @@
+
@@ -3111,6 +3117,7 @@
+
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj.filters
index b95133a94c..6412eaaf0e 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj.filters
+++ b/extras/AudioPluginHost/Builds/VisualStudio2017/AudioPluginHost_App.vcxproj.filters
@@ -401,6 +401,9 @@
{0F70B1A9-BB50-23F5-2AE7-F95E51A00389}
+
+ {D4D9BC01-0DED-2577-4B99-2FF7B9C7EF8A}
+
{D4C8DC40-2CD2-04B6-05D0-1E7A88841390}
@@ -1708,6 +1711,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -4743,6 +4749,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -4890,6 +4899,9 @@
JUCE Modules\juce_core\network
+
+ JUCE Modules\juce_core\serialisation
+
JUCE Modules\juce_core\streams
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj
index 80adb304ae..8e4d3b2c39 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj
+++ b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj
@@ -1158,6 +1158,9 @@
true
+
+ true
+
true
@@ -2554,7 +2557,9 @@
-
+
+ /bigobj %(AdditionalOptions)
+
@@ -3062,6 +3067,7 @@
+
@@ -3111,6 +3117,7 @@
+
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters
index 8030e0558c..fab70583a2 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters
+++ b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters
@@ -401,6 +401,9 @@
{0F70B1A9-BB50-23F5-2AE7-F95E51A00389}
+
+ {D4D9BC01-0DED-2577-4B99-2FF7B9C7EF8A}
+
{D4C8DC40-2CD2-04B6-05D0-1E7A88841390}
@@ -1708,6 +1711,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -4743,6 +4749,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -4890,6 +4899,9 @@
JUCE Modules\juce_core\network
+
+ JUCE Modules\juce_core\serialisation
+
JUCE Modules\juce_core\streams
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj
index 365f14ec0b..a60475887e 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj
+++ b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj
@@ -1158,6 +1158,9 @@
true
+
+ true
+
true
@@ -2554,7 +2557,9 @@
-
+
+ /bigobj %(AdditionalOptions)
+
@@ -3062,6 +3067,7 @@
+
@@ -3111,6 +3117,7 @@
+
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters
index d44e3c1d0e..a1354ba663 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters
+++ b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters
@@ -401,6 +401,9 @@
{0F70B1A9-BB50-23F5-2AE7-F95E51A00389}
+
+ {D4D9BC01-0DED-2577-4B99-2FF7B9C7EF8A}
+
{D4C8DC40-2CD2-04B6-05D0-1E7A88841390}
@@ -1708,6 +1711,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -4743,6 +4749,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -4890,6 +4899,9 @@
JUCE Modules\juce_core\network
+
+ JUCE Modules\juce_core\serialisation
+
JUCE Modules\juce_core\streams
diff --git a/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.xcodeproj/project.pbxproj b/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.xcodeproj/project.pbxproj
index f0cf314521..d68cccdc72 100644
--- a/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.xcodeproj/project.pbxproj
+++ b/extras/AudioPluginHost/Builds/iOS/AudioPluginHost.xcodeproj/project.pbxproj
@@ -510,6 +510,7 @@
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK",
+ "$(HOME)/Developer/VSTSDK",
"$(SRCROOT)/../../JuceLibraryCode",
"$(SRCROOT)/../../../../modules",
"$(inherited)",
@@ -518,7 +519,7 @@
INFOPLIST_PREPROCESS = NO;
INSTALL_PATH = "$(HOME)/Applications";
LLVM_LTO = YES;
- MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
+ MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(HOME)/Developer/VSTSDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit -weak_framework UserNotifications";
@@ -650,6 +651,7 @@
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK",
+ "$(HOME)/Developer/VSTSDK",
"$(SRCROOT)/../../JuceLibraryCode",
"$(SRCROOT)/../../../../modules",
"$(inherited)",
@@ -657,7 +659,7 @@
INFOPLIST_FILE = Info-App.plist;
INFOPLIST_PREPROCESS = NO;
INSTALL_PATH = "$(HOME)/Applications";
- MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
+ MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(HOME)/Developer/VSTSDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit -weak_framework UserNotifications";
diff --git a/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj b/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj
index 02dc30ec5d..111da4d5a0 100644
--- a/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj
+++ b/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj
@@ -217,6 +217,9 @@
true
+
+ true
+
true
@@ -484,7 +487,9 @@
true
-
+
+ /bigobj %(AdditionalOptions)
+
@@ -522,6 +527,7 @@
+
@@ -571,6 +577,7 @@
+
diff --git a/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj.filters b/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj.filters
index b57c4ea2c8..89603e456a 100644
--- a/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj.filters
+++ b/extras/BinaryBuilder/Builds/VisualStudio2022/BinaryBuilder_ConsoleApp.vcxproj.filters
@@ -38,6 +38,9 @@
{0F70B1A9-BB50-23F5-2AE7-F95E51A00389}
+
+ {D4D9BC01-0DED-2577-4B99-2FF7B9C7EF8A}
+
{D4C8DC40-2CD2-04B6-05D0-1E7A88841390}
@@ -154,6 +157,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -549,6 +555,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -696,6 +705,9 @@
JUCE Modules\juce_core\network
+
+ JUCE Modules\juce_core\serialisation
+
JUCE Modules\juce_core\streams
diff --git a/extras/Build/CMake/JUCEModuleSupport.cmake b/extras/Build/CMake/JUCEModuleSupport.cmake
index f353be4e32..e18dd5e087 100644
--- a/extras/Build/CMake/JUCEModuleSupport.cmake
+++ b/extras/Build/CMake/JUCEModuleSupport.cmake
@@ -609,7 +609,7 @@ function(juce_add_module module_path)
_juce_link_libs_from_metadata("${module_name}" "${metadata_dict}" linuxLibs)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
if((CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") OR (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC"))
- if(module_name STREQUAL "juce_gui_basics")
+ if(module_name MATCHES "juce_gui_basics|juce_audio_processors|juce_core")
target_compile_options(${module_name} INTERFACE /bigobj)
endif()
diff --git a/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt b/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt
index 82b4f53ba4..41381d1f81 100644
--- a/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt
+++ b/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt
@@ -894,6 +894,8 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_core/javascript/juce_Javascript.h"
"../../../../../modules/juce_core/javascript/juce_JSON.cpp"
"../../../../../modules/juce_core/javascript/juce_JSON.h"
+ "../../../../../modules/juce_core/javascript/juce_JSONSerialisation.h"
+ "../../../../../modules/juce_core/javascript/juce_JSONSerialisation_test.cpp"
"../../../../../modules/juce_core/logging/juce_FileLogger.cpp"
"../../../../../modules/juce_core/logging/juce_FileLogger.h"
"../../../../../modules/juce_core/logging/juce_Logger.cpp"
@@ -992,6 +994,7 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_core/network/juce_URL.h"
"../../../../../modules/juce_core/network/juce_WebInputStream.cpp"
"../../../../../modules/juce_core/network/juce_WebInputStream.h"
+ "../../../../../modules/juce_core/serialisation/juce_Serialisation.h"
"../../../../../modules/juce_core/streams/juce_AndroidDocumentInputSource.h"
"../../../../../modules/juce_core/streams/juce_BufferedInputStream.cpp"
"../../../../../modules/juce_core/streams/juce_BufferedInputStream.h"
@@ -2737,6 +2740,8 @@ set_source_files_properties(
"../../../../../modules/juce_core/javascript/juce_Javascript.h"
"../../../../../modules/juce_core/javascript/juce_JSON.cpp"
"../../../../../modules/juce_core/javascript/juce_JSON.h"
+ "../../../../../modules/juce_core/javascript/juce_JSONSerialisation.h"
+ "../../../../../modules/juce_core/javascript/juce_JSONSerialisation_test.cpp"
"../../../../../modules/juce_core/logging/juce_FileLogger.cpp"
"../../../../../modules/juce_core/logging/juce_FileLogger.h"
"../../../../../modules/juce_core/logging/juce_Logger.cpp"
@@ -2835,6 +2840,7 @@ set_source_files_properties(
"../../../../../modules/juce_core/network/juce_URL.h"
"../../../../../modules/juce_core/network/juce_WebInputStream.cpp"
"../../../../../modules/juce_core/network/juce_WebInputStream.h"
+ "../../../../../modules/juce_core/serialisation/juce_Serialisation.h"
"../../../../../modules/juce_core/streams/juce_AndroidDocumentInputSource.h"
"../../../../../modules/juce_core/streams/juce_BufferedInputStream.cpp"
"../../../../../modules/juce_core/streams/juce_BufferedInputStream.h"
diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj
index 1371987f31..38228cb131 100644
--- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj
+++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj
@@ -1150,6 +1150,9 @@
true
+
+ true
+
true
@@ -2468,7 +2471,9 @@
-
+
+ /bigobj %(AdditionalOptions)
+
@@ -2973,6 +2978,7 @@
+
@@ -3022,6 +3028,7 @@
+
diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters
index 31cd82ac04..8b36f6bdf8 100644
--- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters
+++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters
@@ -392,6 +392,9 @@
{0F70B1A9-BB50-23F5-2AE7-F95E51A00389}
+
+ {D4D9BC01-0DED-2577-4B99-2FF7B9C7EF8A}
+
{D4C8DC40-2CD2-04B6-05D0-1E7A88841390}
@@ -1663,6 +1666,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -4608,6 +4614,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -4755,6 +4764,9 @@
JUCE Modules\juce_core\network
+
+ JUCE Modules\juce_core\serialisation
+
JUCE Modules\juce_core\streams
diff --git a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj
index 5cd6d923af..e5b0dc5d3f 100644
--- a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj
+++ b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj
@@ -353,6 +353,9 @@
true
+
+ true
+
true
@@ -1600,7 +1603,9 @@
-
+
+ /bigobj %(AdditionalOptions)
+
@@ -1815,6 +1820,7 @@
+
@@ -1864,6 +1870,7 @@
+
diff --git a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters
index 3a6e321cd4..2c6d9092d7 100644
--- a/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters
+++ b/extras/Projucer/Builds/VisualStudio2017/Projucer_App.vcxproj.filters
@@ -119,6 +119,9 @@
{0F70B1A9-BB50-23F5-2AE7-F95E51A00389}
+
+ {D4D9BC01-0DED-2577-4B99-2FF7B9C7EF8A}
+
{D4C8DC40-2CD2-04B6-05D0-1E7A88841390}
@@ -631,6 +634,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -2622,6 +2628,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -2769,6 +2778,9 @@
JUCE Modules\juce_core\network
+
+ JUCE Modules\juce_core\serialisation
+
JUCE Modules\juce_core\streams
diff --git a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj
index ecfaba5e15..3aa9a26508 100644
--- a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj
+++ b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj
@@ -353,6 +353,9 @@
true
+
+ true
+
true
@@ -1600,7 +1603,9 @@
-
+
+ /bigobj %(AdditionalOptions)
+
@@ -1815,6 +1820,7 @@
+
@@ -1864,6 +1870,7 @@
+
diff --git a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters
index 2c138c57f9..62bf8c6eb6 100644
--- a/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters
+++ b/extras/Projucer/Builds/VisualStudio2019/Projucer_App.vcxproj.filters
@@ -119,6 +119,9 @@
{0F70B1A9-BB50-23F5-2AE7-F95E51A00389}
+
+ {D4D9BC01-0DED-2577-4B99-2FF7B9C7EF8A}
+
{D4C8DC40-2CD2-04B6-05D0-1E7A88841390}
@@ -631,6 +634,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -2622,6 +2628,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -2769,6 +2778,9 @@
JUCE Modules\juce_core\network
+
+ JUCE Modules\juce_core\serialisation
+
JUCE Modules\juce_core\streams
diff --git a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj
index da7eb6a76b..f4bd7575a3 100644
--- a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj
+++ b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj
@@ -353,6 +353,9 @@
true
+
+ true
+
true
@@ -1600,7 +1603,9 @@
-
+
+ /bigobj %(AdditionalOptions)
+
@@ -1815,6 +1820,7 @@
+
@@ -1864,6 +1870,7 @@
+
diff --git a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters
index f3ebace5a6..649e69130c 100644
--- a/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters
+++ b/extras/Projucer/Builds/VisualStudio2022/Projucer_App.vcxproj.filters
@@ -119,6 +119,9 @@
{0F70B1A9-BB50-23F5-2AE7-F95E51A00389}
+
+ {D4D9BC01-0DED-2577-4B99-2FF7B9C7EF8A}
+
{D4C8DC40-2CD2-04B6-05D0-1E7A88841390}
@@ -631,6 +634,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -2622,6 +2628,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -2769,6 +2778,9 @@
JUCE Modules\juce_core\network
+
+ JUCE Modules\juce_core\serialisation
+
JUCE Modules\juce_core\streams
diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h
index 54f91e3410..e5c9d69ca8 100644
--- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h
+++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h
@@ -1908,7 +1908,8 @@ protected:
const auto name = path.getFileNameWithoutExtension();
return name.equalsIgnoreCase ("include_juce_gui_basics")
- || name.equalsIgnoreCase ("include_juce_audio_processors");
+ || name.equalsIgnoreCase ("include_juce_audio_processors")
+ || name.equalsIgnoreCase ("include_juce_core");
}
StringArray getModuleLibs() const
diff --git a/extras/UnitTestRunner/Builds/MacOSX/UnitTestRunner.xcodeproj/project.pbxproj b/extras/UnitTestRunner/Builds/MacOSX/UnitTestRunner.xcodeproj/project.pbxproj
index 12fdc68f3c..2207f3ebdb 100644
--- a/extras/UnitTestRunner/Builds/MacOSX/UnitTestRunner.xcodeproj/project.pbxproj
+++ b/extras/UnitTestRunner/Builds/MacOSX/UnitTestRunner.xcodeproj/project.pbxproj
@@ -459,6 +459,7 @@
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK",
+ "$(HOME)/Developer/VSTSDK",
"$(SRCROOT)/../../JuceLibraryCode",
"$(SRCROOT)/../../../../modules",
"$(inherited)",
@@ -466,7 +467,7 @@
INSTALL_PATH = "/usr/bin";
LLVM_LTO = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13;
- MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
+ MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(HOME)/Developer/VSTSDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit";
@@ -590,13 +591,14 @@
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK",
"$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK",
+ "$(HOME)/Developer/VSTSDK",
"$(SRCROOT)/../../JuceLibraryCode",
"$(SRCROOT)/../../../../modules",
"$(inherited)",
);
INSTALL_PATH = "/usr/bin";
MACOSX_DEPLOYMENT_TARGET = 10.13;
- MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
+ MTL_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lilv $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sratom $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord/src $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/sord $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/serd $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK/lv2 $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/LV2_SDK $(SRCROOT)/../../../../modules/juce_audio_processors/format_types/VST3_SDK $(HOME)/Developer/VSTSDK $(SRCROOT)/../../JuceLibraryCode $(SRCROOT)/../../../../modules";
OTHER_CFLAGS = "-Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_CPLUSPLUSFLAGS = "-Woverloaded-virtual -Wreorder -Wzero-as-null-pointer-constant -Wunused-private-field -Winconsistent-missing-destructor-override -Wall -Wcast-align -Wfloat-equal -Wno-ignored-qualifiers -Wsign-compare -Wsign-conversion -Wstrict-aliasing -Wswitch-enum -Wuninitialized -Wunreachable-code -Wunused-parameter -Wmissing-field-initializers -Wshadow-all -Wshorten-64-to-32 -Wconversion -Wint-conversion -Wconditional-uninitialized -Wconstant-conversion -Wbool-conversion -Wextra-semi -Wshift-sign-overflow -Wmissing-prototypes -Wnullable-to-nonnull-conversion -Wpedantic -Wdeprecated -Wunguarded-availability -Wunguarded-availability-new";
OTHER_LDFLAGS = "-weak_framework Metal -weak_framework MetalKit";
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj
index 6a814939f1..4b1fee2c6c 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj
+++ b/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj
@@ -1166,6 +1166,9 @@
true
+
+ true
+
true
@@ -2619,7 +2622,9 @@
-
+
+ /bigobj %(AdditionalOptions)
+
@@ -3128,6 +3133,7 @@
+
@@ -3177,6 +3183,7 @@
+
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj.filters
index e958b4b227..4dfd10ecb3 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj.filters
+++ b/extras/UnitTestRunner/Builds/VisualStudio2017/UnitTestRunner_ConsoleApp.vcxproj.filters
@@ -401,6 +401,9 @@
{0F70B1A9-BB50-23F5-2AE7-F95E51A00389}
+
+ {D4D9BC01-0DED-2577-4B99-2FF7B9C7EF8A}
+
{D4C8DC40-2CD2-04B6-05D0-1E7A88841390}
@@ -1732,6 +1735,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -4833,6 +4839,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -4980,6 +4989,9 @@
JUCE Modules\juce_core\network
+
+ JUCE Modules\juce_core\serialisation
+
JUCE Modules\juce_core\streams
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj
index e611bd6ccb..e6cacf8e8b 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj
+++ b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj
@@ -1166,6 +1166,9 @@
true
+
+ true
+
true
@@ -2619,7 +2622,9 @@
-
+
+ /bigobj %(AdditionalOptions)
+
@@ -3128,6 +3133,7 @@
+
@@ -3177,6 +3183,7 @@
+
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters
index 93cd36c710..1cee45cd03 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters
+++ b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters
@@ -401,6 +401,9 @@
{0F70B1A9-BB50-23F5-2AE7-F95E51A00389}
+
+ {D4D9BC01-0DED-2577-4B99-2FF7B9C7EF8A}
+
{D4C8DC40-2CD2-04B6-05D0-1E7A88841390}
@@ -1732,6 +1735,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -4833,6 +4839,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -4980,6 +4989,9 @@
JUCE Modules\juce_core\network
+
+ JUCE Modules\juce_core\serialisation
+
JUCE Modules\juce_core\streams
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj
index 44d40abc25..d98f2d81f3 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj
+++ b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj
@@ -1166,6 +1166,9 @@
true
+
+ true
+
true
@@ -2619,7 +2622,9 @@
-
+
+ /bigobj %(AdditionalOptions)
+
@@ -3128,6 +3133,7 @@
+
@@ -3177,6 +3183,7 @@
+
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters
index e608da5300..513b91f96f 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters
+++ b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters
@@ -401,6 +401,9 @@
{0F70B1A9-BB50-23F5-2AE7-F95E51A00389}
+
+ {D4D9BC01-0DED-2577-4B99-2FF7B9C7EF8A}
+
{D4C8DC40-2CD2-04B6-05D0-1E7A88841390}
@@ -1732,6 +1735,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -4833,6 +4839,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -4980,6 +4989,9 @@
JUCE Modules\juce_core\network
+
+ JUCE Modules\juce_core\serialisation
+
JUCE Modules\juce_core\streams
diff --git a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj
index 5219f5c8a1..e0876552a7 100644
--- a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj
+++ b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj
@@ -1149,6 +1149,9 @@
true
+
+ true
+
true
@@ -2448,7 +2451,9 @@
-
+
+ /bigobj %(AdditionalOptions)
+
@@ -2949,6 +2954,7 @@
+
@@ -2998,6 +3004,7 @@
+
diff --git a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters
index 78edeef02a..619101a3b3 100644
--- a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters
+++ b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters
@@ -386,6 +386,9 @@
{0F70B1A9-BB50-23F5-2AE7-F95E51A00389}
+
+ {D4D9BC01-0DED-2577-4B99-2FF7B9C7EF8A}
+
{D4C8DC40-2CD2-04B6-05D0-1E7A88841390}
@@ -1660,6 +1663,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -4575,6 +4581,9 @@
JUCE Modules\juce_core\javascript
+
+ JUCE Modules\juce_core\javascript
+
JUCE Modules\juce_core\logging
@@ -4722,6 +4731,9 @@
JUCE Modules\juce_core\network
+
+ JUCE Modules\juce_core\serialisation
+
JUCE Modules\juce_core\streams
diff --git a/modules/juce_core/javascript/juce_JSONSerialisation.h b/modules/juce_core/javascript/juce_JSONSerialisation.h
new file mode 100644
index 0000000000..8726834c34
--- /dev/null
+++ b/modules/juce_core/javascript/juce_JSONSerialisation.h
@@ -0,0 +1,459 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE library.
+ Copyright (c) 2022 - Raw Material Software Limited
+
+ JUCE is an open source library subject to commercial or open-source
+ licensing.
+
+ The code included in this file is provided under the terms of the ISC license
+ http://www.isc.org/downloads/software-support-policy/isc-license. Permission
+ To use, copy, modify, and/or distribute this software for any purpose with or
+ without fee is hereby granted provided that the above copyright notice and
+ this permission notice appear in all copies.
+
+ JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
+ EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
+ DISCLAIMED.
+
+ ==============================================================================
+*/
+
+namespace juce
+{
+
+/**
+ Options that control conversion from arbitrary types to juce::var.
+
+ @see ToVar
+
+ @tags{Core}
+*/
+class ToVarOptions
+{
+public:
+ /** By default, conversion will serialise the type using the marshallingVersion defined for
+ that type. Setting an explicit version allows the type to be serialised as an earlier
+ version.
+ */
+ [[nodiscard]] ToVarOptions withExplicitVersion (std::optional x) const { return withMember (*this, &ToVarOptions::explicitVersion, x); }
+
+ /** By default, conversion will include version information for any type with a non-null
+ marshallingVersion. Setting versionIncluded to false will cause the version info to be
+ omitted, which is useful in situations where the version information is not needed
+ (e.g. when presenting transient information to the user, rather than writing data to
+ disk that must be deserialised in the future).
+ */
+ [[nodiscard]] ToVarOptions withVersionIncluded (bool x) const { return withMember (*this, &ToVarOptions::versionIncluded, x); }
+
+ /** @see withExplicitVersion() */
+ [[nodiscard]] auto getExplicitVersion() const { return explicitVersion; }
+
+ /** @see withVersionIncluded(). */
+ [[nodiscard]] auto getVersionIncluded() const { return versionIncluded; }
+
+private:
+ std::optional> explicitVersion;
+ bool versionIncluded = true;
+};
+
+/**
+ Allows converting an object of arbitrary type to var.
+
+ To use this, you must first ensure that the type passed to convert is set up for serialisation.
+ For details of what this entails, see the docs for SerialisationTraits.
+
+ In short, the constant 'marshallingVersion', and either the single function 'serialise()', or
+ the function pair 'load()' and 'save()' must be defined for the type. These may be defined
+ as public members of the type T itself, or as public members of juce::SerialisationTraits,
+ which is a specialisation of the SerialisationTraits template struct for the type T.
+
+ @see FromVar
+
+ @tags{Core}
+*/
+class ToVar
+{
+public:
+ using Options = ToVarOptions;
+
+ /** Attempts to convert the argument to a var using the serialisation utilities specified for
+ that type.
+
+ This will return a non-null optional if conversion succeeds, or nullopt if conversion fails.
+ */
+ template
+ static std::optional convert (const T& t, const Options& options = {})
+ {
+ return Visitor::convert (t, options);
+ }
+
+private:
+ class Visitor
+ {
+ public:
+ template
+ static std::optional convert (const T& t, const Options& options)
+ {
+ constexpr auto fallbackVersion = detail::ForwardingSerialisationTraits::marshallingVersion;
+ const auto versionToUse = options.getExplicitVersion()
+ .value_or (fallbackVersion);
+
+ if (versionToUse > fallbackVersion)
+ {
+ // The requested explicit version is higher than the declared version of the type.
+ return std::nullopt;
+ }
+
+ Visitor visitor { versionToUse, options.getVersionIncluded() };
+ detail::doSave (visitor, t);
+ return visitor.value;
+ }
+
+ std::optional getVersion() const { return version; }
+
+ template
+ void operator() (Ts&&... ts)
+ {
+ (visit (std::forward (ts)), ...);
+ }
+
+ private:
+ Visitor (const std::optional& explicitVersion, bool includeVersion)
+ : version (explicitVersion),
+ value ([&]() -> var
+ {
+ if (! (version.has_value() && includeVersion))
+ return var();
+
+ auto obj = std::make_unique();
+ obj->setProperty ("__version__", *version);
+ return obj.release();
+ }()),
+ versionIncluded (includeVersion) {}
+
+ template
+ void visit (const T& t)
+ {
+ if constexpr (std::is_integral_v)
+ {
+ push ((int64) t);
+ }
+ else if constexpr (std::is_floating_point_v)
+ {
+ push ((double) t);
+ }
+ else if (auto converted = convert(t))
+ {
+ push (*converted);
+ }
+ else
+ {
+ value.reset();
+ }
+ }
+
+ template
+ void visit (const Named& named)
+ {
+ if (! value.has_value())
+ return;
+
+ if (value == var())
+ value = new DynamicObject;
+
+ auto* obj = value->getDynamicObject();
+
+ if (obj == nullptr)
+ {
+ // Serialisation failure! This may be caused by archiving a primitive or
+ // SerialisationSize, and then attempting to archive a named pair to the same
+ // archive instance.
+ // When using named pairs, *all* items serialised with a particular archiver must be
+ // named pairs.
+ jassertfalse;
+
+ value.reset();
+ return;
+ }
+
+ if (! trySetProperty (*obj, named))
+ value.reset();
+ }
+
+ template
+ void visit (const SerialisationSize&)
+ {
+ push (Array{});
+ }
+
+ void visit (const bool& t)
+ {
+ push (t);
+ }
+
+ void visit (const String& t)
+ {
+ push (t);
+ }
+
+ void visit (const var& t)
+ {
+ push (t);
+ }
+
+ template
+ std::optional convert (const T& t)
+ {
+ return convert (t, Options{}.withVersionIncluded (versionIncluded));
+ }
+
+ void push (var v)
+ {
+ if (! value.has_value())
+ return;
+
+ if (*value == var())
+ *value = v;
+ else if (auto* array = value->getArray())
+ array->add (v);
+ else
+ value.reset();
+ }
+
+ template
+ bool trySetProperty (DynamicObject& obj, const Named& n)
+ {
+ if (const auto converted = convert (n.value))
+ {
+ obj.setProperty (Identifier (std::string (n.name)), *converted);
+ return true;
+ }
+
+ return false;
+ }
+
+ std::optional version;
+ std::optional value;
+ bool versionIncluded = true;
+ };
+};
+
+//==============================================================================
+/**
+ Allows converting a var to an object of arbitrary type.
+
+ To use this, you must first ensure that the type passed to convert is set up for serialisation.
+ For details of what this entails, see the docs for SerialisationTraits.
+
+ In short, the constant 'marshallingVersion', and either the single function 'serialise()', or
+ the function pair 'load()' and 'save()' must be defined for the type. These may be defined
+ as public members of the type T itself, or as public members of juce::SerialisationTraits,
+ which is a specialisation of the SerialisationTraits template struct for the type T.
+
+ @see ToVar
+
+ @tags{Core}
+*/
+class FromVar
+{
+public:
+ /** Attempts to convert a var to an instance of type T.
+
+ This will return a non-null optional if conversion succeeds, or nullopt if conversion fails.
+ */
+ template
+ static std::optional convert (const var& v)
+ {
+ return Visitor::convert (v);
+ }
+
+private:
+ class Visitor
+ {
+ public:
+ template
+ static std::optional convert (const var& v)
+ {
+ const auto version = [&]() -> std::optional
+ {
+ if (auto* obj = v.getDynamicObject())
+ if (obj->hasProperty ("__version__"))
+ return (int) obj->getProperty ("__version__");
+
+ return std::nullopt;
+ }();
+
+ Visitor visitor { version, v };
+ T t{};
+ detail::doLoad (visitor, t);
+ return ! visitor.failed ? std::optional (std::move (t))
+ : std::nullopt;
+ }
+
+ std::optional getVersion() const { return version; }
+
+ template
+ void operator() (Ts&&... ts)
+ {
+ (visit (std::forward (ts)), ...);
+ }
+
+ private:
+ Visitor (std::optional vn, const var& i)
+ : version (vn), input (i) {}
+
+ template
+ void visit (T& t)
+ {
+ if constexpr (std::is_integral_v)
+ {
+ readPrimitive (std::in_place_type, t);
+ }
+ else if constexpr (std::is_floating_point_v)
+ {
+ readPrimitive (std::in_place_type, t);
+ }
+ else
+ {
+ auto node = getNodeToRead();
+
+ if (! node.has_value())
+ return;
+
+ auto converted = convert (*node);
+
+ if (converted.has_value())
+ t = *converted;
+ else
+ failed = true;
+ }
+ }
+
+ template
+ void visit (const Named& named)
+ {
+ auto node = getNodeToRead();
+
+ if (! node.has_value())
+ return;
+
+ auto* obj = node->getDynamicObject();
+
+ failed = obj == nullptr || ! tryGetProperty (*obj, named);
+ }
+
+ template
+ void visit (const SerialisationSize& t)
+ {
+ if (failed)
+ return;
+
+ if (auto* array = input.getArray())
+ {
+ t.size = static_cast (array->size());
+ currentArrayIndex = 0;
+ }
+ else
+ {
+ failed = true;
+ }
+ }
+
+ void visit (bool& t)
+ {
+ readPrimitive (std::in_place_type, t);
+ }
+
+ void visit (String& t)
+ {
+ readPrimitive (std::in_place_type, t);
+ }
+
+ void visit (var& t)
+ {
+ t = input;
+ }
+
+ static std::optional pullTyped (std::in_place_type_t, const var& source)
+ {
+ return source.isDouble() ? std::optional ((double) source) : std::nullopt;
+ }
+
+ static std::optional pullTyped (std::in_place_type_t, const var& source)
+ {
+ return source.isInt() || source.isInt64() ? std::optional ((int64) source) : std::nullopt;
+ }
+
+ static std::optional pullTyped (std::in_place_type_t, const var& source)
+ {
+ return source.isBool() || source.isInt() || source.isInt64() ? std::optional ((bool) source) : std::nullopt;
+ }
+
+ static std::optional pullTyped (std::in_place_type_t, const var& source)
+ {
+ return source.isString() ? std::optional (source.toString()) : std::nullopt;
+ }
+
+ std::optional getNodeToRead()
+ {
+ if (failed)
+ return std::nullopt;
+
+ if (currentArrayIndex == std::numeric_limits::max())
+ return input;
+
+ const auto* array = input.getArray();
+
+ if (array == nullptr)
+ return input;
+
+ if ((int) currentArrayIndex < array->size())
+ return array->getReference ((int) currentArrayIndex++);
+
+ failed = true;
+ return std::nullopt;
+ }
+
+ template
+ void readPrimitive (std::in_place_type_t tag, T& t)
+ {
+ auto node = getNodeToRead();
+
+ if (! node.has_value())
+ return;
+
+ auto typed = pullTyped (tag, *node);
+
+ if (typed.has_value())
+ t = static_cast (*typed);
+ else
+ failed = true;
+ }
+
+ template
+ static bool tryGetProperty (const DynamicObject& obj, const Named& n)
+ {
+ const Identifier identifier (String (n.name.data(), n.name.size()));
+
+ if (! obj.hasProperty (identifier))
+ return false;
+
+ const auto converted = convert (obj.getProperty (identifier));
+
+ if (! converted.has_value())
+ return false;
+
+ n.value = *converted;
+ return true;
+ }
+
+ std::optional version;
+ var input;
+ size_t currentArrayIndex = std::numeric_limits::max();
+ bool failed = false;
+ };
+};
+
+} // namespace juce
diff --git a/modules/juce_core/javascript/juce_JSONSerialisation_test.cpp b/modules/juce_core/javascript/juce_JSONSerialisation_test.cpp
new file mode 100644
index 0000000000..780ececdb6
--- /dev/null
+++ b/modules/juce_core/javascript/juce_JSONSerialisation_test.cpp
@@ -0,0 +1,652 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE library.
+ Copyright (c) 2022 - Raw Material Software Limited
+
+ JUCE is an open source library subject to commercial or open-source
+ licensing.
+
+ The code included in this file is provided under the terms of the ISC license
+ http://www.isc.org/downloads/software-support-policy/isc-license. Permission
+ To use, copy, modify, and/or distribute this software for any purpose with or
+ without fee is hereby granted provided that the above copyright notice and
+ this permission notice appear in all copies.
+
+ JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
+ EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
+ DISCLAIMED.
+
+ ==============================================================================
+*/
+
+namespace juce
+{
+
+struct TypeWithExternalUnifiedSerialisation
+{
+ int a;
+ std::string b;
+ std::vector c;
+ std::map d;
+
+ auto operator== (const TypeWithExternalUnifiedSerialisation& other) const
+ {
+ const auto tie = [] (const auto& x) { return std::tie (x.a, x.b, x.c, x.d); };
+ return tie (*this) == tie (other);
+ }
+
+ auto operator!= (const TypeWithExternalUnifiedSerialisation& other) const { return ! operator== (other); }
+};
+
+template <>
+struct SerialisationTraits
+{
+ static constexpr auto marshallingVersion = 2;
+
+ template
+ static void serialise (Archive& archive, T& t)
+ {
+ archive (named ("a", t.a),
+ named ("b", t.b),
+ named ("c", t.c),
+ named ("d", t.d));
+ }
+};
+
+// Now that the serialiser trait is visible, it should be detected
+static_assert (detail::serialisationKind == detail::SerialisationKind::external);
+
+struct TypeWithInternalUnifiedSerialisation
+{
+ double a;
+ float b;
+ String c;
+ StringArray d;
+
+ auto operator== (const TypeWithInternalUnifiedSerialisation& other) const
+ {
+ const auto tie = [] (const auto& x) { return std::tie (x.a, x.b, x.c, x.d); };
+ return tie (*this) == tie (other);
+ }
+
+ auto operator!= (const TypeWithInternalUnifiedSerialisation& other) const { return ! operator== (other); }
+
+ static constexpr auto marshallingVersion = 5;
+
+ template
+ static void serialise (Archive& archive, T& t)
+ {
+ archive (named ("a", t.a),
+ named ("b", t.b),
+ named ("c", t.c),
+ named ("d", t.d));
+ }
+};
+
+static_assert (detail::serialisationKind == detail::SerialisationKind::internal);
+
+struct TypeWithExternalSplitSerialisation
+{
+ std::optional a;
+ Array b;
+
+ auto operator== (const TypeWithExternalSplitSerialisation& other) const
+ {
+ const auto tie = [] (const auto& x) { return std::tie (x.a, x.b); };
+ return tie (*this) == tie (other);
+ }
+
+ auto operator!= (const TypeWithExternalSplitSerialisation& other) const { return ! operator== (other); }
+};
+
+template <>
+struct SerialisationTraits
+{
+ static constexpr auto marshallingVersion = 10;
+
+ template
+ static void load (Archive& archive, TypeWithExternalSplitSerialisation& t)
+ {
+ std::optional a;
+ Array hexStrings;
+ archive (named ("a", a), named ("b", hexStrings));
+
+ Array b;
+
+ for (auto& i : hexStrings)
+ b.add (i.getHexValue32());
+
+ t = { a, b };
+ }
+
+ template
+ static void save (Archive& archive, const TypeWithExternalSplitSerialisation& t)
+ {
+ Array hexStrings;
+
+ for (auto& i : t.b)
+ hexStrings.add ("0x" + String::toHexString (i));
+
+ archive (named ("a", t.a), named ("b", hexStrings));
+ }
+};
+
+// Now that the serialiser trait is visible, it should be detected
+static_assert (detail::serialisationKind == detail::SerialisationKind::external);
+
+// Check that serialisation kinds are correctly detected for primitives
+static_assert (detail::serialisationKind == detail::SerialisationKind::primitive);
+static_assert (detail::serialisationKind< int8_t> == detail::SerialisationKind::primitive);
+static_assert (detail::serialisationKind< uint8_t> == detail::SerialisationKind::primitive);
+static_assert (detail::serialisationKind< int16_t> == detail::SerialisationKind::primitive);
+static_assert (detail::serialisationKind == detail::SerialisationKind::primitive);
+static_assert (detail::serialisationKind< int32_t> == detail::SerialisationKind::primitive);
+static_assert (detail::serialisationKind == detail::SerialisationKind::primitive);
+static_assert (detail::serialisationKind< int64_t> == detail::SerialisationKind::primitive);
+static_assert (detail::serialisationKind == detail::SerialisationKind::primitive);
+static_assert (detail::serialisationKind == detail::SerialisationKind::primitive);
+static_assert (detail::serialisationKind == detail::SerialisationKind::primitive);
+static_assert (detail::serialisationKind == detail::SerialisationKind::primitive);
+static_assert (detail::serialisationKind == detail::SerialisationKind::primitive);
+
+// Check that serialisation is disabled for types with no serialsation defined
+static_assert (detail::serialisationKind == detail::SerialisationKind::none);
+static_assert (detail::serialisationKind == detail::SerialisationKind::none);
+
+struct TypeWithInternalSplitSerialisation
+{
+ std::string a;
+ Array b;
+
+ auto operator== (const TypeWithInternalSplitSerialisation& other) const
+ {
+ const auto tie = [] (const auto& x) { return std::tie (x.a, x.b); };
+ return tie (*this) == tie (other);
+ }
+
+ auto operator!= (const TypeWithInternalSplitSerialisation& other) const { return ! operator== (other); }
+
+ static constexpr auto marshallingVersion = 1;
+
+ template
+ static void load (Archive& archive, TypeWithInternalSplitSerialisation& t)
+ {
+ std::string a;
+ Array hexStrings;
+ archive (named ("a", a), named ("b", hexStrings));
+
+ Array b;
+
+ for (auto& i : hexStrings)
+ b.add (i.getHexValue32());
+
+ t = { a, b };
+ }
+
+ template
+ static void save (Archive& archive, const TypeWithInternalSplitSerialisation& t)
+ {
+ Array hexStrings;
+
+ for (auto& i : t.b)
+ hexStrings.add ("0x" + String::toHexString (i));
+
+ archive (named ("a", t.a), named ("b", hexStrings));
+ }
+};
+
+static_assert (detail::serialisationKind == detail::SerialisationKind::internal);
+
+struct TypeWithBrokenObjectSerialisation
+{
+ int a;
+ int b;
+
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void serialise (Archive& archive, T& t)
+ {
+ // Archiving a named value will start reading/writing an object
+ archive (named ("a", t.a));
+ // Archiving a non-named value will assume that the current node is convertible
+ archive (t.b);
+ }
+};
+
+struct TypeWithBrokenPrimitiveSerialisation
+{
+ int a;
+ int b;
+
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void serialise (Archive& archive, T& t)
+ {
+ // Archiving a non-named value will assume that the current node is convertible
+ archive (t.a);
+ // Archiving a named value will fail if the current node holds a non-object type
+ archive (named ("b", t.b));
+ }
+};
+
+struct TypeWithBrokenArraySerialisation
+{
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void serialise (Archive& archive, T&)
+ {
+ size_t size = 5;
+ archive (size);
+
+ // serialisationSize should always be serialised first!
+ archive (serialisationSize (size));
+ }
+};
+
+struct TypeWithBrokenNestedSerialisation
+{
+ int a;
+ TypeWithBrokenObjectSerialisation b;
+
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void serialise (Archive& archive, T& t)
+ {
+ archive (named ("a", t.a), named ("b", t.b));
+ }
+};
+
+struct TypeWithBrokenDynamicSerialisation
+{
+ std::vector a;
+
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void serialise (Archive& archive, T& t)
+ {
+ archive (t.a);
+ }
+};
+
+struct TypeWithVersionedSerialisation
+{
+ int a{}, b{}, c{}, d{};
+
+ bool operator== (const TypeWithVersionedSerialisation& other) const
+ {
+ const auto tie = [] (const auto& x) { return std::tie (x.a, x.b, x.c, x.d); };
+ return tie (*this) == tie (other);
+ }
+
+ bool operator!= (const TypeWithVersionedSerialisation& other) const { return ! operator== (other); }
+
+ static constexpr auto marshallingVersion = 3;
+
+ template
+ static void serialise (Archive& archive, T& t)
+ {
+ archive (named ("a", t.a));
+
+ if (archive.getVersion() >= 1)
+ archive (named ("b", t.b));
+
+ if (archive.getVersion() >= 2)
+ archive (named ("c", t.c));
+
+ if (archive.getVersion() >= 3)
+ archive (named ("d", t.d));
+ }
+};
+
+struct TypeWithRawVarLast
+{
+ int status = 0;
+ String message;
+ var extended;
+
+ bool operator== (const TypeWithRawVarLast& other) const
+ {
+ const auto tie = [] (const auto& x) { return std::tie (x.status, x.message, x.extended); };
+ return tie (*this) == tie (other);
+ }
+
+ bool operator!= (const TypeWithRawVarLast& other) const { return ! operator== (other); }
+
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void serialise (Archive& archive, T& t)
+ {
+ archive (named ("status", t.status),
+ named ("message", t.message),
+ named ("extended", t.extended));
+ }
+};
+
+struct TypeWithRawVarFirst
+{
+ int status = 0;
+ String message;
+ var extended;
+
+ bool operator== (const TypeWithRawVarFirst& other) const
+ {
+ const auto tie = [] (const auto& x) { return std::tie (x.status, x.message, x.extended); };
+ return tie (*this) == tie (other);
+ }
+
+ bool operator!= (const TypeWithRawVarFirst& other) const { return ! operator== (other); }
+
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void serialise (Archive& archive, T& t)
+ {
+ archive (named ("extended", t.extended),
+ named ("status", t.status),
+ named ("message", t.message));
+ }
+};
+
+struct TypeWithInnerVar
+{
+ int eventId = 0;
+ var payload;
+
+ bool operator== (const TypeWithInnerVar& other) const
+ {
+ const auto tie = [] (const auto& x) { return std::tie (x.eventId, x.payload); };
+ return tie (*this) == tie (other);
+ }
+
+ bool operator!= (const TypeWithInnerVar& other) const { return ! operator== (other); }
+
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void serialise (Archive& archive, T& t)
+ {
+ archive (named ("eventId", t.eventId),
+ named ("payload", t.payload));
+ }
+};
+
+class JSONSerialisationTest : public UnitTest
+{
+public:
+ JSONSerialisationTest() : UnitTest ("JSONSerialisation", UnitTestCategories::json) {}
+
+ void runTest() override
+ {
+ beginTest ("ToVar");
+ {
+ expectDeepEqual (ToVar::convert (false), false);
+ expectDeepEqual (ToVar::convert (true), true);
+ expectDeepEqual (ToVar::convert (1), 1);
+ expectDeepEqual (ToVar::convert (5.0f), 5.0);
+ expectDeepEqual (ToVar::convert (6LL), 6);
+ expectDeepEqual (ToVar::convert ("hello world"), "hello world");
+ expectDeepEqual (ToVar::convert (String ("hello world")), "hello world");
+ expectDeepEqual (ToVar::convert (std::vector { 1, 2, 3 }), Array { 1, 2, 3 });
+ expectDeepEqual (ToVar::convert (TypeWithExternalUnifiedSerialisation { 7,
+ "hello world",
+ { 5, 6, 7 },
+ { { "foo", 4 }, { "bar", 5 } } }),
+ makeObject ({ { "__version__", 2 },
+ { "a", 7 },
+ { "b", "hello world" },
+ { "c", Array { 5, 6, 7 } },
+ { "d", Array { makeObject ({ { "first", "bar" }, { "second", 5 } }),
+ makeObject ({ { "first", "foo" }, { "second", 4 } }) } } }));
+ expectDeepEqual (ToVar::convert (TypeWithInternalUnifiedSerialisation { 7.89,
+ 4.321f,
+ "custom string",
+ { "foo", "bar", "baz" } }),
+ makeObject ({ { "__version__", 5 },
+ { "a", 7.89 },
+ { "b", 4.321f },
+ { "c", "custom string" },
+ { "d", Array { "foo", "bar", "baz" } } }));
+ expectDeepEqual (ToVar::convert (TypeWithExternalSplitSerialisation { "string", { 1, 2, 3 } }),
+ makeObject ({ { "__version__", 10 },
+ { "a", makeObject ({ { "engaged", true }, { "value", "string" } }) },
+ { "b", Array { "0x1", "0x2", "0x3" } } }));
+ expectDeepEqual (ToVar::convert (TypeWithInternalSplitSerialisation { "string", { 16, 32, 48 } }),
+ makeObject ({ { "__version__", 1 },
+ { "a", "string" },
+ { "b", Array { "0x10", "0x20", "0x30" } } }));
+
+ expect (ToVar::convert (TypeWithBrokenObjectSerialisation { 1, 2 }) == std::nullopt);
+ expect (ToVar::convert (TypeWithBrokenPrimitiveSerialisation { 1, 2 }) == std::nullopt);
+ expect (ToVar::convert (TypeWithBrokenArraySerialisation {}) == std::nullopt);
+ expect (ToVar::convert (TypeWithBrokenNestedSerialisation {}) == std::nullopt);
+ expect (ToVar::convert (TypeWithBrokenDynamicSerialisation { std::vector (10) }) == std::nullopt);
+
+ expectDeepEqual (ToVar::convert (TypeWithVersionedSerialisation { 1, 2, 3, 4 }),
+ makeObject ({ { "__version__", 3 },
+ { "a", 1 },
+ { "b", 2 },
+ { "c", 3 },
+ { "d", 4 } }));
+ expectDeepEqual (ToVar::convert (TypeWithVersionedSerialisation { 1, 2, 3, 4 }, ToVar::Options{}.withVersionIncluded (false)),
+ makeObject ({ { "a", 1 },
+ { "b", 2 },
+ { "c", 3 },
+ { "d", 4 } }));
+ // Requested explicit version is higher than the type's declared version
+ expectDeepEqual (ToVar::convert (TypeWithVersionedSerialisation { 1, 2, 3, 4 }, ToVar::Options{}.withExplicitVersion (4)),
+ std::nullopt);
+ expectDeepEqual (ToVar::convert (TypeWithVersionedSerialisation { 1, 2, 3, 4 }, ToVar::Options {}.withExplicitVersion (3)),
+ makeObject ({ { "__version__", 3 },
+ { "a", 1 },
+ { "b", 2 },
+ { "c", 3 },
+ { "d", 4 } }));
+ expectDeepEqual (ToVar::convert (TypeWithVersionedSerialisation { 1, 2, 3, 4 }, ToVar::Options {}.withExplicitVersion (2)),
+ makeObject ({ { "__version__", 2 },
+ { "a", 1 },
+ { "b", 2 },
+ { "c", 3 } }));
+ expectDeepEqual (ToVar::convert (TypeWithVersionedSerialisation { 1, 2, 3, 4 }, ToVar::Options {}.withExplicitVersion (1)),
+ makeObject ({ { "__version__", 1 },
+ { "a", 1 },
+ { "b", 2 } }));
+ expectDeepEqual (ToVar::convert (TypeWithVersionedSerialisation { 1, 2, 3, 4 }, ToVar::Options {}.withExplicitVersion (0)),
+ makeObject ({ { "__version__", 0 },
+ { "a", 1 } }));
+ expectDeepEqual (ToVar::convert (TypeWithVersionedSerialisation { 1, 2, 3, 4 }, ToVar::Options {}.withExplicitVersion (std::nullopt)),
+ makeObject ({ { "a", 1 } }));
+
+ expectDeepEqual (ToVar::convert (TypeWithRawVarLast { 200, "success", true }),
+ makeObject ({ { "status", 200 }, { "message", "success" }, { "extended", true } }));
+ expectDeepEqual (ToVar::convert (TypeWithRawVarLast { 200,
+ "success",
+ makeObject ({ { "status", 123.456 },
+ { "message", "failure" },
+ { "extended", true } }) }),
+ makeObject ({ { "status", 200 },
+ { "message", "success" },
+ { "extended", makeObject ({ { "status", 123.456 },
+ { "message", "failure" },
+ { "extended", true } }) } }));
+
+ expectDeepEqual (ToVar::convert (TypeWithRawVarFirst { 200, "success", true }),
+ makeObject ({ { "status", 200 }, { "message", "success" }, { "extended", true } }));
+ expectDeepEqual (ToVar::convert (TypeWithRawVarFirst { 200,
+ "success",
+ makeObject ({ { "status", 123.456 },
+ { "message", "failure" },
+ { "extended", true } }) }),
+ makeObject ({ { "status", 200 },
+ { "message", "success" },
+ { "extended", makeObject ({ { "status", 123.456 },
+ { "message", "failure" },
+ { "extended", true } }) } }));
+
+ const auto payload = makeObject ({ { "foo", 1 }, { "bar", 2 } });
+ expectDeepEqual (ToVar::convert (TypeWithInnerVar { 404, payload }),
+ makeObject ({ { "eventId", 404 }, { "payload", payload } }));
+ }
+
+ beginTest ("FromVar");
+ {
+ expect (FromVar::convert (JSON::fromString ("false")) == false);
+ expect (FromVar::convert (JSON::fromString ("true")) == true);
+ expect (FromVar::convert (JSON::fromString ("0")) == false);
+ expect (FromVar::convert (JSON::fromString ("1")) == true);
+ expect (FromVar::convert (JSON::fromString ("1")) == 1);
+ expect (FromVar::convert (JSON::fromString ("5.0f")) == 5.0f);
+ expect (FromVar::convert (JSON::fromString ("6")) == 6);
+ expect (FromVar::convert (JSON::fromString ("\"hello world\"")) == "hello world");
+ expect (FromVar::convert> (JSON::fromString ("[1,2,3]")) == std::vector { 1, 2, 3 });
+ expect (FromVar::convert (makeObject ({ { "__version__", 2 },
+ { "a", 7 },
+ { "b", "hello world" },
+ { "c", Array { 5, 6, 7 } },
+ { "d", Array { makeObject ({ { "first", "bar" }, { "second", 5 } }),
+ makeObject ({ { "first", "foo" }, { "second", 4 } }) } } }))
+ == TypeWithExternalUnifiedSerialisation { 7,
+ "hello world",
+ { 5, 6, 7 },
+ { { "foo", 4 }, { "bar", 5 } } });
+
+ expect (FromVar::convert (makeObject ({ { "__version__", 5 },
+ { "a", 7.89 },
+ { "b", 4.321f },
+ { "c", "custom string" },
+ { "d", Array { "foo", "bar", "baz" } } }))
+ == TypeWithInternalUnifiedSerialisation { 7.89,
+ 4.321f,
+ "custom string",
+ { "foo", "bar", "baz" } });
+
+ expect (FromVar::convert (makeObject ({ { "__version__", 10 },
+ { "a", makeObject ({ { "engaged", true }, { "value", "string" } }) },
+ { "b", Array { "0x1", "0x2", "0x3" } } }))
+ == TypeWithExternalSplitSerialisation { "string", { 1, 2, 3 } });
+ expect (FromVar::convert (makeObject ({ { "__version__", 1 },
+ { "a", "string" },
+ { "b", Array { "0x10", "0x20", "0x30" } } }))
+ == TypeWithInternalSplitSerialisation { "string", { 16, 32, 48 } });
+
+ expect (FromVar::convert (JSON::fromString ("null")) == std::nullopt);
+ expect (FromVar::convert (JSON::fromString ("null")) == std::nullopt);
+ expect (FromVar::convert (JSON::fromString ("null")) == std::nullopt);
+ expect (FromVar::convert (JSON::fromString ("null")) == std::nullopt);
+ expect (FromVar::convert (JSON::fromString ("null")) == std::nullopt);
+
+ expect (FromVar::convert (makeObject ({ { "a", 7.89 },
+ { "b", 4.321f } })) == std::nullopt);
+
+ expect (FromVar::convert (makeObject ({ { "__version__", 3 },
+ { "a", 1 },
+ { "b", 2 },
+ { "c", 3 },
+ { "d", 4 } }))
+ == TypeWithVersionedSerialisation { 1, 2, 3, 4 });
+ expect (FromVar::convert (makeObject ({ { "__version__", 4 },
+ { "a", 1 },
+ { "b", 2 },
+ { "c", 3 },
+ { "d", 4 } }))
+ == TypeWithVersionedSerialisation { 1, 2, 3, 4 });
+ expect (FromVar::convert (makeObject ({ { "__version__", 2 },
+ { "a", 1 },
+ { "b", 2 },
+ { "c", 3 } }))
+ == TypeWithVersionedSerialisation { 1, 2, 3, 0 });
+ expect (FromVar::convert (makeObject ({ { "__version__", 1 },
+ { "a", 1 },
+ { "b", 2 } }))
+ == TypeWithVersionedSerialisation { 1, 2, 0, 0 });
+ expect (FromVar::convert (makeObject ({ { "__version__", 0 },
+ { "a", 1 } }))
+ == TypeWithVersionedSerialisation { 1, 0, 0, 0 });
+ expect (FromVar::convert (makeObject ({ { "a", 1 } }))
+ == TypeWithVersionedSerialisation { 1, 0, 0, 0 });
+
+ const auto raw = makeObject ({ { "status", 200 }, { "message", "success" }, { "extended", "another string" } });
+ expect (FromVar::convert (raw) == TypeWithRawVarLast { 200, "success", "another string" });
+ expect (FromVar::convert (raw) == TypeWithRawVarFirst { 200, "success", "another string" });
+
+ const var payloads[] { makeObject ({ { "foo", 1 }, { "bar", 2 } }),
+ var (Array { 1, 2 }),
+ var() };
+
+ for (const auto& payload : payloads)
+ {
+ const auto objectWithPayload = makeObject ({ { "eventId", 404 }, { "payload", payload } });
+ expect (FromVar::convert (objectWithPayload) == TypeWithInnerVar { 404, payload });
+ }
+ }
+ }
+
+private:
+ void expectDeepEqual (const std::optional& a, const std::optional& b)
+ {
+ expect (deepEqual (a, b), a.has_value() && b.has_value() ? JSON::toString (*a) + " != " + JSON::toString (*b) : String());
+ }
+
+ static var makeObject (const std::map& map)
+ {
+ auto obj = std::make_unique();
+
+ for (auto& [key, value] : map)
+ obj->setProperty (key, value);
+
+ return obj.release();
+ }
+
+ static bool deepEqual (const DynamicObject& a, const DynamicObject& b)
+ {
+ if (a.getProperties().size() != b.getProperties().size())
+ return false;
+
+ for (const auto& [key, value] : a.getProperties())
+ {
+ if (! b.hasProperty (key))
+ return false;
+
+ if (! deepEqual (value, b.getProperty (key)))
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool deepEqual (const Array& a, const Array& b)
+ {
+ return std::equal (a.begin(), a.end(), b.begin(), b.end(), [] (const var& i, const var& j) { return deepEqual (i, j); });
+ }
+
+ static bool deepEqual (const var& a, const var& b)
+ {
+ if (auto* i = a.getDynamicObject())
+ if (auto* j = b.getDynamicObject())
+ return deepEqual (*i, *j);
+
+ if (auto* i = a.getArray())
+ if (auto* j = b.getArray())
+ return deepEqual (*i, *j);
+
+ return a == b;
+ }
+
+ static bool deepEqual (const std::optional& a, const std::optional& b)
+ {
+ if (a.has_value() != b.has_value())
+ return false;
+
+ return ! a.has_value() || deepEqual (*a, *b);
+ }
+};
+
+static JSONSerialisationTest jsonSerialisationTest;
+
+} // namespace juce
diff --git a/modules/juce_core/juce_core.cpp b/modules/juce_core/juce_core.cpp
index 6f0ac4997c..0e6b23fb37 100644
--- a/modules/juce_core/juce_core.cpp
+++ b/modules/juce_core/juce_core.cpp
@@ -281,6 +281,7 @@
#include "maths/juce_MathsFunctions_test.cpp"
#include "misc/juce_EnumHelpers_test.cpp"
#include "containers/juce_FixedSizeFunction_test.cpp"
+ #include "javascript/juce_JSONSerialisation_test.cpp"
#endif
//==============================================================================
diff --git a/modules/juce_core/juce_core.h b/modules/juce_core/juce_core.h
index a1074d03ca..011dd00c68 100644
--- a/modules/juce_core/juce_core.h
+++ b/modules/juce_core/juce_core.h
@@ -309,6 +309,8 @@ JUCE_END_IGNORE_WARNINGS_MSVC
#include "streams/juce_FileInputSource.h"
#include "logging/juce_FileLogger.h"
#include "javascript/juce_JSON.h"
+#include "serialisation/juce_Serialisation.h"
+#include "javascript/juce_JSONSerialisation.h"
#include "javascript/juce_Javascript.h"
#include "maths/juce_BigInteger.h"
#include "maths/juce_Expression.h"
diff --git a/modules/juce_core/serialisation/juce_Serialisation.h b/modules/juce_core/serialisation/juce_Serialisation.h
new file mode 100644
index 0000000000..a8431a0ab1
--- /dev/null
+++ b/modules/juce_core/serialisation/juce_Serialisation.h
@@ -0,0 +1,576 @@
+/*
+ ==============================================================================
+
+ This file is part of the JUCE library.
+ Copyright (c) 2022 - Raw Material Software Limited
+
+ JUCE is an open source library subject to commercial or open-source
+ licensing.
+
+ The code included in this file is provided under the terms of the ISC license
+ http://www.isc.org/downloads/software-support-policy/isc-license. Permission
+ To use, copy, modify, and/or distribute this software for any purpose with or
+ without fee is hereby granted provided that the above copyright notice and
+ this permission notice appear in all copies.
+
+ JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
+ EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
+ DISCLAIMED.
+
+ ==============================================================================
+*/
+
+namespace juce
+{
+
+#define JUCE_COMPARISON_OPS X(==) X(!=) X(<) X(<=) X(>) X(>=)
+
+/**
+ Combines an object with a name.
+
+ Instances of Named have reference-like semantics. That is, Named stores a reference
+ to a wrapped value, rather than storing the value internally.
+
+ @tparam T the type of reference that is wrapped. Passing "const T" will cause the Named
+ instance to hold a "const T&"; passing "T" will cause the Named instance to
+ hold a "T&".
+
+ @see named()
+
+ @tags{Core}
+*/
+template
+struct Named
+{
+ #define X(op) auto operator op (const Named& other) const { return value op other.value; }
+ JUCE_COMPARISON_OPS
+ #undef X
+
+ std::string_view name; ///< A name that corresponds to the value
+ T& value; ///< A reference to a value to wrap
+};
+
+/** Produces a Named instance that holds a mutable reference. */
+template constexpr auto named (std::string_view c, T& t) { return Named { c, t }; }
+
+/** Produces a Named instance that holds an immutable reference. */
+template constexpr auto named (std::string_view c, const T& t) { return Named { c, t }; }
+
+/**
+ Holds a reference to some kind of size value, used to indicate that an object being marshalled
+ is of variable size (e.g. Array, vector, map, set, etc.).
+
+ If you need to write your own serialisation routines for a dynamically-sized type, ensure
+ that you archive an instance of SerialisationSize before any of the contents of the container.
+
+ @tparam the (probably numeric) type of the size value
+
+ @see serialisztionSize()
+
+ @tags{Core}
+*/
+template
+struct SerialisationSize
+{
+ #define X(op) auto operator op (const SerialisationSize& other) const { return size op other.size; }
+ JUCE_COMPARISON_OPS
+ #undef X
+
+ T& size;
+};
+
+/** Produces a SerialisationSize instance that holds a mutable reference to a size value. */
+template constexpr auto serialisationSize (T& t) -> std::enable_if_t, SerialisationSize> { return { t }; }
+
+/** Produces a SerialisationSize instance that holds an immutable reference to a size value. */
+template constexpr auto serialisationSize (const T& t) -> std::enable_if_t, SerialisationSize> { return { t }; }
+
+#undef JUCE_COMPARISON_OPS
+
+/**
+ Allows serialisation functions to be attached to a specific type without having to modify the
+ declaration of that type.
+
+ A specialisation of SerialisationTraits must include:
+ - A static constexpr data member named 'marshallingVersion' with a value that is convertible
+ to std::optional.
+ - Either:
+ - Normally, a single function with the following signature:
+ @code
+ template
+ static void serialise (Archive& archive, Item& item);
+ @endcode
+ - For types that must do slightly different work when loading and saving, you may supply two
+ functions with the following signatures, where "T" is a placeholder for the type on which
+ SerialisationTraits is specialised:
+ @code
+ template
+ static void load (Archive& archive, T& item);
+
+ template
+ static void save (Archive& archive, const T& item);
+ @endcode
+
+ If the marshallingVersion converts to a null optional, then all versioning information will be
+ ignored when marshalling the type. Otherwise, if the value converts to a non-null optional, this
+ versioning information will be included when serialising the type.
+
+ Inside serialise() and load() you may call archive.getVersion() to find the detected version
+ of the object being deserialised. archive.getVersion() will return an std::optional,
+ where 'nullopt' indicates that no versioning information was detected.
+
+ Marshalling functions can also be specified directly inside the type to be marshalled. This
+ approach may be preferable as it is more concise. Internal marshalling functions are written
+ in exactly the same way as external ones; i.e. the type must include a marshallingVersion,
+ and either a single serialise function, or a load/save pair of functions, as specified above.
+
+ @tags{Core}
+*/
+template struct SerialisationTraits
+{
+ /* Intentionally left blank. */
+};
+
+//==============================================================================
+/*
+ The following are specialisations of SerialisationTraits for commonly-used types.
+*/
+
+template
+struct SerialisationTraits>
+{
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void load (Archive& archive, T& t)
+ {
+ auto size = t.size();
+ archive (serialisationSize (size));
+ t.resize (size);
+
+ for (auto& element : t)
+ archive (element);
+ }
+
+ template
+ static void save (Archive& archive, const T& t)
+ {
+ archive (serialisationSize (t.size()));
+
+ for (auto& element : t)
+ archive (element);
+ }
+};
+
+template
+struct SerialisationTraits>
+{
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void load (Archive& archive, T& t)
+ {
+ auto size = t.size();
+ archive (serialisationSize (size));
+ t.resize (size);
+
+ for (auto& element : t)
+ archive (element);
+ }
+
+ template
+ static void save (Archive& archive, const T& t)
+ {
+ archive (serialisationSize (t.size()));
+
+ for (auto& element : t)
+ archive (element);
+ }
+};
+
+template <>
+struct SerialisationTraits
+{
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void serialise (Archive& archive, T& t)
+ {
+ archive (t.strings);
+ }
+};
+
+template
+struct SerialisationTraits>
+{
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void serialise (Archive& archive, T& t)
+ {
+ archive (named ("first", t.first), named ("second", t.second));
+ }
+};
+
+template
+struct SerialisationTraits>
+{
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void load (Archive& archive, std::optional& t)
+ {
+ bool engaged = false;
+
+ archive (named ("engaged", engaged));
+
+ if (! engaged)
+ return;
+
+ t.emplace();
+ archive (named ("value", *t));
+ }
+
+ template
+ static void save (Archive& archive, const std::optional& t)
+ {
+ archive (named ("engaged", t.has_value()));
+
+ if (t.has_value())
+ archive (named ("value", *t));
+ }
+};
+
+template <>
+struct SerialisationTraits
+{
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void load (Archive& archive, std::string& t)
+ {
+ String temporary;
+ archive (temporary);
+ t = temporary.toStdString();
+ }
+
+ template
+ static void save (Archive& archive, const std::string& t)
+ {
+ archive (String (t));
+ }
+};
+
+template
+struct SerialisationTraits>
+{
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void load (Archive& archive, T& t)
+ {
+ auto size = t.size();
+ archive (serialisationSize (size));
+
+ for (auto i = (decltype (size)) 0; i < size; ++i)
+ {
+ std::pair element;
+ archive (element);
+ t.insert (element);
+ }
+ }
+
+ template
+ static void save (Archive& archive, const T& t)
+ {
+ auto size = t.size();
+ archive (serialisationSize (size));
+
+ for (const auto& element : t)
+ archive (element);
+ }
+};
+
+template
+struct SerialisationTraits>
+{
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void load (Archive& archive, T& t)
+ {
+ auto size = t.size();
+ archive (serialisationSize (size));
+
+ for (auto i = (decltype (size)) 0; i < size; ++i)
+ {
+ typename T::value_type element;
+ archive (element);
+ t.insert (element);
+ }
+ }
+
+ template
+ static void save (Archive& archive, const T& t)
+ {
+ auto size = t.size();
+ archive (serialisationSize (size));
+
+ for (const auto& element : t)
+ archive (element);
+ }
+};
+
+template
+struct SerialisationTraits
+{
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void serialise (Archive& archive, T& t) { archive (String (t, N)); }
+};
+
+template
+struct SerialisationTraits
+{
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void load (Archive& archive, T& t)
+ {
+ auto size = N;
+ archive (serialisationSize (size));
+
+ for (auto& element : t)
+ archive (element);
+ }
+
+ template
+ static void save (Archive& archive, const T& t)
+ {
+ const auto size = N;
+ archive (serialisationSize (size));
+
+ for (auto& element : t)
+ archive (element);
+ }
+};
+
+template
+struct SerialisationTraits>
+{
+ static constexpr auto marshallingVersion = std::nullopt;
+
+ template
+ static void load (Archive& archive, T& t)
+ {
+ auto size = N;
+ archive (serialisationSize (size));
+
+ for (auto& element : t)
+ archive (element);
+ }
+
+ template
+ static void save (Archive& archive, const T& t)
+ {
+ const auto size = N;
+ archive (serialisationSize (size));
+
+ for (auto& element : t)
+ archive (element);
+ }
+};
+
+#ifndef DOXYGEN
+
+/*
+ This namespace holds utilities for detecting and using serialisation functions.
+
+ The contents of this namespace are private, and liable to change, so you shouldn't use any of
+ the contents directly.
+*/
+namespace detail
+{
+ struct DummyArchive
+ {
+ template
+ bool operator() (Ts&&...);
+
+ std::optional getVersion() const { return {}; }
+ };
+
+ template
+ constexpr auto hasInternalVersion = false;
+
+ template
+ constexpr auto hasInternalVersion> = true;
+
+ template
+ constexpr auto hasInternalSerialise = false;
+
+ template
+ constexpr auto hasInternalSerialise(), std::declval()))>> = true;
+
+ template
+ constexpr auto hasInternalLoad = false;
+
+ template
+ constexpr auto hasInternalLoad(), std::declval()))>> = true;
+
+ template
+ constexpr auto hasInternalSave = false;
+
+ template
+ constexpr auto hasInternalSave(), std::declval()))>> = true;
+
+ template
+ struct SerialisedTypeTrait { using type = T; };
+
+ template
+ struct SerialisedTypeTrait> { using type = T; };
+
+ template
+ using SerialisedType = typename SerialisedTypeTrait::type;
+
+ template
+ constexpr auto hasSerialisation = hasInternalVersion>
+ || hasInternalSerialise