Skip to content

Commit a4c470b

Browse files
committed
feat: Add an easier way to enable experimental code changes.
1 parent ed2b60c commit a4c470b

File tree

2 files changed

+138
-33
lines changed

2 files changed

+138
-33
lines changed

toxcore/tox.h

Lines changed: 127 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,69 @@ uint32_t tox_max_hostname_length(void);
346346
* @name Global enumerations
347347
*/
348348

349+
/**
350+
* @brief Experiment IDs to control (incompatible) changes dynamically.
351+
*
352+
* Experiments are changes in toxcore that can be configured by client
353+
* code. These are used to make incompatible changes to toxcore between
354+
* API/ABI-breaking releases, so clients can already test some functionality
355+
* that may break or be removed again on the next patch release. Compatible
356+
* changes may still be rolled out using experiments, and the flag can be
357+
* flipped to default to a different value (e.g. true for bool) on the next
358+
* patch release. Clients can explicitly revert them again if desired.
359+
*
360+
* All experiment flags must have an explicit number in this enum. When
361+
* removing an experiment flag, the gap it leaves can not be reused. Removal
362+
* of an experiment flag is an API breaking change, so it can only be done in
363+
* API-breaking releases. Changing the default value of an experiment may or
364+
* may not be an API- or ABI-breaking change.
365+
*
366+
* @see TOX_VERSION_IS_API_COMPATIBLE for what an API-breaking release is.
367+
*
368+
* Next ID: 3
369+
*/
370+
typedef enum Tox_Experiment_Type {
371+
372+
/**
373+
* Not a valid experiment ID. Not used to designate any experiment.
374+
*/
375+
TOX_EXPERIMENT_INVALID = 0,
376+
377+
/**
378+
* Make public API functions thread-safe using a per-instance lock.
379+
*
380+
* Type: bool
381+
* Default: disabled
382+
*/
383+
TOX_EXPERIMENT_THREAD_SAFETY = 1,
384+
385+
/**
386+
* Enable saving DHT-based group chats to Tox save data (via `tox_get_savedata`).
387+
* This format will change in the future, so don't rely on it.
388+
*
389+
* As an alternative, clients can save the group chat ID in client-owned
390+
* savedata. Then, when the client starts, it can use `tox_group_join`
391+
* with the saved chat ID to recreate the group chat.
392+
*
393+
* Type: bool
394+
* Default: disabled
395+
*/
396+
TOX_EXPERIMENT_GROUPS_PERSISTENCE = 2,
397+
398+
} Tox_Experiment_Type;
399+
400+
const char *tox_experiment_type_to_string(Tox_Experiment_Type value);
401+
402+
/**
403+
* @brief Opaque container for an experiment value.
404+
*
405+
* Can have different types (e.g. bool). See The Tox_Experiment_Type enum above
406+
* to see which experiment has which type.
407+
*
408+
* @private
409+
*/
410+
typedef struct Tox_Experiment Tox_Experiment;
411+
349412
/**
350413
* @brief Represents the possible statuses a client can have.
351414
*/
@@ -492,7 +555,7 @@ const char *tox_log_level_to_string(Tox_Log_Level value);
492555
* any time. Thus, user code must make sure it is equipped to handle concurrent
493556
* execution, e.g. by employing appropriate mutex locking.
494557
*
495-
* When using the experimental_thread_safety option, no Tox API functions can
558+
* When using the TOX_EXPERIMENT_THREAD_SAFETY flag, no Tox API functions can
496559
* be called from within the log callback.
497560
*
498561
* @param level The severity of the log message.
@@ -511,14 +574,19 @@ typedef void tox_log_cb(Tox *tox, Tox_Log_Level level, const char *file, uint32_
511574
* This struct is opaque and generally shouldn't be used in clients, but in
512575
* combination with tox_private.h, it allows tests to inject non-IO (hermetic)
513576
* versions of low level network, RNG, and time keeping functions.
577+
*
578+
* @private
514579
*/
515580
typedef struct Tox_System Tox_System;
516581

517582
/**
518-
* @brief This struct contains all the startup options for Tox.
583+
* @brief Opaque options struct containing all the startup options for Tox.
519584
*
520585
* You must tox_options_new to allocate an object of this type.
521-
*
586+
*/
587+
typedef struct Tox_Options Tox_Options;
588+
589+
/**
522590
* WARNING: Although this struct happens to be visible in the API, it is
523591
* effectively private. Do not allocate this yourself or access members
524592
* directly, as it *will* break binary compatibility frequently.
@@ -528,8 +596,8 @@ typedef struct Tox_System Tox_System;
528596
* tox_options_new to allocate the object and accessor functions to set the
529597
* members. The struct will become opaque (i.e. the definition will become
530598
* private) in v0.3.0.
531-
*/
532-
typedef struct Tox_Options Tox_Options;
599+
*
600+
* @private */
533601
struct Tox_Options {
534602

535603
/**
@@ -665,12 +733,6 @@ struct Tox_Options {
665733
* entirely in the future, or may be renamed to something non-experimental
666734
* if they become part of the supported API.
667735
*/
668-
/**
669-
* Make public API functions thread-safe using a per-instance lock.
670-
*
671-
* Default: false.
672-
*/
673-
bool experimental_thread_safety;
674736

675737
/**
676738
* Low level operating system functionality such as send/recv, random
@@ -679,16 +741,14 @@ struct Tox_Options {
679741
const Tox_System *operating_system;
680742

681743
/**
682-
* Enable saving DHT-based group chats to Tox save data (via `tox_get_savedata`).
683-
* This format will change in the future, so don't rely on it.
744+
* @brief Set of enabled experiments.
684745
*
685-
* As an alternative, clients can save the group chat ID in client-owned
686-
* savedata. Then, when the client starts, it can use `tox_group_join`
687-
* with the saved chat ID to recreate the group chat.
746+
* Use set functions to set experiment values to custom values.
688747
*
689-
* Default: false.
748+
* Default: all experiments set to their default values.
690749
*/
691-
bool experimental_groups_persistence;
750+
Tox_Experiment *experiments;
751+
uint32_t experiments_size;
692752
};
693753

694754
bool tox_options_get_ipv6_enabled(const Tox_Options *options);
@@ -755,18 +815,62 @@ void *tox_options_get_log_user_data(const Tox_Options *options);
755815

756816
void tox_options_set_log_user_data(Tox_Options *options, void *log_user_data);
757817

758-
bool tox_options_get_experimental_thread_safety(const Tox_Options *options);
759-
760-
void tox_options_set_experimental_thread_safety(Tox_Options *options, bool experimental_thread_safety);
761-
818+
/** @private */
762819
const Tox_System *tox_options_get_operating_system(const Tox_Options *options);
763820

821+
/** @private */
764822
void tox_options_set_operating_system(Tox_Options *options, const Tox_System *operating_system);
765823

824+
/** @deprecated Use tox_options_experiment_get_bool, instead. */
825+
bool tox_options_get_experimental_thread_safety(const Tox_Options *options);
826+
827+
/** @deprecated Use tox_options_experiment_set_bool, instead. */
828+
void tox_options_set_experimental_thread_safety(Tox_Options *options, bool experimental_thread_safety);
829+
830+
/** @deprecated Use tox_options_experiment_get_bool, instead. */
766831
bool tox_options_get_experimental_groups_persistence(const Tox_Options *options);
767832

833+
/** @deprecated Use tox_options_experiment_set_bool, instead. */
768834
void tox_options_set_experimental_groups_persistence(Tox_Options *options, bool experimental_groups_persistence);
769835

836+
typedef enum Tox_Err_Options_Experiment {
837+
838+
/**
839+
* The function returned successfully.
840+
*/
841+
TOX_ERR_OPTIONS_EXPERIMENT_OK,
842+
843+
/**
844+
* The flag does not exist in this version of toxcore.
845+
*/
846+
TOX_ERR_OPTIONS_EXPERIMENT_INVALID_FLAG,
847+
848+
/**
849+
* The type of this experiment flag is different than the function type.
850+
*/
851+
TOX_ERR_OPTIONS_EXPERIMENT_INVALID_TYPE,
852+
853+
} Tox_Err_Options_Experiment;
854+
855+
/** @brief Get the value of a boolean experiment flag.
856+
*
857+
* @retval true if the flag was enabled and the experiment type was boolean.
858+
* @retval false if the flag was disabled OR the experiment type was not boolean.
859+
*/
860+
bool tox_options_experiment_get_bool(
861+
const Tox_Options *options, Tox_Experiment_Type experiment, Tox_Err_Options_Experiment *err);
862+
863+
/** @brief Enable or explicitly disable a boolean experiment flag.
864+
*
865+
* If the experiment is already enabled/disabled when enabling/disabling,
866+
* respectively, this function does nothing.
867+
*
868+
* @retval true if the flag was set.
869+
* @retval false on error.
870+
*/
871+
bool tox_options_experiment_set_bool(
872+
Tox_Options *options, Tox_Experiment_Type experiment, bool value, Tox_Err_Options_Experiment *err);
873+
770874
/**
771875
* @brief Initialises a Tox_Options object with the default options.
772876
*
@@ -802,6 +906,7 @@ const char *tox_err_options_new_to_string(Tox_Err_Options_New value);
802906
*
803907
* This function can be used to preserve long term ABI compatibility by
804908
* giving the responsibility of allocation and deallocation to the Tox library.
909+
* All experiment flags are set to their default values.
805910
*
806911
* Objects returned from this function must be freed using the tox_options_free
807912
* function.

toxcore/tox_api.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -256,15 +256,6 @@ void tox_options_set_dht_announcements_enabled(Tox_Options *options, bool dht_an
256256
{
257257
options->dht_announcements_enabled = dht_announcements_enabled;
258258
}
259-
bool tox_options_get_experimental_thread_safety(const Tox_Options *options)
260-
{
261-
return options->experimental_thread_safety;
262-
}
263-
void tox_options_set_experimental_thread_safety(
264-
Tox_Options *options, bool experimental_thread_safety)
265-
{
266-
options->experimental_thread_safety = experimental_thread_safety;
267-
}
268259
const Tox_System *tox_options_get_operating_system(const Tox_Options *options)
269260
{
270261
return options->operating_system;
@@ -273,14 +264,23 @@ void tox_options_set_operating_system(Tox_Options *options, const Tox_System *op
273264
{
274265
options->operating_system = operating_system;
275266
}
267+
bool tox_options_get_experimental_thread_safety(const Tox_Options *options)
268+
{
269+
return tox_options_experiment_get_bool(options, TOX_EXPERIMENT_THREAD_SAFETY, nullptr);
270+
}
271+
void tox_options_set_experimental_thread_safety(
272+
Tox_Options *options, bool experimental_thread_safety)
273+
{
274+
tox_options_experiment_set_bool(options, TOX_EXPERIMENT_THREAD_SAFETY, experimental_thread_safety, nullptr);
275+
}
276276
bool tox_options_get_experimental_groups_persistence(const Tox_Options *options)
277277
{
278-
return options->experimental_groups_persistence;
278+
return tox_options_experiment_get_bool(options, TOX_EXPERIMENT_GROUPS_PERSISTENCE, nullptr);
279279
}
280280
void tox_options_set_experimental_groups_persistence(
281281
Tox_Options *options, bool experimental_groups_persistence)
282282
{
283-
options->experimental_groups_persistence = experimental_groups_persistence;
283+
tox_options_experiment_set_bool(options, TOX_EXPERIMENT_GROUPS_PERSISTENCE, experimental_groups_persistence, nullptr);
284284
}
285285

286286
const uint8_t *tox_options_get_savedata_data(const Tox_Options *options)

0 commit comments

Comments
 (0)