--[=[
	Brios wrap a value (or tuple of values) and are used to convey the lifetime of that
	object. The brio is better than a maid, by providing the following constraints:

	- Can be in 2 states, dead or alive.
	- While alive, can retrieve values.
	- While dead, retrieving values is forbidden.
	- Died will fire once upon death.

	Brios encapsulate the "lifetime" of a valid resource. Unlike a maid, they
	- Can only die once, ensuring duplicate calls never occur.
	- Have less memory leaks. Memory leaks in maids can occur when use of the maid occurs
	  after the cleanup of the maid has occured, in certain race conditions.
	- Cannot be reentered, i.e. cannot retrieve values after death.

	:::info
	Calling `brio:Destroy()` or `brio:Kill()` after death does nothing. Brios cannot
	be resurrected.
	:::

	Brios are useful for downstream events where you want to emit a resource. Typically
	brios should be killed when their source is killed. Brios are intended to be merged
	with downstream brios so create a chain of reliable resources.

	```lua
	local brio = Brio.new("a", "b")
	print(brio:GetValue()) --> a b
	print(brio:IsDead()) --> false

	brio:GetDiedSignal():Connect(function()
		print("Hello from signal!")
	end)
	brio:ToMaid():GiveTask(function()
		print("Hello from maid cleanup!")
	end)
	brio:Kill()
	--> Hello from signal!
	--> Hello from maid cleanup!

	print(brio:IsDead()) --> true
	print(brio:GetValue()) --> ERROR: Brio is dead
	```

	## Design philosophy

	Brios are designed to solve this issue where we emit an object with a lifetime associated with it from an
	Observable stream. This resource is only valid for some amount of time (for example, while the object is
	in the Roblox data model).

	In order to know how long we can keep this object/use it, we wrap the object with a Brio, which denotes
	 the lifetime of the object.

	Modeling this with pure observables is very tricky because the subscriber will have to also monitor/emit
	a similar object with less clear conventions. For example  an observable that emits the object, and then nil on death.

	@class Brio
]=]


local require = require(script.Parent.loader).load(script)

local Maid = require("Maid")
local GoodSignal = require("GoodSignal")

local Brio = {}
Brio.ClassName = "Brio"
Brio.__index = Brio
