diff --git a/glass/src/libnt/native/cpp/NTDigitalInput.cpp b/glass/src/libnt/native/cpp/NTDigitalInput.cpp index 96020edfc94..28b916cfbba 100644 --- a/glass/src/libnt/native/cpp/NTDigitalInput.cpp +++ b/glass/src/libnt/native/cpp/NTDigitalInput.cpp @@ -15,8 +15,8 @@ NTDigitalInputModel::NTDigitalInputModel(std::string_view path) NTDigitalInputModel::NTDigitalInputModel(nt::NetworkTableInstance inst, std::string_view path) : m_inst{inst}, - m_value{inst.GetBooleanTopic(fmt::format("{}/Value", path)) - .Subscribe(false, {{nt::PubSubOption::SendAll(true)}})}, + m_value{ + inst.GetBooleanTopic(fmt::format("{}/Value", path)).Subscribe(false)}, m_name{inst.GetStringTopic(fmt::format("{}/.name", path)).Subscribe("")}, m_valueData{fmt::format("NT_DIn:{}", path)}, m_nameValue{wpi::rsplit(path, '/').second} { diff --git a/glass/src/libnt/native/cpp/NTDigitalOutput.cpp b/glass/src/libnt/native/cpp/NTDigitalOutput.cpp index 13a7569c4fb..aa9200dc705 100644 --- a/glass/src/libnt/native/cpp/NTDigitalOutput.cpp +++ b/glass/src/libnt/native/cpp/NTDigitalOutput.cpp @@ -14,8 +14,8 @@ NTDigitalOutputModel::NTDigitalOutputModel(std::string_view path) NTDigitalOutputModel::NTDigitalOutputModel(nt::NetworkTableInstance inst, std::string_view path) : m_inst{inst}, - m_value{inst.GetBooleanTopic(fmt::format("{}/Value", path)) - .GetEntry(false, {{nt::PubSubOption::SendAll(true)}})}, + m_value{ + inst.GetBooleanTopic(fmt::format("{}/Value", path)).GetEntry(false)}, m_name{inst.GetStringTopic(fmt::format("{}/.name", path)).Subscribe("")}, m_controllable{inst.GetBooleanTopic(fmt::format("{}/.controllable", path)) .Subscribe(false)}, diff --git a/glass/src/libnt/native/cpp/NTFMS.cpp b/glass/src/libnt/native/cpp/NTFMS.cpp index 0c2ab8a977e..65ffa6a435f 100644 --- a/glass/src/libnt/native/cpp/NTFMS.cpp +++ b/glass/src/libnt/native/cpp/NTFMS.cpp @@ -21,11 +21,11 @@ NTFMSModel::NTFMSModel(nt::NetworkTableInstance inst, std::string_view path) inst.GetStringTopic(fmt::format("{}/GameSpecificMessage", path)) .Subscribe("")}, m_alliance{inst.GetBooleanTopic(fmt::format("{}/IsRedAlliance", path)) - .Subscribe(false, {{nt::PubSubOption::SendAll(true)}})}, + .Subscribe(false)}, m_station{inst.GetIntegerTopic(fmt::format("{}/StationNumber", path)) - .Subscribe(0, {{nt::PubSubOption::SendAll(true)}})}, + .Subscribe(0)}, m_controlWord{inst.GetIntegerTopic(fmt::format("{}/FMSControlData", path)) - .Subscribe(0, {{nt::PubSubOption::SendAll(true)}})}, + .Subscribe(0)}, m_fmsAttached{fmt::format("NT_FMS:FMSAttached:{}", path)}, m_dsAttached{fmt::format("NT_FMS:DSAttached:{}", path)}, m_allianceStationId{fmt::format("NT_FMS:AllianceStationID:{}", path)}, diff --git a/glass/src/libnt/native/cpp/NTField2D.cpp b/glass/src/libnt/native/cpp/NTField2D.cpp index d4bbdfff3a5..745e9e2b54c 100644 --- a/glass/src/libnt/native/cpp/NTField2D.cpp +++ b/glass/src/libnt/native/cpp/NTField2D.cpp @@ -112,10 +112,7 @@ NTField2DModel::NTField2DModel(nt::NetworkTableInstance inst, std::string_view path) : m_path{fmt::format("{}/", path)}, m_inst{inst}, - m_tableSub{inst, - {{m_path}}, - {{nt::PubSubOption::SendAll(true), - nt::PubSubOption::Periodic(0.05)}}}, + m_tableSub{inst, {{m_path}}, {.periodic = 0.05, .sendAll = true}}, m_nameTopic{inst.GetTopic(fmt::format("{}/.name", path))}, m_poller{inst} { m_poller.AddListener(m_tableSub, nt::EventFlags::kTopic | diff --git a/glass/src/libnt/native/cpp/NTGyro.cpp b/glass/src/libnt/native/cpp/NTGyro.cpp index 2717c558d9e..a036b39c53d 100644 --- a/glass/src/libnt/native/cpp/NTGyro.cpp +++ b/glass/src/libnt/native/cpp/NTGyro.cpp @@ -14,8 +14,7 @@ NTGyroModel::NTGyroModel(std::string_view path) NTGyroModel::NTGyroModel(nt::NetworkTableInstance inst, std::string_view path) : m_inst{inst}, - m_angle{inst.GetDoubleTopic(fmt::format("{}/Value", path)) - .Subscribe(0, {{nt::PubSubOption::SendAll(true)}})}, + m_angle{inst.GetDoubleTopic(fmt::format("{}/Value", path)).Subscribe(0)}, m_name{inst.GetStringTopic(fmt::format("{}/.name", path)).Subscribe({})}, m_angleData{fmt::format("NT_Gyro:{}", path)}, m_nameValue{wpi::rsplit(path, '/').second} {} diff --git a/glass/src/libnt/native/cpp/NTMecanumDrive.cpp b/glass/src/libnt/native/cpp/NTMecanumDrive.cpp index 4e0b769dd96..cb564e81689 100644 --- a/glass/src/libnt/native/cpp/NTMecanumDrive.cpp +++ b/glass/src/libnt/native/cpp/NTMecanumDrive.cpp @@ -22,16 +22,16 @@ NTMecanumDriveModel::NTMecanumDriveModel(nt::NetworkTableInstance inst, .Subscribe(0)}, m_flPercent{ inst.GetDoubleTopic(fmt::format("{}/Front Left Motor Speed", path)) - .GetEntry(0, {{nt::PubSubOption::SendAll(true)}})}, + .GetEntry(0)}, m_frPercent{ inst.GetDoubleTopic(fmt::format("{}/Front Right Motor Speed", path)) - .GetEntry(0, {{nt::PubSubOption::SendAll(true)}})}, + .GetEntry(0)}, m_rlPercent{ inst.GetDoubleTopic(fmt::format("{}/Rear Left Motor Speed", path)) - .GetEntry(0, {{nt::PubSubOption::SendAll(true)}})}, + .GetEntry(0)}, m_rrPercent{ inst.GetDoubleTopic(fmt::format("{}/Rear Right Motor Speed", path)) - .GetEntry(0, {{nt::PubSubOption::SendAll(true)}})}, + .GetEntry(0)}, m_nameValue{wpi::rsplit(path, '/').second}, m_flPercentData{fmt::format("NTMcnmDriveFL:{}", path)}, m_frPercentData{fmt::format("NTMcnmDriveFR:{}", path)}, diff --git a/glass/src/libnt/native/cpp/NTMechanism2D.cpp b/glass/src/libnt/native/cpp/NTMechanism2D.cpp index e931545a7c9..32ed276fe3a 100644 --- a/glass/src/libnt/native/cpp/NTMechanism2D.cpp +++ b/glass/src/libnt/native/cpp/NTMechanism2D.cpp @@ -240,10 +240,7 @@ NTMechanism2DModel::NTMechanism2DModel(nt::NetworkTableInstance inst, std::string_view path) : m_inst{inst}, m_path{fmt::format("{}/", path)}, - m_tableSub{inst, - {{m_path}}, - {{nt::PubSubOption::SendAll(true), - nt::PubSubOption::Periodic(0.05)}}}, + m_tableSub{inst, {{m_path}}, {.periodic = 0.05, .sendAll = true}}, m_nameTopic{m_inst.GetTopic(fmt::format("{}/.name", path))}, m_dimensionsTopic{m_inst.GetTopic(fmt::format("{}/dims", path))}, m_bgColorTopic{m_inst.GetTopic(fmt::format("{}/backgroundColor", path))}, diff --git a/glass/src/libnt/native/cpp/NTMotorController.cpp b/glass/src/libnt/native/cpp/NTMotorController.cpp index eb348efb853..1de6714fbf2 100644 --- a/glass/src/libnt/native/cpp/NTMotorController.cpp +++ b/glass/src/libnt/native/cpp/NTMotorController.cpp @@ -15,8 +15,7 @@ NTMotorControllerModel::NTMotorControllerModel(std::string_view path) NTMotorControllerModel::NTMotorControllerModel(nt::NetworkTableInstance inst, std::string_view path) : m_inst{inst}, - m_value{inst.GetDoubleTopic(fmt::format("{}/Value", path)) - .GetEntry(0, {{nt::PubSubOption::SendAll(true)}})}, + m_value{inst.GetDoubleTopic(fmt::format("{}/Value", path)).GetEntry(0)}, m_name{inst.GetStringTopic(fmt::format("{}/.name", path)).Subscribe("")}, m_controllable{inst.GetBooleanTopic(fmt::format("{}/.controllable", path)) .Subscribe(false)}, diff --git a/glass/src/libnt/native/cpp/NTPIDController.cpp b/glass/src/libnt/native/cpp/NTPIDController.cpp index 6102a1b451f..1dde27d6fdc 100644 --- a/glass/src/libnt/native/cpp/NTPIDController.cpp +++ b/glass/src/libnt/native/cpp/NTPIDController.cpp @@ -18,14 +18,11 @@ NTPIDControllerModel::NTPIDControllerModel(nt::NetworkTableInstance inst, m_name{inst.GetStringTopic(fmt::format("{}/.name", path)).Subscribe("")}, m_controllable{inst.GetBooleanTopic(fmt::format("{}/.controllable", path)) .Subscribe(false)}, - m_p{inst.GetDoubleTopic(fmt::format("{}/p", path)) - .GetEntry(0, {{nt::PubSubOption::SendAll(true)}})}, - m_i{inst.GetDoubleTopic(fmt::format("{}/i", path)) - .GetEntry(0, {{nt::PubSubOption::SendAll(true)}})}, - m_d{inst.GetDoubleTopic(fmt::format("{}/d", path)) - .GetEntry(0, {{nt::PubSubOption::SendAll(true)}})}, - m_setpoint{inst.GetDoubleTopic(fmt::format("{}/setpoint", path)) - .GetEntry(0, {{nt::PubSubOption::SendAll(true)}})}, + m_p{inst.GetDoubleTopic(fmt::format("{}/p", path)).GetEntry(0)}, + m_i{inst.GetDoubleTopic(fmt::format("{}/i", path)).GetEntry(0)}, + m_d{inst.GetDoubleTopic(fmt::format("{}/d", path)).GetEntry(0)}, + m_setpoint{ + inst.GetDoubleTopic(fmt::format("{}/setpoint", path)).GetEntry(0)}, m_pData{fmt::format("NTPIDCtrlP:{}", path)}, m_iData{fmt::format("NTPIDCtrlI:{}", path)}, m_dData{fmt::format("NTPIDCtrlD:{}", path)}, diff --git a/ntcore/src/dev/native/cpp/main.cpp b/ntcore/src/dev/native/cpp/main.cpp index 2ecc1c2393d..fac64e76bbc 100644 --- a/ntcore/src/dev/native/cpp/main.cpp +++ b/ntcore/src/dev/native/cpp/main.cpp @@ -63,8 +63,7 @@ void bench() { // add "typical" set of subscribers on client and server nt::SubscribeMultiple(client, {{std::string_view{}}}); nt::Subscribe(nt::GetTopic(client, "highrate"), NT_DOUBLE, "double", - {{nt::PubSubOption::KeepDuplicates(true), - nt::PubSubOption::SendAll(true)}}); + {.sendAll = true, .keepDuplicates = true}); nt::SubscribeMultiple(server, {{std::string_view{}}}); auto pub = nt::Publish(nt::GetTopic(server, "highrate"), NT_DOUBLE, "double"); nt::SetDouble(pub, 0); diff --git a/ntcore/src/generate/include/networktables/Topic.h.jinja b/ntcore/src/generate/include/networktables/Topic.h.jinja index 0b251e56884..84e80ec59b9 100644 --- a/ntcore/src/generate/include/networktables/Topic.h.jinja +++ b/ntcore/src/generate/include/networktables/Topic.h.jinja @@ -311,7 +311,7 @@ class {{ TypeName }}Topic final : public Topic { [[nodiscard]] SubscriberType Subscribe( {% if not TypeString %}std::string_view typeString, {% endif %}ParamType defaultValue, - std::span options = {}); + const PubSubOptions& options = kDefaultPubSubOptions); {%- if TypeString %} /** * Create a new subscriber to the topic, with specific type string. @@ -332,7 +332,7 @@ class {{ TypeName }}Topic final : public Topic { [[nodiscard]] SubscriberType SubscribeEx( std::string_view typeString, ParamType defaultValue, - std::span options = {}); + const PubSubOptions& options = kDefaultPubSubOptions); {% endif %} /** * Create a new publisher to the topic. @@ -353,7 +353,7 @@ class {{ TypeName }}Topic final : public Topic { * @return publisher */ [[nodiscard]] - PublisherType Publish({% if not TypeString %}std::string_view typeString, {% endif %}std::span options = {}); + PublisherType Publish({% if not TypeString %}std::string_view typeString, {% endif %}const PubSubOptions& options = kDefaultPubSubOptions); /** * Create a new publisher to the topic, with type string and initial @@ -375,7 +375,7 @@ class {{ TypeName }}Topic final : public Topic { */ [[nodiscard]] PublisherType PublishEx(std::string_view typeString, - const wpi::json& properties, std::span options = {}); + const wpi::json& properties, const PubSubOptions& options = kDefaultPubSubOptions); /** * Create a new entry for the topic. @@ -402,7 +402,7 @@ class {{ TypeName }}Topic final : public Topic { */ [[nodiscard]] EntryType GetEntry({% if not TypeString %}std::string_view typeString, {% endif %}ParamType defaultValue, - std::span options = {}); + const PubSubOptions& options = kDefaultPubSubOptions); {%- if TypeString %} /** * Create a new entry for the topic, with specific type string. @@ -427,7 +427,7 @@ class {{ TypeName }}Topic final : public Topic { */ [[nodiscard]] EntryType GetEntryEx(std::string_view typeString, ParamType defaultValue, - std::span options = {}); + const PubSubOptions& options = kDefaultPubSubOptions); {% endif %} }; diff --git a/ntcore/src/generate/include/networktables/Topic.inc.jinja b/ntcore/src/generate/include/networktables/Topic.inc.jinja index 17d250e5a0e..4e7a167d67c 100644 --- a/ntcore/src/generate/include/networktables/Topic.inc.jinja +++ b/ntcore/src/generate/include/networktables/Topic.inc.jinja @@ -89,7 +89,7 @@ inline void {{ TypeName }}Entry::Unpublish() { inline {{ TypeName }}Subscriber {{ TypeName }}Topic::Subscribe( {% if not TypeString %}std::string_view typeString, {% endif %}{{ cpp.ParamType }} defaultValue, - std::span options) { + const PubSubOptions& options) { return {{ TypeName }}Subscriber{ ::nt::Subscribe(m_handle, NT_{{ cpp.TYPE_NAME }}, {{ TypeString|default('typeString') }}, options), defaultValue}; @@ -97,28 +97,28 @@ inline {{ TypeName }}Subscriber {{ TypeName }}Topic::Subscribe( {%- if TypeString %} inline {{ TypeName }}Subscriber {{ TypeName }}Topic::SubscribeEx( std::string_view typeString, {{ cpp.ParamType }} defaultValue, - std::span options) { + const PubSubOptions& options) { return {{ TypeName }}Subscriber{ ::nt::Subscribe(m_handle, NT_{{ cpp.TYPE_NAME }}, typeString, options), defaultValue}; } {% endif %} inline {{ TypeName }}Publisher {{ TypeName }}Topic::Publish( - {% if not TypeString %}std::string_view typeString, {% endif %}std::span options) { + {% if not TypeString %}std::string_view typeString, {% endif %}const PubSubOptions& options) { return {{ TypeName }}Publisher{ ::nt::Publish(m_handle, NT_{{ cpp.TYPE_NAME }}, {{ TypeString|default('typeString') }}, options)}; } inline {{ TypeName }}Publisher {{ TypeName }}Topic::PublishEx( std::string_view typeString, - const wpi::json& properties, std::span options) { + const wpi::json& properties, const PubSubOptions& options) { return {{ TypeName }}Publisher{ ::nt::PublishEx(m_handle, NT_{{ cpp.TYPE_NAME }}, typeString, properties, options)}; } inline {{ TypeName }}Entry {{ TypeName }}Topic::GetEntry( {% if not TypeString %}std::string_view typeString, {% endif %}{{ cpp.ParamType }} defaultValue, - std::span options) { + const PubSubOptions& options) { return {{ TypeName }}Entry{ ::nt::GetEntry(m_handle, NT_{{ cpp.TYPE_NAME }}, {{ TypeString|default('typeString') }}, options), defaultValue}; @@ -126,7 +126,7 @@ inline {{ TypeName }}Entry {{ TypeName }}Topic::GetEntry( {%- if TypeString %} inline {{ TypeName }}Entry {{ TypeName }}Topic::GetEntryEx( std::string_view typeString, {{ cpp.ParamType }} defaultValue, - std::span options) { + const PubSubOptions& options) { return {{ TypeName }}Entry{ ::nt::GetEntry(m_handle, NT_{{ cpp.TYPE_NAME }}, typeString, options), defaultValue}; diff --git a/ntcore/src/generate/java/NetworkTablesJNI.java.jinja b/ntcore/src/generate/java/NetworkTablesJNI.java.jinja index 269c20a0984..41ba45e7d8c 100644 --- a/ntcore/src/generate/java/NetworkTablesJNI.java.jinja +++ b/ntcore/src/generate/java/NetworkTablesJNI.java.jinja @@ -57,20 +57,11 @@ public final class NetworkTablesJNI { libraryLoaded = true; } - private static int[] pubSubOptionTypes(PubSubOption... options) { - int[] rv = new int[options.length]; - for (int i = 0; i < options.length; i++) { - rv[i] = options[i].m_type; + private static PubSubOptions buildOptions(PubSubOption... options) { + if (options.length == 0) { + return null; // optimize common case (JNI checks for null) } - return rv; - } - - private static int[] pubSubOptionValues(PubSubOption... options) { - int[] rv = new int[options.length]; - for (int i = 0; i < options.length; i++) { - rv[i] = options[i].m_value; - } - return rv; + return new PubSubOptions(options); } public static native int getDefaultInstance(); @@ -81,13 +72,19 @@ public final class NetworkTablesJNI { public static native int getInstanceFromHandle(int handle); + private static native int getEntryImpl( + int topic, int type, String typeStr, PubSubOptions options); + public static native int getEntry(int inst, String key); - private static native int getEntry( - int topic, int type, String typeStr, int[] optionTypes, int[] optionValues); + public static int getEntry( + int topic, int type, String typeStr, PubSubOptions options) { + return getEntryImpl(topic, type, typeStr, options); + } - public static int getEntry(int topic, int type, String typeStr, PubSubOption... options) { - return getEntry(topic, type, typeStr, pubSubOptionTypes(options), pubSubOptionValues(options)); + public static int getEntry( + int topic, int type, String typeStr, PubSubOption... options) { + return getEntryImpl(topic, type, typeStr, buildOptions(options)); } public static native String getEntryName(int entry); @@ -136,27 +133,30 @@ public final class NetworkTablesJNI { public static native void setTopicProperties(int topic, String properties); - private static native int subscribe( - int topic, int type, String typeStr, int[] optionTypes, int[] optionValues); + public static native int subscribe( + int topic, int type, String typeStr, PubSubOptions options); - public static int subscribe(int topic, int type, String typeStr, PubSubOption... options) { - return subscribe(topic, type, typeStr, pubSubOptionTypes(options), pubSubOptionValues(options)); + public static int subscribe( + int topic, int type, String typeStr, PubSubOption... options) { + return subscribe(topic, type, typeStr, buildOptions(options)); } public static native void unsubscribe(int sub); - private static native int publish( - int topic, int type, String typeStr, int[] optionTypes, int[] optionValues); + public static native int publish( + int topic, int type, String typeStr, PubSubOptions options); - public static int publish(int topic, int type, String typeStr, PubSubOption... options) { - return publish(topic, type, typeStr, pubSubOptionTypes(options), pubSubOptionValues(options)); + public static int publish( + int topic, int type, String typeStr, PubSubOption... options) { + return publish(topic, type, typeStr, buildOptions(options)); } - private static native int publishEx( - int topic, int type, String typeStr, String properties, int[] optionTypes, int[] optionValues); + public static native int publishEx( + int topic, int type, String typeStr, String properties, PubSubOptions options); - public static int publishEx(int topic, int type, String typeStr, String properties, PubSubOption... options) { - return publishEx(topic, type, typeStr, properties, pubSubOptionTypes(options), pubSubOptionValues(options)); + public static int publishEx( + int topic, int type, String typeStr, String properties, PubSubOption... options) { + return publishEx(topic, type, typeStr, properties, buildOptions(options)); } public static native void unpublish(int pubentry); @@ -167,12 +167,10 @@ public final class NetworkTablesJNI { public static native int getTopicFromHandle(int pubsubentry); - private static native int subscribeMultiple( - int inst, String[] prefixes, int[] optionTypes, int[] optionValues); + public static native int subscribeMultiple(int inst, String[] prefixes, PubSubOptions options); public static int subscribeMultiple(int inst, String[] prefixes, PubSubOption... options) { - return subscribeMultiple( - inst, prefixes, pubSubOptionTypes(options), pubSubOptionValues(options)); + return subscribeMultiple(inst, prefixes, buildOptions(options)); } public static native void unsubscribeMultiple(int sub); diff --git a/ntcore/src/main/java/edu/wpi/first/networktables/PubSubOption.java b/ntcore/src/main/java/edu/wpi/first/networktables/PubSubOption.java index 00fa508d049..340418c0941 100644 --- a/ntcore/src/main/java/edu/wpi/first/networktables/PubSubOption.java +++ b/ntcore/src/main/java/edu/wpi/first/networktables/PubSubOption.java @@ -6,52 +6,69 @@ /** NetworkTables publish/subscribe option. */ public class PubSubOption { - private static final int kPeriodic = 1; - private static final int kSendAll = 2; - private static final int kTopicsOnly = 3; - private static final int kPollStorage = 4; - private static final int kKeepDuplicates = 5; - private static final int kLocalRemote = 6; - private static final int kExcludePub = 7; - private static final int kExcludeSelf = 8; - - PubSubOption(int type, int value) { - m_type = type; - m_value = value; + enum Kind { + periodic, + sendAll, + topicsOnly, + pollStorage, + keepDuplicates, + disableRemote, + disableLocal, + excludePublisher, + excludeSelf; + } + + PubSubOption(Kind kind, boolean value) { + m_kind = kind; + m_bValue = value; + m_iValue = 0; + m_dValue = 0; + } + + PubSubOption(Kind kind, int value) { + m_kind = kind; + m_bValue = false; + m_iValue = value; + m_dValue = 0; + } + + PubSubOption(Kind kind, double value) { + m_kind = kind; + m_bValue = false; + m_iValue = 0; + m_dValue = value; } /** * How frequently changes will be sent over the network. NetworkTables may send more frequently * than this (e.g. use a combined minimum period for all values) or apply a restricted range to - * this value. The default if unspecified (and the immediate flag is false) is 100 ms. This option - * and the immediate option override each other. + * this value. The default if unspecified is 100 ms. * * @param period time between updates, in seconds * @return option */ public static PubSubOption periodic(double period) { - return new PubSubOption(kPeriodic, (int) (period * 1000)); + return new PubSubOption(Kind.periodic, period); } /** - * If enabled, sends all value changes over the network even if only sent periodically. This - * option defaults to disabled. + * If enabled, sends all value changes over the network. This option defaults to disabled. * * @param enabled True to enable, false to disable * @return option */ public static PubSubOption sendAll(boolean enabled) { - return new PubSubOption(kSendAll, enabled ? 1 : 0); + return new PubSubOption(Kind.sendAll, enabled); } /** - * If enabled, no value changes are sent over the network. This option defaults to disabled. + * If enabled on a subscription, does not request value changes. This option defaults to disabled. * * @param enabled True to enable, false to disable * @return option */ public static PubSubOption topicsOnly(boolean enabled) { - return new PubSubOption(kTopicsOnly, enabled ? 1 : 0); + return new PubSubOption(Kind.topicsOnly, enabled); } /** @@ -62,7 +79,7 @@ public static PubSubOption topicsOnly(boolean enabled) { * @return option */ public static PubSubOption keepDuplicates(boolean enabled) { - return new PubSubOption(kKeepDuplicates, enabled ? 1 : 0); + return new PubSubOption(Kind.keepDuplicates, enabled); } /** @@ -74,37 +91,29 @@ public static PubSubOption keepDuplicates(boolean enabled) { * @return option */ public static PubSubOption pollStorage(int depth) { - return new PubSubOption(kPollStorage, depth); - } - - /** - * If only local value updates should be queued for readQueue(). See also remoteOnly() and - * allUpdates(). Default is allUpdates. Only has an effect on subscriptions. - * - * @return option - */ - public static PubSubOption localOnly() { - return new PubSubOption(kLocalRemote, 1); + return new PubSubOption(Kind.pollStorage, depth); } /** - * If only remote value updates should be queued for readQueue(). See also localOnly() and - * allUpdates(). Default is allUpdates. Only has an effect on subscriptions. + * For subscriptions, specify whether remote value updates should not be queued for readQueue(). + * See also disableLocal(). Defaults to false (remote value updates are queued). * + * @param disabled True to disable, false to enable * @return option */ - public static PubSubOption remoteOnly() { - return new PubSubOption(kLocalRemote, 2); + public static PubSubOption disableRemote(boolean disabled) { + return new PubSubOption(Kind.disableRemote, disabled); } /** - * If both local and remote value updates should be queued for readQueue(). See also localOnly() - * and remoteOnly(). Default is allUpdates. Only has an effect on subscriptions. + * For subscriptions, specify whether local value updates should not be queued for readQueue(). + * See alse disableRemote(). Defaults to false (local value updates are queued). * + * @param disabled True to disable, false to enable * @return option */ - public static PubSubOption allUpdates() { - return new PubSubOption(kLocalRemote, 0); + public static PubSubOption disableLocal(boolean disabled) { + return new PubSubOption(Kind.disableLocal, disabled); } /** @@ -115,7 +124,7 @@ public static PubSubOption allUpdates() { * @return option */ public static PubSubOption excludePublisher(int publisher) { - return new PubSubOption(kExcludePub, publisher); + return new PubSubOption(Kind.excludePublisher, publisher); } /** @@ -126,7 +135,7 @@ public static PubSubOption excludePublisher(int publisher) { * @return option */ public static PubSubOption excludePublisher(Publisher publisher) { - return new PubSubOption(kExcludePub, publisher != null ? publisher.getHandle() : 0); + return excludePublisher(publisher != null ? publisher.getHandle() : 0); } /** @@ -137,9 +146,11 @@ public static PubSubOption excludePublisher(Publisher publisher) { * @return option */ public static PubSubOption excludeSelf(boolean enabled) { - return new PubSubOption(kExcludeSelf, enabled ? 1 : 0); + return new PubSubOption(Kind.excludeSelf, enabled); } - final int m_type; - final int m_value; + final Kind m_kind; + final boolean m_bValue; + final int m_iValue; + final double m_dValue; } diff --git a/ntcore/src/main/java/edu/wpi/first/networktables/PubSubOptions.java b/ntcore/src/main/java/edu/wpi/first/networktables/PubSubOptions.java new file mode 100644 index 00000000000..18557b93db4 --- /dev/null +++ b/ntcore/src/main/java/edu/wpi/first/networktables/PubSubOptions.java @@ -0,0 +1,126 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package edu.wpi.first.networktables; + +/** NetworkTables publish/subscribe options. */ +@SuppressWarnings("MemberName") +public class PubSubOptions { + /** + * Construct from a list of options. + * + * @param options options + */ + public PubSubOptions(PubSubOption... options) { + for (PubSubOption option : options) { + switch (option.m_kind) { + case periodic: + periodic = option.m_dValue; + break; + case sendAll: + sendAll = option.m_bValue; + break; + case topicsOnly: + topicsOnly = option.m_bValue; + break; + case pollStorage: + pollStorage = option.m_iValue; + break; + case keepDuplicates: + keepDuplicates = option.m_bValue; + break; + case disableRemote: + disableRemote = option.m_bValue; + break; + case disableLocal: + disableLocal = option.m_bValue; + break; + case excludePublisher: + excludePublisher = option.m_iValue; + break; + case excludeSelf: + excludeSelf = option.m_bValue; + break; + default: + break; + } + } + } + + PubSubOptions( + int pollStorage, + double periodic, + int excludePublisher, + boolean sendAll, + boolean topicsOnly, + boolean keepDuplicates, + boolean prefixMatch, + boolean disableRemote, + boolean disableLocal, + boolean excludeSelf) { + this.pollStorage = pollStorage; + this.periodic = periodic; + this.excludePublisher = excludePublisher; + this.sendAll = sendAll; + this.topicsOnly = topicsOnly; + this.keepDuplicates = keepDuplicates; + this.prefixMatch = prefixMatch; + this.disableRemote = disableRemote; + this.disableLocal = disableLocal; + this.excludeSelf = excludeSelf; + } + + /** Default value of periodic. */ + public static final double kDefaultPeriodic = 0.1; + + /** + * Polling storage size for a subscription. Specifies the maximum number of updates NetworkTables + * should store between calls to the subscriber's readQueue() function. If zero, defaults to 1 if + * sendAll is false, 20 if sendAll is true. + */ + public int pollStorage; + + /** + * How frequently changes will be sent over the network, in seconds. NetworkTables may send more + * frequently than this (e.g. use a combined minimum period for all values) or apply a restricted + * range to this value. The default is 100 ms. + */ + public double periodic = kDefaultPeriodic; + + /** + * For subscriptions, if non-zero, value updates for readQueue() are not queued for this + * publisher. + */ + public int excludePublisher; + + /** Send all value changes over the network. */ + public boolean sendAll; + + /** For subscriptions, don't ask for value changes (only topic announcements). */ + public boolean topicsOnly; + + /** Preserve duplicate value changes (rather than ignoring them). */ + public boolean keepDuplicates; + + /** + * Perform prefix match on subscriber topic names. Is ignored/overridden by subscribe() functions; + * only present in struct for the purposes of getting information about subscriptions. + */ + public boolean prefixMatch; + + /** + * For subscriptions, if remote value updates should not be queued for readQueue(). See also + * disableLocal. + */ + public boolean disableRemote; + + /** + * For subscriptions, if local value updates should not be queued for readQueue(). See also + * disableRemote. + */ + public boolean disableLocal; + + /** For entries, don't queue (for readQueue) value updates for the entry's internal publisher. */ + public boolean excludeSelf; +} diff --git a/ntcore/src/main/native/cpp/LocalStorage.cpp b/ntcore/src/main/native/cpp/LocalStorage.cpp index 6325900c15a..d0cb335bc92 100644 --- a/ntcore/src/main/native/cpp/LocalStorage.cpp +++ b/ntcore/src/main/native/cpp/LocalStorage.cpp @@ -107,11 +107,13 @@ struct TopicData { VectorSet listeners; }; -struct PubSubConfig : public PubSubOptions { +struct PubSubConfig : public PubSubOptionsImpl { PubSubConfig() = default; PubSubConfig(NT_Type type, std::string_view typeStr, - std::span options) - : PubSubOptions{options}, type{type}, typeStr{typeStr} {} + const PubSubOptions& options) + : PubSubOptionsImpl{options}, type{type}, typeStr{typeStr} { + prefixMatch = false; + } NT_Type type{NT_UNASSIGNED}; std::string typeStr; @@ -141,7 +143,7 @@ struct SubscriberData { : handle{handle}, topic{topic}, config{std::move(config)}, - pollStorage{config.pollStorageSize} {} + pollStorage{config.pollStorage} {} void UpdateActive(); @@ -180,8 +182,8 @@ struct MultiSubscriberData { MultiSubscriberData(NT_MultiSubscriber handle, std::span prefixes, - PubSubOptions options) - : handle{handle}, options{std::move(options)} { + const PubSubOptionsImpl& options) + : handle{handle}, options{options} { this->options.prefixMatch = true; this->prefixes.reserve(prefixes.size()); for (auto&& prefix : prefixes) { @@ -194,7 +196,7 @@ struct MultiSubscriberData { // invariants wpi::SignalObject handle; std::vector prefixes; - PubSubOptions options; + PubSubOptionsImpl options; // value listeners VectorSet valueListeners; @@ -517,10 +519,10 @@ void LSImpl::NotifyValue(TopicData* topic, unsigned int eventFlags, for (auto&& subscriber : topic->localSubscribers) { if (subscriber->active && (subscriber->config.keepDuplicates || !isDuplicate) && - ((isNetwork && subscriber->config.fromRemote) || - (!isNetwork && subscriber->config.fromLocal)) && - (!publisher || - (publisher && (subscriber->config.excludePub != publisher->handle)))) { + ((isNetwork && !subscriber->config.disableRemote) || + (!isNetwork && !subscriber->config.disableLocal)) && + (!publisher || (publisher && (subscriber->config.excludePublisher != + publisher->handle)))) { subscriber->pollStorage.emplace_back(topic->lastValue); subscriber->handle.Set(); if (!subscriber->valueListeners.empty()) { @@ -1090,10 +1092,8 @@ void LSImpl::AddListener(NT_Listener listenerHandle, return; } // subscribe to make sure topic updates are received - PubSubOptions options; - options.topicsOnly = (eventMask & NT_EVENT_VALUE_ALL) == 0; - options.prefixMatch = true; - auto sub = AddMultiSubscriber(prefixes, options); + auto sub = AddMultiSubscriber( + prefixes, {.topicsOnly = (eventMask & NT_EVENT_VALUE_ALL) == 0}); AddListenerImpl(listenerHandle, sub, eventMask, true); } @@ -1266,7 +1266,7 @@ bool LSImpl::SetEntryValue(NT_Handle pubentryHandle, const Value& value) { if (auto entry = m_entries.Get(pubentryHandle)) { publisher = PublishEntry(entry, value.type()); if (entry->subscriber->config.excludeSelf) { - entry->subscriber->config.excludePub = publisher->handle; + entry->subscriber->config.excludePublisher = publisher->handle; } } if (!publisher) { @@ -1642,7 +1642,7 @@ TopicInfo LocalStorage::GetTopicInfo(NT_Topic topicHandle) { NT_Subscriber LocalStorage::Subscribe(NT_Topic topicHandle, NT_Type type, std::string_view typeStr, - std::span options) { + const PubSubOptions& options) { std::scoped_lock lock{m_mutex}; // Get the topic @@ -1669,8 +1669,7 @@ void LocalStorage::Unsubscribe(NT_Subscriber subHandle) { } NT_MultiSubscriber LocalStorage::SubscribeMultiple( - std::span prefixes, - std::span options) { + std::span prefixes, const PubSubOptions& options) { std::scoped_lock lock{m_mutex}; if (m_impl->m_multiSubscribers.size() >= kMaxMultiSubscribers) { @@ -1679,9 +1678,7 @@ NT_MultiSubscriber LocalStorage::SubscribeMultiple( return 0; } - PubSubOptions opts{options}; - opts.prefixMatch = true; - return m_impl->AddMultiSubscriber(prefixes, opts)->handle; + return m_impl->AddMultiSubscriber(prefixes, options)->handle; } void LocalStorage::UnsubscribeMultiple(NT_MultiSubscriber subHandle) { @@ -1692,7 +1689,7 @@ void LocalStorage::UnsubscribeMultiple(NT_MultiSubscriber subHandle) { NT_Publisher LocalStorage::Publish(NT_Topic topicHandle, NT_Type type, std::string_view typeStr, const wpi::json& properties, - std::span options) { + const PubSubOptions& options) { std::scoped_lock lock{m_mutex}; // Get the topic @@ -1742,7 +1739,7 @@ void LocalStorage::Unpublish(NT_Handle pubentryHandle) { NT_Entry LocalStorage::GetEntry(NT_Topic topicHandle, NT_Type type, std::string_view typeStr, - std::span options) { + const PubSubOptions& options) { std::scoped_lock lock{m_mutex}; // Get the topic diff --git a/ntcore/src/main/native/cpp/LocalStorage.h b/ntcore/src/main/native/cpp/LocalStorage.h index 8205da3f018..58644908f91 100644 --- a/ntcore/src/main/native/cpp/LocalStorage.h +++ b/ntcore/src/main/native/cpp/LocalStorage.h @@ -93,24 +93,23 @@ class LocalStorage final : public net::ILocalStorage { NT_Subscriber Subscribe(NT_Topic topic, NT_Type type, std::string_view typeStr, - std::span options); + const PubSubOptions& options); void Unsubscribe(NT_Subscriber sub); NT_MultiSubscriber SubscribeMultiple( - std::span prefixes, - std::span options); + std::span prefixes, const PubSubOptions& options); void UnsubscribeMultiple(NT_MultiSubscriber subHandle); NT_Publisher Publish(NT_Topic topic, NT_Type type, std::string_view typeStr, const wpi::json& properties, - std::span options); + const PubSubOptions& options); void Unpublish(NT_Handle pubentry); NT_Entry GetEntry(NT_Topic topic, NT_Type type, std::string_view typeStr, - std::span options); + const PubSubOptions& options); void ReleaseEntry(NT_Entry entry); diff --git a/ntcore/src/main/native/cpp/PubSubOptions.cpp b/ntcore/src/main/native/cpp/PubSubOptions.cpp deleted file mode 100644 index 92be2c26c8c..00000000000 --- a/ntcore/src/main/native/cpp/PubSubOptions.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) FIRST and other WPILib contributors. -// Open Source Software; you can modify and/or share it under the terms of -// the WPILib BSD license file in the root directory of this project. - -#include "PubSubOptions.h" - -#include "ntcore_c.h" -#include "ntcore_cpp.h" - -using namespace nt; - -nt::PubSubOptions::PubSubOptions(std::span options) { - for (auto&& option : options) { - switch (option.type) { - case NT_PUBSUB_PERIODIC: - periodicMs = option.value; - break; - case NT_PUBSUB_SENDALL: - sendAll = option.value != 0; - if (sendAll) { - pollStorageSize = 20; - } - break; - case NT_PUBSUB_TOPICSONLY: - topicsOnly = option.value != 0; - break; - case NT_PUBSUB_KEEPDUPLICATES: - keepDuplicates = option.value != 0; - break; - case NT_PUBSUB_POLLSTORAGE: - pollStorageSize = static_cast(option.value); - break; - case NT_PUBSUB_LOCALREMOTE: - switch (static_cast(option.value)) { - case 0: - case 3: - fromLocal = true; - fromRemote = true; - break; - case 1: - fromLocal = true; - fromRemote = false; - break; - case 2: - fromLocal = false; - fromRemote = true; - break; - default: - break; - } - break; - case NT_PUBSUB_EXCLUDEPUB: - excludePub = option.value; - break; - case NT_PUBSUB_EXCLUDESELF: - excludeSelf = option.value != 0; - break; - default: - break; - } - } -} diff --git a/ntcore/src/main/native/cpp/PubSubOptions.h b/ntcore/src/main/native/cpp/PubSubOptions.h index 35e97a40874..72ba2c3ed2c 100644 --- a/ntcore/src/main/native/cpp/PubSubOptions.h +++ b/ntcore/src/main/native/cpp/PubSubOptions.h @@ -4,30 +4,33 @@ #pragma once -#include - #include "ntcore_cpp.h" namespace nt { -// options built from array of PubSubOption -class PubSubOptions { +// internal helper class for PubSubOptions +class PubSubOptionsImpl : public PubSubOptions { public: - PubSubOptions() = default; - explicit PubSubOptions(std::span options); + constexpr PubSubOptionsImpl() : PubSubOptionsImpl{kDefaultPubSubOptions} {} + + /*implicit*/ constexpr PubSubOptionsImpl( // NOLINT + const PubSubOptions& options) + : PubSubOptions{options} { + if (periodic == 0) { + periodic = kDefaultPeriodic; + } + periodicMs = static_cast(periodic * 1000); + if (pollStorage == 0) { + if (sendAll) { + pollStorage = 20; + } else { + pollStorage = 1; + } + } + } static constexpr unsigned int kDefaultPeriodicMs = 100; - unsigned int periodicMs = kDefaultPeriodicMs; - size_t pollStorageSize = 1; - bool sendAll = false; - bool topicsOnly = false; - bool prefixMatch = false; - bool keepDuplicates = false; - bool fromRemote = true; - bool fromLocal = true; - unsigned int excludePub = 0; - bool excludeSelf = false; }; } // namespace nt diff --git a/ntcore/src/main/native/cpp/jni/NetworkTablesJNI.cpp b/ntcore/src/main/native/cpp/jni/NetworkTablesJNI.cpp index f072bcd706b..a1a1bf652c5 100644 --- a/ntcore/src/main/native/cpp/jni/NetworkTablesJNI.cpp +++ b/ntcore/src/main/native/cpp/jni/NetworkTablesJNI.cpp @@ -39,6 +39,7 @@ static JClass eventCls; static JClass floatCls; static JClass logMessageCls; static JClass longCls; +static JClass pubSubOptionsCls; static JClass topicInfoCls; static JClass valueCls; static JClass valueEventDataCls; @@ -54,6 +55,7 @@ static const JClassInit classes[] = { {"java/lang/Float", &floatCls}, {"edu/wpi/first/networktables/LogMessage", &logMessageCls}, {"java/lang/Long", &longCls}, + {"edu/wpi/first/networktables/PubSubOptions", &pubSubOptionsCls}, {"edu/wpi/first/networktables/TopicInfo", &topicInfoCls}, {"edu/wpi/first/networktables/NetworkTableValue", &valueCls}, {"edu/wpi/first/networktables/ValueEventData", &valueEventDataCls}}; @@ -117,20 +119,45 @@ JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) { // Conversions from Java objects to C++ // -static std::span FromJavaPubSubOptions( - JNIEnv* env, jintArray optionTypes, jintArray optionValues, - wpi::SmallVectorImpl& arr) { - JIntArrayRef types{env, optionTypes}; - JIntArrayRef values{env, optionValues}; - if (types.size() != values.size()) { +static nt::PubSubOptions FromJavaPubSubOptions(JNIEnv* env, jobject joptions) { + if (!joptions) { return {}; } - arr.clear(); - arr.reserve(types.size()); - for (size_t i = 0, iend = types.size(); i != iend; ++i) { - arr.emplace_back(static_cast(types[i]), values[i]); +#define FIELD(name, sig) \ + static jfieldID name##Field = nullptr; \ + if (!name##Field) { \ + name##Field = env->GetFieldID(pubSubOptionsCls, #name, sig); \ } - return arr; + + FIELD(pollStorage, "I"); + FIELD(periodic, "D"); + FIELD(excludePublisher, "I"); + FIELD(sendAll, "Z"); + FIELD(topicsOnly, "Z"); + FIELD(keepDuplicates, "Z"); + FIELD(prefixMatch, "Z"); + FIELD(disableRemote, "Z"); + FIELD(disableLocal, "Z"); + FIELD(excludeSelf, "Z"); + +#undef FIELD + +#define FIELD(ctype, jtype, name) \ + .name = static_cast(env->Get##jtype##Field(joptions, name##Field)) + + return {FIELD(unsigned int, Int, pollStorage), + FIELD(double, Double, periodic), + FIELD(NT_Publisher, Int, excludePublisher), + FIELD(bool, Boolean, sendAll), + FIELD(bool, Boolean, topicsOnly), + FIELD(bool, Boolean, keepDuplicates), + FIELD(bool, Boolean, prefixMatch), + FIELD(bool, Boolean, disableRemote), + FIELD(bool, Boolean, disableLocal), + FIELD(bool, Boolean, excludeSelf)}; + +#undef GET +#undef FIELD } // @@ -356,7 +383,7 @@ Java_edu_wpi_first_networktables_NetworkTablesJNI_getInstanceFromHandle * Signature: (ILjava/lang/String;)I */ JNIEXPORT jint JNICALL -Java_edu_wpi_first_networktables_NetworkTablesJNI_getEntry__ILjava_lang_String_2 +Java_edu_wpi_first_networktables_NetworkTablesJNI_getEntry (JNIEnv* env, jclass, jint inst, jstring key) { if (!key) { @@ -720,17 +747,15 @@ Java_edu_wpi_first_networktables_NetworkTablesJNI_setTopicProperties /* * Class: edu_wpi_first_networktables_NetworkTablesJNI * Method: subscribe - * Signature: (IILjava/lang/String;[I[I)I + * Signature: (IILjava/lang/String;Ljava/lang/Object;)I */ JNIEXPORT jint JNICALL Java_edu_wpi_first_networktables_NetworkTablesJNI_subscribe - (JNIEnv* env, jclass, jint topic, jint type, jstring typeStr, - jintArray optionTypes, jintArray optionValues) + (JNIEnv* env, jclass, jint topic, jint type, jstring typeStr, jobject options) { - wpi::SmallVector options; - return nt::Subscribe( - topic, static_cast(type), JStringRef{env, typeStr}, - FromJavaPubSubOptions(env, optionTypes, optionValues, options)); + return nt::Subscribe(topic, static_cast(type), + JStringRef{env, typeStr}, + FromJavaPubSubOptions(env, options)); } /* @@ -748,28 +773,26 @@ Java_edu_wpi_first_networktables_NetworkTablesJNI_unsubscribe /* * Class: edu_wpi_first_networktables_NetworkTablesJNI * Method: publish - * Signature: (IILjava/lang/String;[I[I)I + * Signature: (IILjava/lang/String;Ljava/lang/Object;)I */ JNIEXPORT jint JNICALL Java_edu_wpi_first_networktables_NetworkTablesJNI_publish - (JNIEnv* env, jclass, jint topic, jint type, jstring typeStr, - jintArray optionTypes, jintArray optionValues) + (JNIEnv* env, jclass, jint topic, jint type, jstring typeStr, jobject options) { - wpi::SmallVector options; - return nt::Publish( - topic, static_cast(type), JStringRef{env, typeStr}, - FromJavaPubSubOptions(env, optionTypes, optionValues, options)); + return nt::Publish(topic, static_cast(type), + JStringRef{env, typeStr}, + FromJavaPubSubOptions(env, options)); } /* * Class: edu_wpi_first_networktables_NetworkTablesJNI * Method: publishEx - * Signature: (IILjava/lang/String;Ljava/lang/String;[I[I)I + * Signature: (IILjava/lang/String;Ljava/lang/String;Ljava/lang/Object;)I */ JNIEXPORT jint JNICALL Java_edu_wpi_first_networktables_NetworkTablesJNI_publishEx (JNIEnv* env, jclass, jint topic, jint type, jstring typeStr, - jstring properties, jintArray optionTypes, jintArray optionValues) + jstring properties, jobject options) { wpi::json j; try { @@ -783,10 +806,9 @@ Java_edu_wpi_first_networktables_NetworkTablesJNI_publishEx illegalArgEx.Throw(env, "properties is not a JSON object"); return 0; } - wpi::SmallVector options; - return nt::PublishEx( - topic, static_cast(type), JStringRef{env, typeStr}, j, - FromJavaPubSubOptions(env, optionTypes, optionValues, options)); + return nt::PublishEx(topic, static_cast(type), + JStringRef{env, typeStr}, j, + FromJavaPubSubOptions(env, options)); } /* @@ -803,18 +825,16 @@ Java_edu_wpi_first_networktables_NetworkTablesJNI_unpublish /* * Class: edu_wpi_first_networktables_NetworkTablesJNI - * Method: getEntry - * Signature: (IILjava/lang/String;[I[I)I + * Method: getEntryImpl + * Signature: (IILjava/lang/String;Ljava/lang/Object;)I */ JNIEXPORT jint JNICALL -Java_edu_wpi_first_networktables_NetworkTablesJNI_getEntry__IILjava_lang_String_2_3I_3I - (JNIEnv* env, jclass, jint topic, jint type, jstring typeStr, - jintArray optionTypes, jintArray optionValues) +Java_edu_wpi_first_networktables_NetworkTablesJNI_getEntryImpl + (JNIEnv* env, jclass, jint topic, jint type, jstring typeStr, jobject options) { - wpi::SmallVector options; - return nt::GetEntry( - topic, static_cast(type), JStringRef{env, typeStr}, - FromJavaPubSubOptions(env, optionTypes, optionValues, options)); + return nt::GetEntry(topic, static_cast(type), + JStringRef{env, typeStr}, + FromJavaPubSubOptions(env, options)); } /* @@ -856,12 +876,11 @@ Java_edu_wpi_first_networktables_NetworkTablesJNI_getTopicFromHandle /* * Class: edu_wpi_first_networktables_NetworkTablesJNI * Method: subscribeMultiple - * Signature: (I[Ljava/lang/Object;[I[I)I + * Signature: (I[Ljava/lang/Object;Ljava/lang/Object;)I */ JNIEXPORT jint JNICALL Java_edu_wpi_first_networktables_NetworkTablesJNI_subscribeMultiple - (JNIEnv* env, jclass, jint inst, jobjectArray prefixes, jintArray optionTypes, - jintArray optionValues) + (JNIEnv* env, jclass, jint inst, jobjectArray prefixes, jobject options) { if (!prefixes) { nullPointerEx.Throw(env, "prefixes cannot be null"); @@ -884,10 +903,8 @@ Java_edu_wpi_first_networktables_NetworkTablesJNI_subscribeMultiple prefixStringViews.emplace_back(prefixStrings.back()); } - wpi::SmallVector options; - return nt::SubscribeMultiple( - inst, prefixStringViews, - FromJavaPubSubOptions(env, optionTypes, optionValues, options)); + return nt::SubscribeMultiple(inst, prefixStringViews, + FromJavaPubSubOptions(env, options)); } /* diff --git a/ntcore/src/main/native/cpp/net/ClientImpl.cpp b/ntcore/src/main/native/cpp/net/ClientImpl.cpp index 6a9a68fdd04..b606b3827b9 100644 --- a/ntcore/src/main/native/cpp/net/ClientImpl.cpp +++ b/ntcore/src/main/native/cpp/net/ClientImpl.cpp @@ -38,7 +38,7 @@ namespace { struct PublisherData { NT_Publisher handle; - PubSubOptions options; + PubSubOptionsImpl options; // in options as double, but copy here as integer; rounded to the nearest // 10 ms uint32_t periodMs; @@ -67,7 +67,7 @@ class CImpl : public ServerMessageHandler { void Publish(NT_Publisher pubHandle, NT_Topic topicHandle, std::string_view name, std::string_view typeStr, - const wpi::json& properties, const PubSubOptions& options); + const wpi::json& properties, const PubSubOptionsImpl& options); bool Unpublish(NT_Publisher pubHandle, NT_Topic topicHandle); void SetValue(NT_Publisher pubHandle, const Value& value); @@ -282,7 +282,8 @@ bool CImpl::CheckNetworkReady() { void CImpl::Publish(NT_Publisher pubHandle, NT_Topic topicHandle, std::string_view name, std::string_view typeStr, - const wpi::json& properties, const PubSubOptions& options) { + const wpi::json& properties, + const PubSubOptionsImpl& options) { unsigned int index = Handle{pubHandle}.GetIndex(); if (index >= m_publishers.size()) { m_publishers.resize(index + 1); @@ -445,7 +446,7 @@ ClientStartup::~ClientStartup() { void ClientStartup::Publish(NT_Publisher pubHandle, NT_Topic topicHandle, std::string_view name, std::string_view typeStr, const wpi::json& properties, - const PubSubOptions& options) { + const PubSubOptionsImpl& options) { WPI_DEBUG4(m_client.m_impl->m_logger, "StartupPublish({}, {}, {}, {})", pubHandle, topicHandle, name, typeStr); m_client.m_impl->Publish(pubHandle, topicHandle, name, typeStr, properties, @@ -456,7 +457,7 @@ void ClientStartup::Publish(NT_Publisher pubHandle, NT_Topic topicHandle, void ClientStartup::Subscribe(NT_Subscriber subHandle, std::span prefixes, - const PubSubOptions& options) { + const PubSubOptionsImpl& options) { WPI_DEBUG4(m_client.m_impl->m_logger, "StartupSubscribe({})", subHandle); WireEncodeSubscribe(m_textWriter.Add(), Handle{subHandle}.GetIndex(), prefixes, options); diff --git a/ntcore/src/main/native/cpp/net/ClientImpl.h b/ntcore/src/main/native/cpp/net/ClientImpl.h index a429a2edf63..ae9a2f978b6 100644 --- a/ntcore/src/main/native/cpp/net/ClientImpl.h +++ b/ntcore/src/main/native/cpp/net/ClientImpl.h @@ -21,7 +21,7 @@ class Logger; } // namespace wpi namespace nt { -class PubSubOptions; +class PubSubOptionsImpl; class Value; } // namespace nt @@ -64,9 +64,10 @@ class ClientStartup final : public NetworkStartupInterface { // NetworkStartupInterface interface void Publish(NT_Publisher pubHandle, NT_Topic topicHandle, std::string_view name, std::string_view typeStr, - const wpi::json& properties, const PubSubOptions& options) final; + const wpi::json& properties, + const PubSubOptionsImpl& options) final; void Subscribe(NT_Subscriber subHandle, std::span prefixes, - const PubSubOptions& options) final; + const PubSubOptionsImpl& options) final; void SetValue(NT_Publisher pubHandle, const Value& value) final; private: diff --git a/ntcore/src/main/native/cpp/net/Message.h b/ntcore/src/main/native/cpp/net/Message.h index 1cec920e606..a95c5e8f6ef 100644 --- a/ntcore/src/main/native/cpp/net/Message.h +++ b/ntcore/src/main/native/cpp/net/Message.h @@ -24,7 +24,7 @@ struct PublishMsg { std::string name; std::string typeStr; wpi::json properties; - PubSubOptions options; // will be empty when coming from network + PubSubOptionsImpl options; // will be empty when coming from network }; struct UnpublishMsg { @@ -44,7 +44,7 @@ struct SubscribeMsg { static constexpr std::string_view kMethodStr = "subscribe"; NT_Subscriber subHandle{0}; std::vector topicNames; - PubSubOptions options; + PubSubOptionsImpl options; }; struct UnsubscribeMsg { diff --git a/ntcore/src/main/native/cpp/net/NetworkInterface.h b/ntcore/src/main/native/cpp/net/NetworkInterface.h index 0a6f47c5535..0ef60335d7b 100644 --- a/ntcore/src/main/native/cpp/net/NetworkInterface.h +++ b/ntcore/src/main/native/cpp/net/NetworkInterface.h @@ -15,7 +15,7 @@ class json; } // namespace wpi namespace nt { -class PubSubOptions; +class PubSubOptionsImpl; class Value; } // namespace nt @@ -42,10 +42,10 @@ class NetworkStartupInterface { virtual void Publish(NT_Publisher pubHandle, NT_Topic topicHandle, std::string_view name, std::string_view typeStr, const wpi::json& properties, - const PubSubOptions& options) = 0; + const PubSubOptionsImpl& options) = 0; virtual void Subscribe(NT_Subscriber subHandle, std::span topicNames, - const PubSubOptions& options) = 0; + const PubSubOptionsImpl& options) = 0; virtual void SetValue(NT_Publisher pubHandle, const Value& value) = 0; }; diff --git a/ntcore/src/main/native/cpp/net/NetworkLoopQueue.h b/ntcore/src/main/native/cpp/net/NetworkLoopQueue.h index 3ff3324bcd2..6ab68b6a7cc 100644 --- a/ntcore/src/main/native/cpp/net/NetworkLoopQueue.h +++ b/ntcore/src/main/native/cpp/net/NetworkLoopQueue.h @@ -33,13 +33,14 @@ class NetworkLoopQueue : public NetworkInterface { // NetworkInterface - calls to these append to the queue void Publish(NT_Publisher pubHandle, NT_Topic topicHandle, std::string_view name, std::string_view typeStr, - const wpi::json& properties, const PubSubOptions& options) final; + const wpi::json& properties, + const PubSubOptionsImpl& options) final; void Unpublish(NT_Publisher pubHandle, NT_Topic topicHandle) final; void SetProperties(NT_Topic topicHandle, std::string_view name, const wpi::json& update) final; void Subscribe(NT_Subscriber subHandle, std::span topicNames, - const PubSubOptions& options) final; + const PubSubOptionsImpl& options) final; void Unsubscribe(NT_Subscriber subHandle) final; void SetValue(NT_Publisher pubHandle, const Value& value) final; diff --git a/ntcore/src/main/native/cpp/net/NetworkLoopQueue.inc b/ntcore/src/main/native/cpp/net/NetworkLoopQueue.inc index 1f039ad39a9..a441780658b 100644 --- a/ntcore/src/main/native/cpp/net/NetworkLoopQueue.inc +++ b/ntcore/src/main/native/cpp/net/NetworkLoopQueue.inc @@ -34,7 +34,7 @@ inline void NetworkLoopQueue::Publish(NT_Publisher pubHandle, std::string_view name, std::string_view typeStr, const wpi::json& properties, - const PubSubOptions& options) { + const PubSubOptionsImpl& options) { std::scoped_lock lock{m_mutex}; m_queue.emplace_back( ClientMessage{PublishMsg{pubHandle, topicHandle, std::string{name}, @@ -57,7 +57,7 @@ inline void NetworkLoopQueue::SetProperties(NT_Topic topicHandle, inline void NetworkLoopQueue::Subscribe(NT_Subscriber subHandle, std::span topicNames, - const PubSubOptions& options) { + const PubSubOptionsImpl& options) { std::scoped_lock lock{m_mutex}; m_queue.emplace_back(ClientMessage{SubscribeMsg{ subHandle, {topicNames.begin(), topicNames.end()}, options}}); diff --git a/ntcore/src/main/native/cpp/net/ServerImpl.cpp b/ntcore/src/main/native/cpp/net/ServerImpl.cpp index 98ebdc73229..60c7d4f7006 100644 --- a/ntcore/src/main/native/cpp/net/ServerImpl.cpp +++ b/ntcore/src/main/native/cpp/net/ServerImpl.cpp @@ -159,7 +159,7 @@ class ClientData4Base : public ClientData, protected ClientMessageHandler { void ClientSetProperties(std::string_view name, const wpi::json& update) final; void ClientSubscribe(int64_t subuid, std::span topicNames, - const PubSubOptions& options) final; + const PubSubOptionsImpl& options) final; void ClientUnsubscribe(int64_t subuid) final; void ClientSetValue(int64_t pubuid, const Value& value); @@ -362,7 +362,7 @@ struct PublisherData { struct SubscriberData { SubscriberData(ClientData* client, std::span topicNames, - int64_t subuid, const PubSubOptions& options) + int64_t subuid, const PubSubOptionsImpl& options) : client{client}, topicNames{topicNames.begin(), topicNames.end()}, subuid{subuid}, @@ -374,7 +374,7 @@ struct SubscriberData { } void Update(std::span topicNames_, - const PubSubOptions& options_) { + const PubSubOptionsImpl& options_) { topicNames = {topicNames_.begin(), topicNames_.end()}; options = options_; periodMs = std::lround(options_.periodicMs / 10.0) * 10; @@ -388,7 +388,7 @@ struct SubscriberData { ClientData* client; std::vector topicNames; int64_t subuid; - PubSubOptions options; + PubSubOptionsImpl options; // in options as double, but copy here as integer; rounded to the nearest // 10 ms uint32_t periodMs; @@ -463,10 +463,11 @@ struct Writer : public mpack_writer_t { }; } // namespace -static void WriteOptions(mpack_writer_t& w, const PubSubOptions& options) { - int size = (options.sendAll ? 1 : 0) + (options.topicsOnly ? 1 : 0) + - (options.periodicMs != PubSubOptions::kDefaultPeriodicMs ? 1 : 0) + - (options.prefixMatch ? 1 : 0); +static void WriteOptions(mpack_writer_t& w, const PubSubOptionsImpl& options) { + int size = + (options.sendAll ? 1 : 0) + (options.topicsOnly ? 1 : 0) + + (options.periodicMs != PubSubOptionsImpl::kDefaultPeriodicMs ? 1 : 0) + + (options.prefixMatch ? 1 : 0); mpack_start_map(&w, size); if (options.sendAll) { mpack_write_str(&w, "all"); @@ -476,7 +477,7 @@ static void WriteOptions(mpack_writer_t& w, const PubSubOptions& options) { mpack_write_str(&w, "topicsonly"); mpack_write_bool(&w, true); } - if (options.periodicMs != PubSubOptions::kDefaultPeriodicMs) { + if (options.periodicMs != PubSubOptionsImpl::kDefaultPeriodicMs) { mpack_write_str(&w, "periodic"); mpack_write_float(&w, options.periodicMs / 1000.0); } @@ -616,7 +617,7 @@ void ClientData4Base::ClientSetProperties(std::string_view name, void ClientData4Base::ClientSubscribe(int64_t subuid, std::span topicNames, - const PubSubOptions& options) { + const PubSubOptionsImpl& options) { DEBUG4("ClientSubscribe({}, ({}), {})", m_id, fmt::join(topicNames, ","), subuid); auto& sub = m_subscribers[subuid]; @@ -2365,14 +2366,14 @@ std::string ServerImpl::LoadPersistent(std::string_view in) { void ServerStartup::Publish(NT_Publisher pubHandle, NT_Topic topicHandle, std::string_view name, std::string_view typeStr, const wpi::json& properties, - const PubSubOptions& options) { + const PubSubOptionsImpl& options) { m_server.m_impl->m_localClient->ClientPublish(pubHandle, name, typeStr, properties); } void ServerStartup::Subscribe(NT_Subscriber subHandle, std::span topicNames, - const PubSubOptions& options) { + const PubSubOptionsImpl& options) { m_server.m_impl->m_localClient->ClientSubscribe(subHandle, topicNames, options); } diff --git a/ntcore/src/main/native/cpp/net/ServerImpl.h b/ntcore/src/main/native/cpp/net/ServerImpl.h index d82a08404d9..d99c6098e34 100644 --- a/ntcore/src/main/native/cpp/net/ServerImpl.h +++ b/ntcore/src/main/native/cpp/net/ServerImpl.h @@ -83,10 +83,11 @@ class ServerStartup final : public NetworkStartupInterface { // NetworkStartupInterface interface void Publish(NT_Publisher pubHandle, NT_Topic topicHandle, std::string_view name, std::string_view typeStr, - const wpi::json& properties, const PubSubOptions& options) final; + const wpi::json& properties, + const PubSubOptionsImpl& options) final; void Subscribe(NT_Subscriber subHandle, std::span topicNames, - const PubSubOptions& options) final; + const PubSubOptionsImpl& options) final; void SetValue(NT_Publisher pubHandle, const Value& value) final; private: diff --git a/ntcore/src/main/native/cpp/net/WireDecoder.cpp b/ntcore/src/main/native/cpp/net/WireDecoder.cpp index 785e3ebf8e2..e6474b2faab 100644 --- a/ntcore/src/main/native/cpp/net/WireDecoder.cpp +++ b/ntcore/src/main/native/cpp/net/WireDecoder.cpp @@ -226,7 +226,7 @@ static void WireDecodeTextImpl(std::string_view in, T& out, } // options - PubSubOptions options; + PubSubOptionsImpl options; auto optionsIt = params->find("options"); if (optionsIt != params->end()) { auto joptions = optionsIt->second.get_ptr(); @@ -243,6 +243,7 @@ static void WireDecodeTextImpl(std::string_view in, T& out, error = "periodic value must be a number"; goto err; } + options.periodic = val; options.periodicMs = val * 1000; } diff --git a/ntcore/src/main/native/cpp/net/WireDecoder.h b/ntcore/src/main/native/cpp/net/WireDecoder.h index dd472e81c5b..128dff2fb84 100644 --- a/ntcore/src/main/native/cpp/net/WireDecoder.h +++ b/ntcore/src/main/native/cpp/net/WireDecoder.h @@ -17,7 +17,7 @@ class json; } // namespace wpi namespace nt { -class PubSubOptions; +class PubSubOptionsImpl; class Value; } // namespace nt @@ -35,7 +35,7 @@ class ClientMessageHandler { const wpi::json& update) = 0; virtual void ClientSubscribe(int64_t subuid, std::span topicNames, - const PubSubOptions& options) = 0; + const PubSubOptionsImpl& options) = 0; virtual void ClientUnsubscribe(int64_t subuid) = 0; }; diff --git a/ntcore/src/main/native/cpp/net/WireEncoder.cpp b/ntcore/src/main/native/cpp/net/WireEncoder.cpp index 0482b43d8a1..143fe0dc056 100644 --- a/ntcore/src/main/native/cpp/net/WireEncoder.cpp +++ b/ntcore/src/main/native/cpp/net/WireEncoder.cpp @@ -76,7 +76,7 @@ static void EncodePrefixes(wpi::raw_ostream& os, std::span topicNames, template static void WireEncodeSubscribeImpl(wpi::raw_ostream& os, int64_t subuid, std::span topicNames, - const PubSubOptions& options) { + const PubSubOptionsImpl& options) { wpi::json::serializer s{os, ' ', 0}; os << "{\"method\":\"" << SubscribeMsg::kMethodStr << "\",\"params\":{"; os << "\"options\":{"; @@ -99,7 +99,7 @@ static void WireEncodeSubscribeImpl(wpi::raw_ostream& os, int64_t subuid, os << "\"prefix\":true"; first = false; } - if (options.periodicMs != PubSubOptions::kDefaultPeriodicMs) { + if (options.periodicMs != PubSubOptionsImpl::kDefaultPeriodicMs) { if (!first) { os << ','; } @@ -115,13 +115,13 @@ static void WireEncodeSubscribeImpl(wpi::raw_ostream& os, int64_t subuid, void nt::net::WireEncodeSubscribe(wpi::raw_ostream& os, int64_t subuid, std::span topicNames, - const PubSubOptions& options) { + const PubSubOptionsImpl& options) { WireEncodeSubscribeImpl(os, subuid, topicNames, options); } void nt::net::WireEncodeSubscribe(wpi::raw_ostream& os, int64_t subuid, std::span topicNames, - const PubSubOptions& options) { + const PubSubOptionsImpl& options) { WireEncodeSubscribeImpl(os, subuid, topicNames, options); } diff --git a/ntcore/src/main/native/cpp/net/WireEncoder.h b/ntcore/src/main/native/cpp/net/WireEncoder.h index 63f8b362b52..d0a04cb0b95 100644 --- a/ntcore/src/main/native/cpp/net/WireEncoder.h +++ b/ntcore/src/main/native/cpp/net/WireEncoder.h @@ -15,7 +15,7 @@ class raw_ostream; } // namespace wpi namespace nt { -class PubSubOptions; +class PubSubOptionsImpl; class Value; } // namespace nt @@ -33,10 +33,10 @@ void WireEncodeSetProperties(wpi::raw_ostream& os, std::string_view name, const wpi::json& update); void WireEncodeSubscribe(wpi::raw_ostream& os, int64_t subuid, std::span topicNames, - const PubSubOptions& options); + const PubSubOptionsImpl& options); void WireEncodeSubscribe(wpi::raw_ostream& os, int64_t subuid, std::span topicNames, - const PubSubOptions& options); + const PubSubOptionsImpl& options); void WireEncodeUnsubscribe(wpi::raw_ostream& os, int64_t subuid); // encoders for server text messages (avoids need to construct a Message struct) diff --git a/ntcore/src/main/native/cpp/net3/ClientImpl3.cpp b/ntcore/src/main/native/cpp/net3/ClientImpl3.cpp index 579f94daece..53325a8fb98 100644 --- a/ntcore/src/main/native/cpp/net3/ClientImpl3.cpp +++ b/ntcore/src/main/native/cpp/net3/ClientImpl3.cpp @@ -44,7 +44,7 @@ struct PublisherData { Entry* entry; NT_Publisher handle; - PubSubOptions options; + PubSubOptionsImpl options; // in options as double, but copy here as integer; rounded to the nearest // 10 ms uint32_t periodMs; @@ -98,7 +98,7 @@ class CImpl : public MessageHandler3 { // Outgoing handlers void Publish(NT_Publisher pubHandle, NT_Topic topicHandle, std::string_view name, std::string_view typeStr, - const wpi::json& properties, const PubSubOptions& options); + const wpi::json& properties, const PubSubOptionsImpl& options); void Unpublish(NT_Publisher pubHandle, NT_Topic topicHandle); void SetProperties(NT_Topic topicHandle, std::string_view name, const wpi::json& update); @@ -315,7 +315,8 @@ bool CImpl::CheckNetworkReady() { void CImpl::Publish(NT_Publisher pubHandle, NT_Topic topicHandle, std::string_view name, std::string_view typeStr, - const wpi::json& properties, const PubSubOptions& options) { + const wpi::json& properties, + const PubSubOptionsImpl& options) { DEBUG4("Publish('{}', '{}')", name, typeStr); unsigned int index = Handle{pubHandle}.GetIndex(); if (index >= m_publishers.size()) { @@ -647,7 +648,7 @@ ClientStartup3::~ClientStartup3() = default; void ClientStartup3::Publish(NT_Publisher pubHandle, NT_Topic topicHandle, std::string_view name, std::string_view typeStr, const wpi::json& properties, - const PubSubOptions& options) { + const PubSubOptionsImpl& options) { WPI_DEBUG4(m_client.m_impl->m_logger, "StartupPublish({}, {}, {}, {})", pubHandle, topicHandle, name, typeStr); m_client.m_impl->Publish(pubHandle, topicHandle, name, typeStr, properties, @@ -656,7 +657,7 @@ void ClientStartup3::Publish(NT_Publisher pubHandle, NT_Topic topicHandle, void ClientStartup3::Subscribe(NT_Subscriber subHandle, std::span prefixes, - const PubSubOptions& options) { + const PubSubOptionsImpl& options) { // NT3 ignores subscribes, so no action required } diff --git a/ntcore/src/main/native/cpp/net3/ClientImpl3.h b/ntcore/src/main/native/cpp/net3/ClientImpl3.h index 5b30a463ab4..9214800fcf2 100644 --- a/ntcore/src/main/native/cpp/net3/ClientImpl3.h +++ b/ntcore/src/main/native/cpp/net3/ClientImpl3.h @@ -60,9 +60,10 @@ class ClientStartup3 final : public net::NetworkStartupInterface { // NetworkStartupInterface interface void Publish(NT_Publisher pubHandle, NT_Topic topicHandle, std::string_view name, std::string_view typeStr, - const wpi::json& properties, const PubSubOptions& options) final; + const wpi::json& properties, + const PubSubOptionsImpl& options) final; void Subscribe(NT_Subscriber subHandle, std::span prefixes, - const PubSubOptions& options) final; + const PubSubOptionsImpl& options) final; void SetValue(NT_Publisher pubHandle, const Value& value) final; private: diff --git a/ntcore/src/main/native/cpp/networktables/Topic.cpp b/ntcore/src/main/native/cpp/networktables/Topic.cpp index d37057ceb5f..e3f6ac02e8f 100644 --- a/ntcore/src/main/native/cpp/networktables/Topic.cpp +++ b/ntcore/src/main/native/cpp/networktables/Topic.cpp @@ -22,37 +22,36 @@ wpi::json Topic::GetProperties() const { return ::nt::GetTopicProperties(m_handle); } -GenericSubscriber Topic::GenericSubscribe( - std::span options) { +GenericSubscriber Topic::GenericSubscribe(const PubSubOptions& options) { return GenericSubscribe("", options); } -GenericSubscriber Topic::GenericSubscribe( - std::string_view typeString, std::span options) { +GenericSubscriber Topic::GenericSubscribe(std::string_view typeString, + const PubSubOptions& options) { return GenericSubscriber{::nt::Subscribe( m_handle, ::nt::GetTypeFromString(typeString), typeString, options)}; } GenericPublisher Topic::GenericPublish(std::string_view typeString, - std::span options) { + const PubSubOptions& options) { return GenericPublisher{::nt::Publish( m_handle, ::nt::GetTypeFromString(typeString), typeString, options)}; } -GenericPublisher Topic::GenericPublishEx( - std::string_view typeString, const wpi::json& properties, - std::span options) { +GenericPublisher Topic::GenericPublishEx(std::string_view typeString, + const wpi::json& properties, + const PubSubOptions& options) { return GenericPublisher{::nt::PublishEx(m_handle, ::nt::GetTypeFromString(typeString), typeString, properties, options)}; } -GenericEntry Topic::GetGenericEntry(std::span options) { +GenericEntry Topic::GetGenericEntry(const PubSubOptions& options) { return GetGenericEntry("", options); } GenericEntry Topic::GetGenericEntry(std::string_view typeString, - std::span options) { + const PubSubOptions& options) { return GenericEntry{::nt::GetEntry( m_handle, ::nt::GetTypeFromString(typeString), typeString, options)}; } diff --git a/ntcore/src/main/native/cpp/ntcore_c.cpp b/ntcore/src/main/native/cpp/ntcore_c.cpp index e6d15300b8b..bca7266d6b7 100644 --- a/ntcore/src/main/native/cpp/ntcore_c.cpp +++ b/ntcore/src/main/native/cpp/ntcore_c.cpp @@ -2,6 +2,8 @@ // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. +#include "ntcore_c.h" + #include #include @@ -101,6 +103,21 @@ static void DisposeEvent(NT_Event* event) { } } +static PubSubOptions ConvertToCpp(const NT_PubSubOptions* in) { + PubSubOptions out; + out.pollStorage = in->pollStorage; + out.periodic = in->periodic; + out.excludePublisher = in->excludePublisher; + out.sendAll = in->sendAll; + out.topicsOnly = in->topicsOnly; + out.prefixMatch = in->prefixMatch; + out.keepDuplicates = in->keepDuplicates; + out.disableRemote = in->disableRemote; + out.disableLocal = in->disableLocal; + out.excludeSelf = in->excludeSelf; + return out; +} + extern "C" { /* @@ -314,14 +331,8 @@ NT_Bool NT_SetTopicProperties(NT_Topic topic, const char* properties) { } NT_Subscriber NT_Subscribe(NT_Topic topic, NT_Type type, const char* typeStr, - const struct NT_PubSubOption* options, - size_t options_len) { - wpi::SmallVector o; - o.reserve(options_len); - for (size_t i = 0; i < options_len; ++i) { - o.emplace_back(options[i].type, options[i].value); - } - return nt::Subscribe(topic, type, typeStr, o); + const struct NT_PubSubOptions* options) { + return nt::Subscribe(topic, type, typeStr, ConvertToCpp(options)); } void NT_Unsubscribe(NT_Subscriber sub) { @@ -329,20 +340,13 @@ void NT_Unsubscribe(NT_Subscriber sub) { } NT_Publisher NT_Publish(NT_Topic topic, NT_Type type, const char* typeStr, - const struct NT_PubSubOption* options, - size_t options_len) { - wpi::SmallVector o; - o.reserve(options_len); - for (size_t i = 0; i < options_len; ++i) { - o.emplace_back(options[i].type, options[i].value); - } - return nt::Publish(topic, type, typeStr, o); + const struct NT_PubSubOptions* options) { + return nt::Publish(topic, type, typeStr, ConvertToCpp(options)); } NT_Publisher NT_PublishEx(NT_Topic topic, NT_Type type, const char* typeStr, const char* properties, - const struct NT_PubSubOption* options, - size_t options_len) { + const struct NT_PubSubOptions* options) { wpi::json j; if (properties[0] == '\0') { // gracefully handle empty string @@ -355,13 +359,7 @@ NT_Publisher NT_PublishEx(NT_Topic topic, NT_Type type, const char* typeStr, } } - wpi::SmallVector o; - o.reserve(options_len); - for (size_t i = 0; i < options_len; ++i) { - o.emplace_back(options[i].type, options[i].value); - } - - return nt::PublishEx(topic, type, typeStr, j, o); + return nt::PublishEx(topic, type, typeStr, j, ConvertToCpp(options)); } void NT_Unpublish(NT_Handle pubentry) { @@ -369,14 +367,8 @@ void NT_Unpublish(NT_Handle pubentry) { } NT_Entry NT_GetEntryEx(NT_Topic topic, NT_Type type, const char* typeStr, - const struct NT_PubSubOption* options, - size_t options_len) { - wpi::SmallVector o; - o.reserve(options_len); - for (size_t i = 0; i < options_len; ++i) { - o.emplace_back(options[i].type, options[i].value); - } - return nt::GetEntry(topic, type, typeStr, o); + const struct NT_PubSubOptions* options) { + return nt::GetEntry(topic, type, typeStr, ConvertToCpp(options)); } void NT_ReleaseEntry(NT_Entry entry) { diff --git a/ntcore/src/main/native/cpp/ntcore_cpp.cpp b/ntcore/src/main/native/cpp/ntcore_cpp.cpp index fd8d3238443..2780bb2f33b 100644 --- a/ntcore/src/main/native/cpp/ntcore_cpp.cpp +++ b/ntcore/src/main/native/cpp/ntcore_cpp.cpp @@ -310,7 +310,7 @@ bool SetTopicProperties(NT_Topic topic, const wpi::json& properties) { } NT_Subscriber Subscribe(NT_Topic topic, NT_Type type, std::string_view typeStr, - std::span options) { + const PubSubOptions& options) { if (auto ii = InstanceImpl::GetTyped(topic, Handle::kTopic)) { return ii->localStorage.Subscribe(topic, type, typeStr, options); } else { @@ -325,13 +325,13 @@ void Unsubscribe(NT_Subscriber sub) { } NT_Publisher Publish(NT_Topic topic, NT_Type type, std::string_view typeStr, - std::span options) { + const PubSubOptions& options) { return PublishEx(topic, type, typeStr, wpi::json::object(), options); } NT_Publisher PublishEx(NT_Topic topic, NT_Type type, std::string_view typeStr, const wpi::json& properties, - std::span options) { + const PubSubOptions& options) { if (auto ii = InstanceImpl::GetTyped(topic, Handle::kTopic)) { return ii->localStorage.Publish(topic, type, typeStr, properties, options); } else { @@ -346,7 +346,7 @@ void Unpublish(NT_Handle pubentry) { } NT_Entry GetEntry(NT_Topic topic, NT_Type type, std::string_view typeStr, - std::span options) { + const PubSubOptions& options) { if (auto ii = InstanceImpl::GetTyped(topic, Handle::kTopic)) { return ii->localStorage.GetEntry(topic, type, typeStr, options); } else { @@ -376,7 +376,7 @@ NT_Topic GetTopicFromHandle(NT_Handle pubsubentry) { NT_MultiSubscriber SubscribeMultiple(NT_Inst inst, std::span prefixes, - std::span options) { + const PubSubOptions& options) { if (auto ii = InstanceImpl::GetTyped(inst, Handle::kInstance)) { return ii->localStorage.SubscribeMultiple(prefixes, options); } else { diff --git a/ntcore/src/main/native/include/networktables/MultiSubscriber.h b/ntcore/src/main/native/include/networktables/MultiSubscriber.h index 69c286c1ac1..f146351b627 100644 --- a/ntcore/src/main/native/include/networktables/MultiSubscriber.h +++ b/ntcore/src/main/native/include/networktables/MultiSubscriber.h @@ -30,7 +30,7 @@ class MultiSubscriber final { */ MultiSubscriber(NetworkTableInstance inst, std::span prefixes, - std::span options = {}); + const PubSubOptions& options = kDefaultPubSubOptions); MultiSubscriber(const MultiSubscriber&) = delete; MultiSubscriber& operator=(const MultiSubscriber&) = delete; diff --git a/ntcore/src/main/native/include/networktables/MultiSubscriber.inc b/ntcore/src/main/native/include/networktables/MultiSubscriber.inc index 25aed502ce6..c32c06a8785 100644 --- a/ntcore/src/main/native/include/networktables/MultiSubscriber.inc +++ b/ntcore/src/main/native/include/networktables/MultiSubscriber.inc @@ -10,7 +10,7 @@ namespace nt { inline MultiSubscriber::MultiSubscriber( NetworkTableInstance inst, std::span prefixes, - std::span options) + const PubSubOptions& options) : m_handle{::nt::SubscribeMultiple(inst.GetHandle(), prefixes, options)} {} inline MultiSubscriber::MultiSubscriber(MultiSubscriber&& rhs) diff --git a/ntcore/src/main/native/include/networktables/Topic.h b/ntcore/src/main/native/include/networktables/Topic.h index 9825135450d..e2a8a5a3506 100644 --- a/ntcore/src/main/native/include/networktables/Topic.h +++ b/ntcore/src/main/native/include/networktables/Topic.h @@ -6,7 +6,6 @@ #include -#include #include #include #include @@ -171,7 +170,7 @@ class Topic { * @return subscriber */ [[nodiscard]] GenericSubscriber GenericSubscribe( - std::span options = {}); + const PubSubOptions& options = kDefaultPubSubOptions); /** * Create a new subscriber to the topic. @@ -188,7 +187,8 @@ class Topic { * @return subscriber */ [[nodiscard]] GenericSubscriber GenericSubscribe( - std::string_view typeString, std::span options = {}); + std::string_view typeString, + const PubSubOptions& options = kDefaultPubSubOptions); /** * Create a new publisher to the topic. @@ -207,7 +207,8 @@ class Topic { * @return publisher */ [[nodiscard]] GenericPublisher GenericPublish( - std::string_view typeString, std::span options = {}); + std::string_view typeString, + const PubSubOptions& options = kDefaultPubSubOptions); /** * Create a new publisher to the topic, with type string and initial @@ -229,7 +230,7 @@ class Topic { */ [[nodiscard]] GenericPublisher GenericPublishEx( std::string_view typeString, const wpi::json& properties, - std::span options = {}); + const PubSubOptions& options = kDefaultPubSubOptions); /** * Create a new generic entry for the topic. @@ -250,7 +251,7 @@ class Topic { * @return entry */ [[nodiscard]] GenericEntry GetGenericEntry( - std::span options = {}); + const PubSubOptions& options = kDefaultPubSubOptions); /** * Create a new generic entry for the topic. @@ -272,7 +273,8 @@ class Topic { * @return entry */ [[nodiscard]] GenericEntry GetGenericEntry( - std::string_view typeString, std::span options = {}); + std::string_view typeString, + const PubSubOptions& options = kDefaultPubSubOptions); /** * Equality operator. Returns true if both instances refer to the same diff --git a/ntcore/src/main/native/include/networktables/UnitTopic.h b/ntcore/src/main/native/include/networktables/UnitTopic.h index a422f0ed0d9..cac950180b9 100644 --- a/ntcore/src/main/native/include/networktables/UnitTopic.h +++ b/ntcore/src/main/native/include/networktables/UnitTopic.h @@ -11,6 +11,7 @@ #include #include "networktables/Topic.h" +#include "ntcore_cpp.h" namespace wpi { class json; @@ -295,7 +296,8 @@ class UnitTopic final : public Topic { * @return subscriber */ [[nodiscard]] SubscriberType Subscribe( - ParamType defaultValue, std::span options = {}); + ParamType defaultValue, + const PubSubOptions& options = kDefaultPubSubOptions); /** * Create a new subscriber to the topic, with specific type string. @@ -315,7 +317,7 @@ class UnitTopic final : public Topic { */ [[nodiscard]] SubscriberType SubscribeEx( std::string_view typeString, ParamType defaultValue, - std::span options = {}); + const PubSubOptions& options = kDefaultPubSubOptions); /** * Create a new publisher to the topic. @@ -333,7 +335,7 @@ class UnitTopic final : public Topic { * @return publisher */ [[nodiscard]] PublisherType Publish( - std::span options = {}); + const PubSubOptions& options = kDefaultPubSubOptions); /** * Create a new publisher to the topic, with type string and initial @@ -355,7 +357,7 @@ class UnitTopic final : public Topic { */ [[nodiscard]] PublisherType PublishEx( std::string_view typeString, const wpi::json& properties, - std::span options = {}); + const PubSubOptions& options = kDefaultPubSubOptions); /** * Create a new entry for the topic. @@ -377,8 +379,9 @@ class UnitTopic final : public Topic { * @param options publish and/or subscribe options * @return entry */ - [[nodiscard]] EntryType GetEntry(ParamType defaultValue, - std::span options = {}); + [[nodiscard]] EntryType GetEntry( + ParamType defaultValue, + const PubSubOptions& options = kDefaultPubSubOptions); /** * Create a new entry for the topic, with specific type string. @@ -403,7 +406,7 @@ class UnitTopic final : public Topic { */ [[nodiscard]] EntryType GetEntryEx( std::string_view typeString, ParamType defaultValue, - std::span options = {}); + const PubSubOptions& options = kDefaultPubSubOptions); }; } // namespace nt diff --git a/ntcore/src/main/native/include/networktables/UnitTopic.inc b/ntcore/src/main/native/include/networktables/UnitTopic.inc index 9327a48d7f5..c107526da1f 100644 --- a/ntcore/src/main/native/include/networktables/UnitTopic.inc +++ b/ntcore/src/main/native/include/networktables/UnitTopic.inc @@ -93,31 +93,29 @@ inline bool UnitTopic::IsMatchingUnit() const { } template -inline UnitSubscriber UnitTopic::Subscribe( - T defaultValue, std::span options) { +inline UnitSubscriber UnitTopic::Subscribe(T defaultValue, + const PubSubOptions& options) { return UnitSubscriber{ ::nt::Subscribe(m_handle, NT_DOUBLE, "double", options), defaultValue}; } template inline UnitSubscriber UnitTopic::SubscribeEx( - std::string_view typeString, T defaultValue, - std::span options) { + std::string_view typeString, T defaultValue, const PubSubOptions& options) { return UnitSubscriber{ ::nt::Subscribe(m_handle, NT_DOUBLE, typeString, options), defaultValue}; } template -inline UnitPublisher UnitTopic::Publish( - std::span options) { +inline UnitPublisher UnitTopic::Publish(const PubSubOptions& options) { return UnitPublisher{::nt::PublishEx(m_handle, NT_DOUBLE, "double", {{"unit", T{}.name()}}, options)}; } template -inline UnitPublisher UnitTopic::PublishEx( - std::string_view typeString, const wpi::json& properties, - std::span options) { +inline UnitPublisher UnitTopic::PublishEx(std::string_view typeString, + const wpi::json& properties, + const PubSubOptions& options) { wpi::json props = properties; props["unit"] = T{}.name(); return UnitPublisher{ @@ -125,16 +123,16 @@ inline UnitPublisher UnitTopic::PublishEx( } template -inline UnitEntry UnitTopic::GetEntry( - T defaultValue, std::span options) { +inline UnitEntry UnitTopic::GetEntry(T defaultValue, + const PubSubOptions& options) { return UnitEntry{::nt::GetEntry(m_handle, NT_DOUBLE, "double", options), defaultValue}; } template -inline UnitEntry UnitTopic::GetEntryEx( - std::string_view typeString, T defaultValue, - std::span options) { +inline UnitEntry UnitTopic::GetEntryEx(std::string_view typeString, + T defaultValue, + const PubSubOptions& options) { return UnitEntry{::nt::GetEntry(m_handle, NT_DOUBLE, typeString, options), defaultValue}; } diff --git a/ntcore/src/main/native/include/ntcore_c.h b/ntcore/src/main/native/include/ntcore_c.h index 3d2d17e33e6..f00cb21225e 100644 --- a/ntcore/src/main/native/include/ntcore_c.h +++ b/ntcore/src/main/native/include/ntcore_c.h @@ -88,18 +88,6 @@ enum NT_NetworkMode { NT_NET_MODE_LOCAL = 0x10, /* running in local-only mode */ }; -/** Pub/sub option types */ -enum NT_PubSubOptionType { - NT_PUBSUB_PERIODIC = 1, /* period between transmissions */ - NT_PUBSUB_SENDALL, /* all value changes are sent */ - NT_PUBSUB_TOPICSONLY, /* only send topic changes, no value changes */ - NT_PUBSUB_POLLSTORAGE, /* polling storage for subscription */ - NT_PUBSUB_KEEPDUPLICATES, /* preserve duplicate values */ - NT_PUBSUB_LOCALREMOTE, /* local, remote, or any value changes */ - NT_PUBSUB_EXCLUDEPUB, /* exclude value changes made by given publisher */ - NT_PUBSUB_EXCLUDESELF, /* exclude value changes made by entry publisher */ -}; - /** Event notification flags. */ enum NT_EventFlags { NT_EVENT_NONE = 0, @@ -283,18 +271,74 @@ struct NT_Event { } data; }; -/** NetworkTables publish/subscribe option. */ -struct NT_PubSubOption { - /** Option type. */ - enum NT_PubSubOptionType type; +/** NetworkTables publish/subscribe options. */ +struct NT_PubSubOptions { + /** + * Structure size. Must be set to sizeof(NT_PubSubOptions). + */ + unsigned int structSize; + + /** + * Polling storage size for a subscription. Specifies the maximum number of + * updates NetworkTables should store between calls to the subscriber's + * ReadQueue() function. If zero, defaults to 1 if sendAll is false, 20 if + * sendAll is true. + */ + unsigned int pollStorage; + + /** + * How frequently changes will be sent over the network, in seconds. + * NetworkTables may send more frequently than this (e.g. use a combined + * minimum period for all values) or apply a restricted range to this value. + * The default is 100 ms. + */ + double periodic; + + /** + * For subscriptions, if non-zero, value updates for ReadQueue() are not + * queued for this publisher. + */ + NT_Publisher excludePublisher; + + /** + * Send all value changes over the network. + */ + NT_Bool sendAll; + + /** + * For subscriptions, don't ask for value changes (only topic announcements). + */ + NT_Bool topicsOnly; + + /** + * Perform prefix match on subscriber topic names. Is ignored/overridden by + * Subscribe() functions; only present in struct for the purposes of getting + * information about subscriptions. + */ + NT_Bool prefixMatch; + + /** + * Preserve duplicate value changes (rather than ignoring them). + */ + NT_Bool keepDuplicates; + + /** + * For subscriptions, if remote value updates should not be queued for + * ReadQueue(). See also disableLocal. + */ + NT_Bool disableRemote; + + /** + * For subscriptions, if local value updates should not be queued for + * ReadQueue(). See also disableRemote. + */ + NT_Bool disableLocal; /** - * Option value. 1 (true) or 0 (false) for immediate and logging options, - * time between updates, in milliseconds, for periodic option. For - * local/remote option, 1=local only, 2=remote only, 0 or 3=both local and - * remote. For exclude publisher, publisher handle. + * For entries, don't queue (for ReadQueue) value updates for the entry's + * internal publisher. */ - unsigned int value; + NT_Bool excludeSelf; }; /** @@ -682,13 +726,11 @@ NT_Bool NT_SetTopicProperties(NT_Topic topic, const char* properties); * @param type expected type * @param typeStr expected type string * @param options subscription options - * @param options_len number of elements in options array * @return Subscriber handle */ NT_Subscriber NT_Subscribe(NT_Topic topic, enum NT_Type type, const char* typeStr, - const struct NT_PubSubOption* options, - size_t options_len); + const struct NT_PubSubOptions* options); /** * Stops subscriber. @@ -704,12 +746,10 @@ void NT_Unsubscribe(NT_Subscriber sub); * @param type type * @param typeStr type string * @param options publish options - * @param options_len number of elements in options array * @return Publisher handle */ NT_Publisher NT_Publish(NT_Topic topic, enum NT_Type type, const char* typeStr, - const struct NT_PubSubOption* options, - size_t options_len); + const struct NT_PubSubOptions* options); /** * Creates a new publisher to a topic. @@ -719,13 +759,11 @@ NT_Publisher NT_Publish(NT_Topic topic, enum NT_Type type, const char* typeStr, * @param typeStr type string * @param properties initial properties (JSON object) * @param options publish options - * @param options_len number of elements in options array * @return Publisher handle */ NT_Publisher NT_PublishEx(NT_Topic topic, enum NT_Type type, const char* typeStr, const char* properties, - const struct NT_PubSubOption* options, - size_t options_len); + const struct NT_PubSubOptions* options); /** * Stops publisher. @@ -741,12 +779,10 @@ void NT_Unpublish(NT_Handle pubentry); * @param type type * @param typeStr type string * @param options publish options - * @param options_len number of elements in options array * @return Entry handle */ NT_Entry NT_GetEntryEx(NT_Topic topic, enum NT_Type type, const char* typeStr, - const struct NT_PubSubOption* options, - size_t options_len); + const struct NT_PubSubOptions* options); /** * Stops entry subscriber/publisher. @@ -786,14 +822,12 @@ NT_Topic NT_GetTopicFromHandle(NT_Handle pubsubentry); * @param prefixes topic name prefixes * @param prefixes_len number of elements in prefixes array * @param options subscriber options - * @param options_len number of elements in options array * @return subscriber handle */ NT_MultiSubscriber NT_SubscribeMultiple(NT_Inst inst, const struct NT_String* prefixes, size_t prefixes_len, - const struct NT_PubSubOption* options, - size_t options_len); + const struct NT_PubSubOptions* options); /** * Unsubscribes a multi-subscriber. diff --git a/ntcore/src/main/native/include/ntcore_cpp.h b/ntcore/src/main/native/include/ntcore_cpp.h index ef65c84909c..279efe641b6 100644 --- a/ntcore/src/main/native/include/ntcore_cpp.h +++ b/ntcore/src/main/native/include/ntcore_cpp.h @@ -259,131 +259,86 @@ class Event { LogMessage* GetLogMessage() { return std::get_if(&data); } }; -/** NetworkTables publish/subscribe option. */ -class PubSubOption { - public: - constexpr PubSubOption(NT_PubSubOptionType type, unsigned int value) - : type{type}, value{value} {} +/** NetworkTables publish/subscribe options. */ +struct PubSubOptions { + /** + * Default value of periodic. + */ + static constexpr double kDefaultPeriodic = 0.1; /** - * How frequently changes will be sent over the network. NetworkTables may - * send more frequently than this (e.g. use a combined minimum period for all - * values) or apply a restricted range to this value. The default if - * unspecified (and the immediate flag is false) is 100 ms. This option and - * the immediate option override each other. - * - * @param time time between updates, in seconds - * @return option + * Structure size. Must be set to sizeof(PubSubOptions). */ - static constexpr PubSubOption Periodic(double time) { - return PubSubOption{NT_PUBSUB_PERIODIC, - static_cast(time * 1000)}; - } + unsigned int structSize = sizeof(PubSubOptions); /** - * If enabled, sends all value changes over the network even if only sent - * periodically. This option defaults to disabled. - * - * @param enabled True to enable, false to disable - * @return option + * Polling storage size for a subscription. Specifies the maximum number of + * updates NetworkTables should store between calls to the subscriber's + * ReadQueue() function. If zero, defaults to 1 if sendAll is false, 20 if + * sendAll is true. */ - static constexpr PubSubOption SendAll(bool enabled) { - return PubSubOption{NT_PUBSUB_SENDALL, enabled ? 1u : 0u}; - } + unsigned int pollStorage = 0; /** - * If enabled, no value changes are sent over the network. This option - * defaults to disabled. - * - * @param enabled True to enable, false to disable - * @return option + * How frequently changes will be sent over the network, in seconds. + * NetworkTables may send more frequently than this (e.g. use a combined + * minimum period for all values) or apply a restricted range to this value. + * The default is 100 ms. */ - static constexpr PubSubOption TopicsOnly(bool enabled) { - return PubSubOption{NT_PUBSUB_TOPICSONLY, enabled ? 1u : 0u}; - } + double periodic = kDefaultPeriodic; /** - * If enabled, preserves duplicate value changes (rather than ignoring them). - * This option defaults to disabled. - * - * @param enabled True to enable, false to disable - * @return option + * For subscriptions, if non-zero, value updates for ReadQueue() are not + * queued for this publisher. */ - static constexpr PubSubOption KeepDuplicates(bool enabled) { - return PubSubOption{NT_PUBSUB_KEEPDUPLICATES, enabled ? 1u : 0u}; - } + NT_Publisher excludePublisher = 0; /** - * Polling storage for subscription. Specifies the maximum number of updates - * NetworkTables should store between calls to the subscriber's ReadQueue() - * function. Defaults to 1 if SendAll is false, 20 if SendAll is true. - * - * @param depth number of entries to save for polling. - * @return option + * Send all value changes over the network. */ - static constexpr PubSubOption PollStorage(unsigned int depth) { - return PubSubOption{NT_PUBSUB_POLLSTORAGE, depth}; - } + bool sendAll = false; /** - * If only local value updates should be queued for ReadQueue(). See also - * RemoteOnly() and AllUpdates(). Default is AllUpdates. Only has an effect on - * subscriptions. - * - * @return option + * For subscriptions, don't ask for value changes (only topic announcements). */ - static constexpr PubSubOption LocalOnly() { - return PubSubOption{NT_PUBSUB_LOCALREMOTE, 1u}; - } + bool topicsOnly = false; /** - * If only remote value updates should be queued for ReadQueue(). See also - * LocalOnly() and AllUpdates(). Default is AllUpdates. Only has an effect on - * subscriptions. - * - * @return option + * Preserve duplicate value changes (rather than ignoring them). */ - static constexpr PubSubOption RemoteOnly() { - return PubSubOption{NT_PUBSUB_LOCALREMOTE, 2u}; - } + bool keepDuplicates = false; /** - * If both local and remote value updates should be queued for ReadQueue(). - * See also LocalOnly() and RemoteOnly(). Default is AllUpdates. Only has an - * effect on subscriptions. - * - * @return option + * Perform prefix match on subscriber topic names. Is ignored/overridden by + * Subscribe() functions; only present in struct for the purposes of getting + * information about subscriptions. */ - static constexpr PubSubOption AllUpdates() { - return PubSubOption{NT_PUBSUB_LOCALREMOTE, 0u}; - } + bool prefixMatch = false; /** - * Don't queue value updates for the given publisher. Only has an effect on - * subscriptions. Only one exclusion may be set. - * - * @param publisher publisher handle - * @return option + * For subscriptions, if remote value updates should not be queued for + * ReadQueue(). See also disableLocal. */ - static constexpr PubSubOption ExcludePublisher(NT_Publisher publisher) { - return PubSubOption{NT_PUBSUB_EXCLUDEPUB, publisher}; - } + bool disableRemote = false; /** - * Don't queue value updates for the internal publisher for an entry. Only has - * an effect on entries. - * - * @param enabled True to enable, false to disable - * @return option + * For subscriptions, if local value updates should not be queued for + * ReadQueue(). See also disableRemote. */ - static constexpr PubSubOption ExcludeSelf(bool enabled) { - return PubSubOption{NT_PUBSUB_EXCLUDESELF, enabled ? 1u : 0u}; - } + bool disableLocal = false; - NT_PubSubOptionType type; - unsigned int value; + /** + * For entries, don't queue (for ReadQueue) value updates for the entry's + * internal publisher. + */ + bool excludeSelf = false; }; +/** + * Default publish/subscribe options. + */ +constexpr PubSubOptions kDefaultPubSubOptions; + /** * @defgroup ntcore_instance_func Instance Functions * @{ @@ -750,7 +705,7 @@ bool SetTopicProperties(NT_Topic topic, const wpi::json& update); * @return Subscriber handle */ NT_Subscriber Subscribe(NT_Topic topic, NT_Type type, std::string_view typeStr, - std::span options = {}); + const PubSubOptions& options = kDefaultPubSubOptions); /** * Stops subscriber. @@ -769,7 +724,7 @@ void Unsubscribe(NT_Subscriber sub); * @return Publisher handle */ NT_Publisher Publish(NT_Topic topic, NT_Type type, std::string_view typeStr, - std::span options = {}); + const PubSubOptions& options = kDefaultPubSubOptions); /** * Creates a new publisher to a topic. @@ -783,7 +738,7 @@ NT_Publisher Publish(NT_Topic topic, NT_Type type, std::string_view typeStr, */ NT_Publisher PublishEx(NT_Topic topic, NT_Type type, std::string_view typeStr, const wpi::json& properties, - std::span options = {}); + const PubSubOptions& options = kDefaultPubSubOptions); /** * Stops publisher. @@ -802,7 +757,7 @@ void Unpublish(NT_Handle pubentry); * @return Entry handle */ NT_Entry GetEntry(NT_Topic topic, NT_Type type, std::string_view typeStr, - std::span options = {}); + const PubSubOptions& options = kDefaultPubSubOptions); /** * Stops entry subscriber/publisher. @@ -845,7 +800,7 @@ NT_Topic GetTopicFromHandle(NT_Handle pubsubentry); */ NT_MultiSubscriber SubscribeMultiple( NT_Inst inst, std::span prefixes, - std::span options = {}); + const PubSubOptions& options = kDefaultPubSubOptions); /** * Unsubscribes a multi-subscriber. diff --git a/ntcore/src/test/native/cpp/LocalStorageTest.cpp b/ntcore/src/test/native/cpp/LocalStorageTest.cpp index 83155cda964..0df7c1fe6b2 100644 --- a/ntcore/src/test/native/cpp/LocalStorageTest.cpp +++ b/ntcore/src/test/native/cpp/LocalStorageTest.cpp @@ -25,14 +25,19 @@ using ::testing::Return; namespace nt { -::testing::Matcher IsPubSubOptions( - const PubSubOptions& good) { - return AllOf(Field("periodic", &PubSubOptions::periodicMs, good.periodicMs), - Field("pollStorageSize", &PubSubOptions::pollStorageSize, - good.pollStorageSize), - Field("logging", &PubSubOptions::sendAll, good.sendAll), - Field("keepDuplicates", &PubSubOptions::keepDuplicates, - good.keepDuplicates)); +::testing::Matcher IsPubSubOptions( + const PubSubOptionsImpl& good) { + return AllOf( + Field("periodic", &PubSubOptionsImpl::periodicMs, good.periodicMs), + Field("pollStorage", &PubSubOptionsImpl::pollStorage, good.pollStorage), + Field("sendAll", &PubSubOptionsImpl::sendAll, good.sendAll), + Field("keepDuplicates", &PubSubOptionsImpl::keepDuplicates, + good.keepDuplicates)); +} + +::testing::Matcher IsDefaultPubSubOptions() { + static constexpr PubSubOptionsImpl kDefaultPubSubOptionsImpl; + return IsPubSubOptions(kDefaultPubSubOptionsImpl); } class LocalStorageTest : public ::testing::Test { @@ -72,7 +77,7 @@ TEST_F(LocalStorageTest, GetEntryEmptyName) { TEST_F(LocalStorageTest, GetEntryCached) { EXPECT_CALL(network, Subscribe(_, wpi::SpanEq({std::string{"tocache"}}), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); auto entry1 = storage.GetEntry("tocache"); EXPECT_EQ(entry1, storage.GetEntry("tocache")); @@ -99,7 +104,7 @@ TEST_F(LocalStorageTest, GetTopicInfoUnpublished) { TEST_F(LocalStorageTest, PublishNewNoProps) { EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"boolean"}, wpi::json::object(), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); storage.Publish(fooTopic, NT_BOOLEAN, "boolean", wpi::json::object(), {}); auto info = storage.GetTopicInfo(fooTopic); @@ -109,7 +114,7 @@ TEST_F(LocalStorageTest, PublishNewNoProps) { TEST_F(LocalStorageTest, PublishNewNoPropsNull) { EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"boolean"}, wpi::json::object(), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); storage.Publish(fooTopic, NT_BOOLEAN, "boolean", {}, {}); auto info = storage.GetTopicInfo(fooTopic); @@ -120,7 +125,7 @@ TEST_F(LocalStorageTest, PublishNew) { wpi::json properties = {{"persistent", true}}; EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"boolean"}, properties, - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); storage.Publish(fooTopic, NT_BOOLEAN, "boolean", {{"persistent", true}}, {}); auto info = storage.GetTopicInfo(fooTopic); @@ -137,12 +142,12 @@ TEST_F(LocalStorageTest, PublishNew) { TEST_F(LocalStorageTest, SubscribeNoTypeLocalPubPost) { EXPECT_CALL(network, Subscribe(_, wpi::SpanEq({std::string{"foo"}}), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); auto sub = storage.Subscribe(fooTopic, NT_UNASSIGNED, "", {}); EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"boolean"}, wpi::json::object(), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); auto pub = storage.Publish(fooTopic, NT_BOOLEAN, "boolean", {}, {}); auto val = Value::MakeBoolean(true, 5); @@ -174,7 +179,7 @@ TEST_F(LocalStorageTest, SubscribeNoTypeLocalPubPost) { TEST_F(LocalStorageTest, SubscribeNoTypeLocalPubPre) { EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"boolean"}, wpi::json::object(), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); auto pub = storage.Publish(fooTopic, NT_BOOLEAN, "boolean", {}, {}); auto val = Value::MakeBoolean(true, 5); @@ -182,7 +187,7 @@ TEST_F(LocalStorageTest, SubscribeNoTypeLocalPubPre) { storage.SetEntryValue(pub, val); EXPECT_CALL(network, Subscribe(_, wpi::SpanEq({std::string{"foo"}}), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); auto sub = storage.Subscribe(fooTopic, NT_UNASSIGNED, "", {}); EXPECT_EQ(storage.GetTopicType(fooTopic), NT_BOOLEAN); @@ -200,14 +205,14 @@ TEST_F(LocalStorageTest, SubscribeNoTypeLocalPubPre) { TEST_F(LocalStorageTest, EntryNoTypeLocalSet) { EXPECT_CALL(network, Subscribe(_, wpi::SpanEq({std::string{"foo"}}), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); auto entry = storage.GetEntry(fooTopic, NT_UNASSIGNED, "", {}); // results in a publish and value set auto val = Value::MakeBoolean(true, 5); EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"boolean"}, wpi::json::object(), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); EXPECT_CALL(network, SetValue(_, val)); EXPECT_TRUE(storage.SetEntryValue(entry, val)); @@ -246,12 +251,12 @@ TEST_F(LocalStorageTest, EntryNoTypeLocalSet) { TEST_F(LocalStorageTest, PubUnpubPub) { EXPECT_CALL(network, Subscribe(_, wpi::SpanEq({std::string{"foo"}}), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); auto sub = storage.Subscribe(fooTopic, NT_INTEGER, "int", {}); EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"boolean"}, wpi::json::object(), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); EXPECT_CALL(logger, Call(NT_LOG_INFO, _, _, "local subscribe to 'foo' disabled due to type " "mismatch (wanted 'int', published as 'boolean')")); @@ -276,7 +281,7 @@ TEST_F(LocalStorageTest, PubUnpubPub) { EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"int"}, wpi::json::object(), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); pub = storage.Publish(fooTopic, NT_INTEGER, "int", {}, {}); val = Value::MakeInteger(3, 5); @@ -293,7 +298,7 @@ TEST_F(LocalStorageTest, PubUnpubPub) { TEST_F(LocalStorageTest, LocalPubConflict) { EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"boolean"}, wpi::json::object(), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); auto pub1 = storage.Publish(fooTopic, NT_BOOLEAN, "boolean", {}, {}); EXPECT_CALL(logger, Call(NT_LOG_INFO, _, _, @@ -314,7 +319,7 @@ TEST_F(LocalStorageTest, LocalPubConflict) { EXPECT_CALL(network, Unpublish(pub1, fooTopic)); EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"int"}, wpi::json::object(), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); storage.Unpublish(pub1); EXPECT_EQ(storage.GetTopicType(fooTopic), NT_INTEGER); @@ -330,11 +335,11 @@ TEST_F(LocalStorageTest, LocalPubConflict) { TEST_F(LocalStorageTest, LocalSubConflict) { EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"boolean"}, wpi::json::object(), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); storage.Publish(fooTopic, NT_BOOLEAN, "boolean", {}, {}); EXPECT_CALL(network, Subscribe(_, wpi::SpanEq({std::string{"foo"}}), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); EXPECT_CALL(logger, Call(NT_LOG_INFO, _, _, "local subscribe to 'foo' disabled due to type " "mismatch (wanted 'int', published as 'boolean')")); @@ -344,7 +349,7 @@ TEST_F(LocalStorageTest, LocalSubConflict) { TEST_F(LocalStorageTest, RemotePubConflict) { EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"boolean"}, wpi::json::object(), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); storage.Publish(fooTopic, NT_BOOLEAN, "boolean", {}, {}); @@ -361,7 +366,7 @@ TEST_F(LocalStorageTest, RemotePubConflict) { EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"boolean"}, wpi::json::object(), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); storage.NetworkUnannounce("foo"); @@ -373,14 +378,14 @@ TEST_F(LocalStorageTest, RemotePubConflict) { TEST_F(LocalStorageTest, SubNonExist) { // makes sure no warning is emitted EXPECT_CALL(network, Subscribe(_, wpi::SpanEq({std::string{"foo"}}), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); storage.Subscribe(fooTopic, NT_BOOLEAN, "boolean", {}); } TEST_F(LocalStorageTest, SetDefaultSubscribe) { // no publish, no value on wire, this is just handled locally EXPECT_CALL(network, Subscribe(_, wpi::SpanEq({std::string{"foo"}}), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); auto sub = storage.Subscribe(fooTopic, NT_BOOLEAN, "boolean", {}); EXPECT_TRUE(storage.SetDefaultEntryValue(sub, Value::MakeBoolean(true))); auto val = storage.GetEntryValue(sub); @@ -392,7 +397,7 @@ TEST_F(LocalStorageTest, SetDefaultSubscribe) { TEST_F(LocalStorageTest, SetDefaultPublish) { EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"boolean"}, wpi::json::object(), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); auto pub = storage.Publish(fooTopic, NT_BOOLEAN, "boolean", {}, {}); // expect a value across the wire @@ -400,7 +405,7 @@ TEST_F(LocalStorageTest, SetDefaultPublish) { EXPECT_CALL(network, SetValue(pub, expectVal)); EXPECT_TRUE(storage.SetDefaultEntryValue(pub, Value::MakeBoolean(true))); - EXPECT_CALL(network, Subscribe(_, _, IsPubSubOptions({}))); + EXPECT_CALL(network, Subscribe(_, _, IsDefaultPubSubOptions())); auto sub = storage.Subscribe(fooTopic, NT_BOOLEAN, "boolean", {}); auto val = storage.GetEntryValue(sub); ASSERT_TRUE(val.IsBoolean()); @@ -410,13 +415,13 @@ TEST_F(LocalStorageTest, SetDefaultPublish) { TEST_F(LocalStorageTest, SetDefaultEntry) { EXPECT_CALL(network, Subscribe(_, wpi::SpanEq({std::string{"foo"}}), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); auto entry = storage.GetEntry(fooTopic, NT_BOOLEAN, "boolean", {}); // expect a publish and value EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"boolean"}, wpi::json::object(), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); auto expectVal = Value::MakeBoolean(true, 0); EXPECT_CALL(network, SetValue(_, expectVal)); EXPECT_TRUE(storage.SetDefaultEntryValue(entry, Value::MakeBoolean(true))); @@ -429,13 +434,13 @@ TEST_F(LocalStorageTest, SetDefaultEntry) { TEST_F(LocalStorageTest, SetDefaultEntryUnassigned) { EXPECT_CALL(network, Subscribe(_, wpi::SpanEq({std::string{"foo"}}), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); auto entry = storage.GetEntry(fooTopic, NT_UNASSIGNED, "", {}); // expect a publish and value EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"boolean"}, wpi::json::object(), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); auto expectVal = Value::MakeBoolean(true, 0); EXPECT_CALL(network, SetValue(_, expectVal)); EXPECT_TRUE(storage.SetDefaultEntryValue(entry, Value::MakeBoolean(true))); @@ -450,7 +455,7 @@ TEST_F(LocalStorageTest, SetDefaultEntryUnassigned) { TEST_F(LocalStorageTest, SetDefaultEntryDiffType) { EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"string"}, wpi::json::object(), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); auto pub = storage.Publish(fooTopic, NT_STRING, "string", {}, {}); EXPECT_FALSE(storage.SetDefaultEntryValue(pub, Value::MakeBoolean(true))); @@ -460,7 +465,7 @@ TEST_F(LocalStorageTest, SetDefaultEntryDiffType) { TEST_F(LocalStorageTest, SetValueEmptyValue) { EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"string"}, wpi::json::object(), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); auto pub = storage.Publish(fooTopic, NT_STRING, "string", {}, {}); EXPECT_FALSE(storage.SetEntryValue(pub, {})); @@ -468,7 +473,7 @@ TEST_F(LocalStorageTest, SetValueEmptyValue) { TEST_F(LocalStorageTest, SetValueEmptyUntypedEntry) { EXPECT_CALL(network, Subscribe(_, wpi::SpanEq({std::string{"foo"}}), - IsPubSubOptions({}))); + IsDefaultPubSubOptions())); auto entry = storage.GetEntry(fooTopic, NT_UNASSIGNED, "", {}); EXPECT_FALSE(storage.SetEntryValue(entry, {})); } @@ -500,22 +505,21 @@ class LocalStorageDuplicatesTest : public LocalStorageTest { }; void LocalStorageDuplicatesTest::SetupPubSub(bool keepPub, bool keepSub) { - PubSubOptions pubOptions; + PubSubOptionsImpl pubOptions; pubOptions.keepDuplicates = keepPub; EXPECT_CALL(network, Publish(_, fooTopic, std::string_view{"foo"}, std::string_view{"double"}, wpi::json::object(), IsPubSubOptions(pubOptions))); pub = storage.Publish(fooTopic, NT_DOUBLE, "double", {}, - {{PubSubOption::KeepDuplicates(keepPub)}}); + {.keepDuplicates = keepPub}); - PubSubOptions subOptions; - subOptions.pollStorageSize = 10; + PubSubOptionsImpl subOptions; + subOptions.pollStorage = 10; subOptions.keepDuplicates = keepSub; EXPECT_CALL(network, Subscribe(_, wpi::SpanEq({std::string{"foo"}}), IsPubSubOptions(subOptions))); - sub = storage.Subscribe( - fooTopic, NT_DOUBLE, "double", - {{PubSubOption::KeepDuplicates(keepSub), PubSubOption::PollStorage(10)}}); + sub = storage.Subscribe(fooTopic, NT_DOUBLE, "double", + {.pollStorage = 10, .keepDuplicates = keepSub}); } void LocalStorageDuplicatesTest::SetValues() { @@ -839,12 +843,12 @@ TEST_F(LocalStorageTest, ReadQueueLocalRemote) { EXPECT_CALL(network, Subscribe(_, _, _)).Times(3); EXPECT_CALL(network, Publish(_, _, _, _, _, _)).Times(1); - auto subBoth = storage.Subscribe(fooTopic, NT_DOUBLE, "double", - {{PubSubOption::AllUpdates()}}); - auto subLocal = storage.Subscribe(fooTopic, NT_DOUBLE, "double", - {{PubSubOption::LocalOnly()}}); - auto subRemote = storage.Subscribe(fooTopic, NT_DOUBLE, "double", - {{PubSubOption::RemoteOnly()}}); + auto subBoth = + storage.Subscribe(fooTopic, NT_DOUBLE, "double", kDefaultPubSubOptions); + auto subLocal = + storage.Subscribe(fooTopic, NT_DOUBLE, "double", {.disableRemote = true}); + auto subRemote = + storage.Subscribe(fooTopic, NT_DOUBLE, "double", {.disableLocal = true}); auto pub = storage.Publish(fooTopic, NT_DOUBLE, "double", {}, {}); auto remoteTopic = storage.NetworkAnnounce("foo", "double", wpi::json::object(), 0); @@ -874,7 +878,7 @@ TEST_F(LocalStorageTest, SubExcludePub) { auto pub = storage.Publish(fooTopic, NT_DOUBLE, "double", {}, {}); auto subActive = storage.Subscribe(fooTopic, NT_DOUBLE, "double", {}); auto subExclude = storage.Subscribe(fooTopic, NT_DOUBLE, "double", - {{PubSubOption::ExcludePublisher(pub)}}); + {.excludePublisher = pub}); auto remoteTopic = storage.NetworkAnnounce("foo", "double", wpi::json::object(), 0); @@ -896,8 +900,8 @@ TEST_F(LocalStorageTest, SubExcludePub) { TEST_F(LocalStorageTest, EntryExcludeSelf) { EXPECT_CALL(network, Subscribe(_, _, _)); - auto entry = storage.GetEntry(fooTopic, NT_DOUBLE, "double", - {{PubSubOption::ExcludeSelf(true)}}); + auto entry = + storage.GetEntry(fooTopic, NT_DOUBLE, "double", {.excludeSelf = true}); auto remoteTopic = storage.NetworkAnnounce("foo", "double", wpi::json::object(), 0); diff --git a/ntcore/src/test/native/cpp/PubSubOptionsMatcher.cpp b/ntcore/src/test/native/cpp/PubSubOptionsMatcher.cpp index e9719f97dd7..3437a9102b7 100644 --- a/ntcore/src/test/native/cpp/PubSubOptionsMatcher.cpp +++ b/ntcore/src/test/native/cpp/PubSubOptionsMatcher.cpp @@ -9,18 +9,19 @@ namespace nt { bool PubSubOptionsMatcher::MatchAndExplain( - const PubSubOptions& val, ::testing::MatchResultListener* listener) const { + const PubSubOptionsImpl& val, + ::testing::MatchResultListener* listener) const { bool match = true; if (val.periodicMs != good.periodicMs) { *listener << "periodic mismatch "; match = false; } - if (val.pollStorageSize != good.pollStorageSize) { - *listener << "pollStorageSize mismatch "; + if (val.pollStorage != good.pollStorage) { + *listener << "pollStorage mismatch "; match = false; } if (val.sendAll != good.sendAll) { - *listener << "logging mismatch "; + *listener << "sendAll mismatch "; match = false; } if (val.keepDuplicates != good.keepDuplicates) { diff --git a/ntcore/src/test/native/cpp/PubSubOptionsMatcher.h b/ntcore/src/test/native/cpp/PubSubOptionsMatcher.h index 219c7e13e0e..925f17d2930 100644 --- a/ntcore/src/test/native/cpp/PubSubOptionsMatcher.h +++ b/ntcore/src/test/native/cpp/PubSubOptionsMatcher.h @@ -13,21 +13,22 @@ namespace nt { class PubSubOptionsMatcher - : public ::testing::MatcherInterface { + : public ::testing::MatcherInterface { public: - explicit PubSubOptionsMatcher(PubSubOptions good) : good{std::move(good)} {} + explicit PubSubOptionsMatcher(PubSubOptionsImpl good) + : good{std::move(good)} {} - bool MatchAndExplain(const PubSubOptions& val, + bool MatchAndExplain(const PubSubOptionsImpl& val, ::testing::MatchResultListener* listener) const override; void DescribeTo(::std::ostream* os) const override; void DescribeNegationTo(::std::ostream* os) const override; private: - PubSubOptions good; + PubSubOptionsImpl good; }; -inline ::testing::Matcher PubSubOptionsEq( - PubSubOptions good) { +inline ::testing::Matcher PubSubOptionsEq( + PubSubOptionsImpl good) { return ::testing::MakeMatcher(new PubSubOptionsMatcher(std::move(good))); } diff --git a/ntcore/src/test/native/cpp/TestPrinters.cpp b/ntcore/src/test/native/cpp/TestPrinters.cpp index 36fdb9759c6..66afe4e0d59 100644 --- a/ntcore/src/test/native/cpp/TestPrinters.cpp +++ b/ntcore/src/test/native/cpp/TestPrinters.cpp @@ -160,10 +160,10 @@ void PrintTo(const Value& value, std::ostream* os) { *os << '}'; } -void PrintTo(const PubSubOptions& options, std::ostream* os) { +void PrintTo(const PubSubOptionsImpl& options, std::ostream* os) { *os << "PubSubOptions{periodicMs=" << options.periodicMs - << ", pollStorageSize=" << options.pollStorageSize - << ", logging=" << options.sendAll + << ", pollStorage=" << options.pollStorage + << ", sendAll=" << options.sendAll << ", keepDuplicates=" << options.keepDuplicates << '}'; } diff --git a/ntcore/src/test/native/cpp/TestPrinters.h b/ntcore/src/test/native/cpp/TestPrinters.h index c9c7e0e191d..2b8f1da979f 100644 --- a/ntcore/src/test/native/cpp/TestPrinters.h +++ b/ntcore/src/test/native/cpp/TestPrinters.h @@ -51,7 +51,7 @@ struct ServerMessage; class Event; class Handle; -class PubSubOptions; +class PubSubOptionsImpl; class Value; void PrintTo(const Event& event, std::ostream* os); @@ -60,6 +60,6 @@ void PrintTo(const net3::Message3& msg, std::ostream* os); void PrintTo(const net::ClientMessage& msg, std::ostream* os); void PrintTo(const net::ServerMessage& msg, std::ostream* os); void PrintTo(const Value& value, std::ostream* os); -void PrintTo(const PubSubOptions& options, std::ostream* os); +void PrintTo(const PubSubOptionsImpl& options, std::ostream* os); } // namespace nt diff --git a/ntcore/src/test/native/cpp/net/MockNetworkInterface.h b/ntcore/src/test/native/cpp/net/MockNetworkInterface.h index 9d81fbf0ced..bdf3e3ecbfa 100644 --- a/ntcore/src/test/native/cpp/net/MockNetworkInterface.h +++ b/ntcore/src/test/native/cpp/net/MockNetworkInterface.h @@ -33,11 +33,11 @@ class MockNetworkStartupInterface : public NetworkStartupInterface { MOCK_METHOD(void, Publish, (NT_Publisher pubHandle, NT_Topic topicHandle, std::string_view name, std::string_view typeStr, - const wpi::json& properties, const PubSubOptions& options), + const wpi::json& properties, const PubSubOptionsImpl& options), (override)); MOCK_METHOD(void, Subscribe, (NT_Subscriber subHandle, std::span prefixes, - const PubSubOptions& options), + const PubSubOptionsImpl& options), (override)); MOCK_METHOD(void, SetValue, (NT_Publisher pubHandle, const Value& value), (override)); @@ -48,7 +48,7 @@ class MockNetworkInterface : public NetworkInterface { MOCK_METHOD(void, Publish, (NT_Publisher pubHandle, NT_Topic topicHandle, std::string_view name, std::string_view typeStr, - const wpi::json& properties, const PubSubOptions& options), + const wpi::json& properties, const PubSubOptionsImpl& options), (override)); MOCK_METHOD(void, Unpublish, (NT_Publisher pubHandle, NT_Topic topicHandle), (override)); @@ -58,7 +58,7 @@ class MockNetworkInterface : public NetworkInterface { (override)); MOCK_METHOD(void, Subscribe, (NT_Subscriber subHandle, std::span prefixes, - const PubSubOptions& options), + const PubSubOptionsImpl& options), (override)); MOCK_METHOD(void, Unsubscribe, (NT_Subscriber subHandle), (override)); MOCK_METHOD(void, SetValue, (NT_Publisher pubHandle, const Value& value), diff --git a/ntcore/src/test/native/cpp/net/WireDecoderTest.cpp b/ntcore/src/test/native/cpp/net/WireDecoderTest.cpp index b9d71904b98..f89330229a7 100644 --- a/ntcore/src/test/native/cpp/net/WireDecoderTest.cpp +++ b/ntcore/src/test/native/cpp/net/WireDecoderTest.cpp @@ -31,7 +31,7 @@ class MockClientMessageHandler : public net::ClientMessageHandler { void(std::string_view name, const wpi::json& update)); MOCK_METHOD3(ClientSubscribe, void(int64_t subuid, std::span prefixes, - const PubSubOptions& options)); + const PubSubOptionsImpl& options)); MOCK_METHOD1(ClientUnsubscribe, void(int64_t subuid)); }; diff --git a/ntcore/src/test/native/cpp/net/WireEncoderTest.cpp b/ntcore/src/test/native/cpp/net/WireEncoderTest.cpp index 49379c3428c..9cc31878652 100644 --- a/ntcore/src/test/native/cpp/net/WireEncoderTest.cpp +++ b/ntcore/src/test/native/cpp/net/WireEncoderTest.cpp @@ -74,7 +74,7 @@ TEST_F(WireEncoderTextTest, Subscribe) { } TEST_F(WireEncoderTextTest, SubscribeSendAll) { - PubSubOptions options; + PubSubOptionsImpl options; options.sendAll = true; net::WireEncodeSubscribe(os, 5, std::span{{"a", "b"}}, options); @@ -85,7 +85,7 @@ TEST_F(WireEncoderTextTest, SubscribeSendAll) { } TEST_F(WireEncoderTextTest, SubscribePeriodic) { - PubSubOptions options; + PubSubOptionsImpl options; options.periodicMs = 500u; net::WireEncodeSubscribe(os, 5, std::span{{"a", "b"}}, options); @@ -96,7 +96,7 @@ TEST_F(WireEncoderTextTest, SubscribePeriodic) { } TEST_F(WireEncoderTextTest, SubscribeAllOptions) { - PubSubOptions options; + PubSubOptionsImpl options; options.sendAll = true; options.periodicMs = 500u; net::WireEncodeSubscribe(os, 5, std::span{{"a", "b"}}, diff --git a/wpilibc/src/main/native/cpp/smartdashboard/SendableBuilderImpl.cpp b/wpilibc/src/main/native/cpp/smartdashboard/SendableBuilderImpl.cpp index a6723a67357..79b0e6e8969 100644 --- a/wpilibc/src/main/native/cpp/smartdashboard/SendableBuilderImpl.cpp +++ b/wpilibc/src/main/native/cpp/smartdashboard/SendableBuilderImpl.cpp @@ -130,8 +130,8 @@ void SendableBuilderImpl::AddPropertyImpl(Topic topic, Getter getter, }; } if (setter) { - prop->sub = topic.Subscribe( - {}, {{nt::PubSubOption::ExcludePublisher(prop->pub.GetHandle())}}); + prop->sub = + topic.Subscribe({}, {.excludePublisher = prop->pub.GetHandle()}); prop->updateLocal = [=](auto& sub) { for (auto&& val : sub.ReadQueue()) { setter(val.value); @@ -224,9 +224,8 @@ void SendableBuilderImpl::AddRawProperty( }; } if (setter) { - prop->sub = topic.Subscribe( - typeString, {}, - {{nt::PubSubOption::ExcludePublisher(prop->pub.GetHandle())}}); + prop->sub = topic.Subscribe(typeString, {}, + {.excludePublisher = prop->pub.GetHandle()}); prop->updateLocal = [=](auto& sub) { for (auto&& val : sub.ReadQueue()) { setter(val.value); @@ -249,8 +248,8 @@ void SendableBuilderImpl::AddSmallPropertyImpl(Topic topic, Getter getter, }; } if (setter) { - prop->sub = topic.Subscribe( - {}, {{nt::PubSubOption::ExcludePublisher(prop->pub.GetHandle())}}); + prop->sub = + topic.Subscribe({}, {.excludePublisher = prop->pub.GetHandle()}); prop->updateLocal = [=](auto& sub) { for (auto&& val : sub.ReadQueue()) { setter(val.value); @@ -328,9 +327,8 @@ void SendableBuilderImpl::AddSmallRawProperty( }; } if (setter) { - prop->sub = topic.Subscribe( - typeString, {}, - {{nt::PubSubOption::ExcludePublisher(prop->pub.GetHandle())}}); + prop->sub = topic.Subscribe(typeString, {}, + {.excludePublisher = prop->pub.GetHandle()}); prop->updateLocal = [=](auto& sub) { for (auto&& val : sub.ReadQueue()) { setter(val.value);