Skip to content

Commit fdb847d

Browse files
committed
✨ Add SequenceSet class [🚧 #index_of, #delete_at, etc]
SequenceSet represents the IMAP sequence set data type with an API inspired by both Set and Range (and Array). It represents `sequence-set` in the grammar both parsing and generating. It is also broadly useful e.g. for storing and working with mailbox state. In addition to Integer, Range, and enumerables, any object with `#to_sequence_set` can be used to create a sequence set. For compatibility with MessageSet, `ThreadMember#to_sequence_set` collects all child seqno into a SequenceSet. Because mailbox state can be _very_ large, Inputs are stored in an internal sorted array of ranges (stored as `[start, stop]` tuples, not as Range, for simpler manipulation... a future optimization coul. convert to a single-dimensional Array (to reduce object allocations). This allows many of the important methods to be `O(lg n)`. Although updates do use `Array#insert` and `Array#slice!`, which are technically `O(n)`, they tend to be fast until the number of elements is very large. Count and index-based methods are also `O(n)`. A future optimization could cache the count and compose larger sets from a sorted tree of smaller sets, to preserve `O(lg n)` for more operations. Differences from MessageSet (used internally to output command args): * Most validation is done up-front, when initializing or inputing values * A ThreadMember to `sequence-set` bug has been fixed * The generated string is sorted and adjacent ranges are combined TODO: * Don't allow 2**32 as valid input for "*" * #index_of => get the index of a number in the set * #index_lte => get the index of a number in the set, or if the number isn't in the set, the number before it. * #delete_at => remove a number or numbers at a given index or indices TODO in future PRs (not until v0.5.0): * fully replace MessageSet (used internally to output command args) * Replace (or supplement) the UID sets in UIDPlusData.
1 parent faf858b commit fdb847d

File tree

7 files changed

+2000
-48
lines changed

7 files changed

+2000
-48
lines changed

lib/net/imap/response_data.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,19 @@ class ThreadMember < Struct.new(:seqno, :children)
728728
#
729729
# An array of Net::IMAP::ThreadMember objects for mail items that are
730730
# children of this in the thread.
731+
732+
# Returns a SequenceSet containing #seqno and all #children's seqno,
733+
# recursively.
734+
def to_sequence_set
735+
SequenceSet.new all_seqnos
736+
end
737+
738+
protected
739+
740+
def all_seqnos(node = self)
741+
[node.seqno].concat node.children.flat_map { _1.all_seqnos }
742+
end
743+
731744
end
732745

733746
# Net::IMAP::BodyStructure is included by all of the structs that can be

lib/net/imap/response_parser.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ def unescape_quoted(quoted)
464464
def sequence_set
465465
str = combine_adjacent(*SEQUENCE_SET_TOKENS)
466466
if Patterns::SEQUENCE_SET_STR.match?(str)
467-
SequenceSet.new(str)
467+
SequenceSet[str]
468468
else
469469
parse_error("unexpected atom %p, expected sequence-set", str)
470470
end

0 commit comments

Comments
 (0)