BlockTypeRegistry: Added hint manipulation
This commit is contained in:
parent
3722a239bf
commit
f48ac9f0c3
@ -56,6 +56,33 @@ AString BlockInfo::hintValue(
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void BlockInfo::setHint(const AString & aHintKey, const AString & aHintValue)
|
||||||
|
{
|
||||||
|
mHints[aHintKey] = aHintValue;
|
||||||
|
|
||||||
|
// Warn if the hint is already provided by a callback (aHintValue will be ignored when evaluating the hint):
|
||||||
|
auto itrC = mHintCallbacks.find(aHintKey);
|
||||||
|
if (itrC != mHintCallbacks.end())
|
||||||
|
{
|
||||||
|
LOGINFO("Setting a static hint %s for block type %s, but there's already a callback for that hint. The static hint will be ignored.",
|
||||||
|
aHintKey.c_str(), mBlockTypeName.c_str()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void BlockInfo::removeHint(const AString & aHintKey)
|
||||||
|
{
|
||||||
|
mHints.erase(aHintKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// BlockTypeRegistry:
|
// BlockTypeRegistry:
|
||||||
|
|
||||||
@ -123,6 +150,43 @@ void BlockTypeRegistry::removeAllByPlugin(const AString & aPluginName)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void BlockTypeRegistry::setBlockTypeHint(
|
||||||
|
const AString & aBlockTypeName,
|
||||||
|
const AString & aHintKey,
|
||||||
|
const AString & aHintValue
|
||||||
|
)
|
||||||
|
{
|
||||||
|
cCSLock lock(mCSRegistry);
|
||||||
|
auto blockInfo = mRegistry.find(aBlockTypeName);
|
||||||
|
if (blockInfo == mRegistry.end())
|
||||||
|
{
|
||||||
|
throw NotRegisteredException(aBlockTypeName, aHintKey, aHintValue);
|
||||||
|
}
|
||||||
|
blockInfo->second->setHint(aHintKey, aHintValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void BlockTypeRegistry::removeBlockTypeHint(
|
||||||
|
const AString & aBlockTypeName,
|
||||||
|
const AString & aHintKey
|
||||||
|
)
|
||||||
|
{
|
||||||
|
cCSLock lock(mCSRegistry);
|
||||||
|
auto blockInfo = mRegistry.find(aBlockTypeName);
|
||||||
|
if (blockInfo == mRegistry.end())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
blockInfo->second->removeHint(aHintKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// BlockTypeRegistry::AlreadyRegisteredException:
|
// BlockTypeRegistry::AlreadyRegisteredException:
|
||||||
|
|
||||||
@ -151,3 +215,24 @@ AString BlockTypeRegistry::AlreadyRegisteredException::message(
|
|||||||
aPreviousRegistration->pluginName().c_str()
|
aPreviousRegistration->pluginName().c_str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// BlockTypeRegistry::NotRegisteredException:
|
||||||
|
|
||||||
|
BlockTypeRegistry::NotRegisteredException::NotRegisteredException(
|
||||||
|
const AString & aBlockTypeName,
|
||||||
|
const AString & aHintKey,
|
||||||
|
const AString & aHintValue
|
||||||
|
):
|
||||||
|
Super(Printf(
|
||||||
|
"Attempting to set a hint of nonexistent BlockTypeName.\n\tBlockTypeName = %s\n\tHintKey = %s\n\tHintValue = %s",
|
||||||
|
aBlockTypeName.c_str(),
|
||||||
|
aHintKey.c_str(),
|
||||||
|
aHintValue.c_str()
|
||||||
|
))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
@ -40,7 +40,7 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
/** Retrieves the value associated with the specified hint for this specific BlockTypeName and BlockState.
|
/** Retrieves the value associated with the specified hint for this specific BlockTypeName and BlockState.
|
||||||
Queries callbacks first, then hints if a callback doesn't exist.
|
Queries hint callbacks first, then static hints if a callback doesn't exist.
|
||||||
Returns an empty string if hint not found at all. */
|
Returns an empty string if hint not found at all. */
|
||||||
AString hintValue(
|
AString hintValue(
|
||||||
const AString & aHintName,
|
const AString & aHintName,
|
||||||
@ -52,6 +52,15 @@ public:
|
|||||||
const AString & blockTypeName() const { return mBlockTypeName; }
|
const AString & blockTypeName() const { return mBlockTypeName; }
|
||||||
std::shared_ptr<cBlockHandler> handler() const { return mHandler; }
|
std::shared_ptr<cBlockHandler> handler() const { return mHandler; }
|
||||||
|
|
||||||
|
/** Sets (creates or updates) a static hint.
|
||||||
|
Hints provided by callbacks are unaffected by this - callbacks are "higher priority", they overwrite anything set here.
|
||||||
|
Logs an info message if the hint is already provided by a hint callback. */
|
||||||
|
void setHint(const AString & aHintKey, const AString & aHintValue);
|
||||||
|
|
||||||
|
/** Removes a hint.
|
||||||
|
Silently ignored if the hint hasn't been previously set. */
|
||||||
|
void removeHint(const AString & aHintKey);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -64,10 +73,12 @@ private:
|
|||||||
/** The callbacks to call for various interaction. */
|
/** The callbacks to call for various interaction. */
|
||||||
std::shared_ptr<cBlockHandler> mHandler;
|
std::shared_ptr<cBlockHandler> mHandler;
|
||||||
|
|
||||||
/** Optional hints for any subsystem to use, such as "IsSnowable" -> "1". */
|
/** Optional static hints for any subsystem to use, such as "IsSnowable" -> "1".
|
||||||
|
Hint callbacks are of higher priority than mHints - if a hint is provided by a mHintCallback, its value in mHints is ignored. */
|
||||||
std::map<AString, AString> mHints;
|
std::map<AString, AString> mHints;
|
||||||
|
|
||||||
/** The callbacks for dynamic evaluation of hints, such as "LightValue" -> function(BlockTypeName, BlockState). */
|
/** The callbacks for dynamic evaluation of hints, such as "LightValue" -> function(BlockTypeName, BlockState).
|
||||||
|
Hint callbacks are of higher priority than mHints - if a hint is provided by a mHintCallback, its value in mHints is ignored. */
|
||||||
std::map<AString, HintCallback> mHintCallbacks;
|
std::map<AString, HintCallback> mHintCallbacks;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -86,6 +97,7 @@ class BlockTypeRegistry
|
|||||||
public:
|
public:
|
||||||
// fwd:
|
// fwd:
|
||||||
class AlreadyRegisteredException;
|
class AlreadyRegisteredException;
|
||||||
|
class NotRegisteredException;
|
||||||
|
|
||||||
|
|
||||||
/** Creates an empty new instance of the block type registry */
|
/** Creates an empty new instance of the block type registry */
|
||||||
@ -109,6 +121,22 @@ public:
|
|||||||
/** Removes all registrations done by the specified plugin. */
|
/** Removes all registrations done by the specified plugin. */
|
||||||
void removeAllByPlugin(const AString & aPluginName);
|
void removeAllByPlugin(const AString & aPluginName);
|
||||||
|
|
||||||
|
/** Sets (adds or overwrites) a single Hint value for a BlockType.
|
||||||
|
Throws NotRegisteredException if the BlockTypeName is not registered. */
|
||||||
|
void setBlockTypeHint(
|
||||||
|
const AString & aBlockTypeName,
|
||||||
|
const AString & aHintKey,
|
||||||
|
const AString & aHintValue
|
||||||
|
);
|
||||||
|
|
||||||
|
/** Removes a previously registered single Hint value for a BlockType.
|
||||||
|
Throws NotRegisteredException if the BlockTypeName is not registered.
|
||||||
|
Silently ignored if the Hint hasn't been previously set. */
|
||||||
|
void removeBlockTypeHint(
|
||||||
|
const AString & aBlockTypeName,
|
||||||
|
const AString & aHintKey
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -156,3 +184,31 @@ private:
|
|||||||
std::shared_ptr<BlockInfo> aNewRegistration
|
std::shared_ptr<BlockInfo> aNewRegistration
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** The exception thrown from BlockTypeRegistry::setBlockTypeHint() if the block type has not been registered before. */
|
||||||
|
class BlockTypeRegistry::NotRegisteredException: public std::runtime_error
|
||||||
|
{
|
||||||
|
using Super = std::runtime_error;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** Creates a new instance of the exception that provides info on both the original registration and the newly attempted
|
||||||
|
registration that caused the failure. */
|
||||||
|
NotRegisteredException(
|
||||||
|
const AString & aBlockTypeName,
|
||||||
|
const AString & aHintKey,
|
||||||
|
const AString & aHintValue
|
||||||
|
);
|
||||||
|
|
||||||
|
// Simple getters:
|
||||||
|
const AString & blockTypeName() const { return mBlockTypeName; }
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
const AString mBlockTypeName;
|
||||||
|
};
|
||||||
|
@ -64,6 +64,42 @@ static void testSimpleReg()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Tests setting and removing a BlockType hint. */
|
||||||
|
static void testHintSetRemove()
|
||||||
|
{
|
||||||
|
LOGD("Testing hint addition and removal...");
|
||||||
|
|
||||||
|
// Register the block type:
|
||||||
|
BlockTypeRegistry reg;
|
||||||
|
AString blockTypeName("test:block1");
|
||||||
|
AString pluginName("testPlugin");
|
||||||
|
AString hint1("testHint1");
|
||||||
|
AString hint1Value("value1");
|
||||||
|
AString hint2("testHint2");
|
||||||
|
AString hint2Value("value2");
|
||||||
|
std::shared_ptr<cBlockHandler> handler(new cBlockHandler(0x12345678));
|
||||||
|
std::map<AString, AString> hints = {{hint1, hint1Value}};
|
||||||
|
std::map<AString, BlockInfo::HintCallback> hintCallbacks;
|
||||||
|
reg.registerBlockType(pluginName, blockTypeName, handler, hints, hintCallbacks);
|
||||||
|
|
||||||
|
// Modify the hints:
|
||||||
|
auto blockInfo = reg.blockInfo(blockTypeName);
|
||||||
|
reg.setBlockTypeHint(blockTypeName, hint2, hint2Value);
|
||||||
|
TEST_EQUAL(blockInfo->hintValue(hint2, BlockState()), hint2Value); // Was created successfully
|
||||||
|
reg.setBlockTypeHint(blockTypeName, hint1, "testValue2");
|
||||||
|
TEST_EQUAL(blockInfo->hintValue(hint1, BlockState()), "testValue2"); // Was updated successfully
|
||||||
|
reg.removeBlockTypeHint(blockTypeName, hint2);
|
||||||
|
TEST_EQUAL(blockInfo->hintValue(hint2, BlockState()), ""); // Was removed successfully
|
||||||
|
|
||||||
|
// Test the error reporting:
|
||||||
|
TEST_THROWS(reg.setBlockTypeHint("nonexistent", "hint", "value"), BlockTypeRegistry::NotRegisteredException);
|
||||||
|
reg.removeBlockTypeHint(blockTypeName, "nonexistent"); // Should fail silently
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Tests that the plugin-based information is used correctly for registration.
|
/** Tests that the plugin-based information is used correctly for registration.
|
||||||
Registers two different block types with two different plugins, then tries to re-register them from a different plugin.
|
Registers two different block types with two different plugins, then tries to re-register them from a different plugin.
|
||||||
Finally removes the registration through removeAllByPlugin() and checks its success. */
|
Finally removes the registration through removeAllByPlugin() and checks its success. */
|
||||||
@ -190,6 +226,7 @@ static void testThreadLocking()
|
|||||||
static void testBlockTypeRegistry()
|
static void testBlockTypeRegistry()
|
||||||
{
|
{
|
||||||
testSimpleReg();
|
testSimpleReg();
|
||||||
|
testHintSetRemove();
|
||||||
testPlugins();
|
testPlugins();
|
||||||
testHintCallbacks();
|
testHintCallbacks();
|
||||||
testThreadLocking();
|
testThreadLocking();
|
||||||
|
Loading…
Reference in New Issue
Block a user