1010use Smoren \ArrayView \Exceptions \ReadonlyError ;
1111use Smoren \ArrayView \Interfaces \ArraySelectorInterface ;
1212use Smoren \ArrayView \Interfaces \ArrayViewInterface ;
13+ use Smoren \ArrayView \Selectors \IndexListSelector ;
14+ use Smoren \ArrayView \Selectors \MaskSelector ;
1315use Smoren \ArrayView \Selectors \SliceSelector ;
1416use Smoren \ArrayView \Structs \Slice ;
17+ use Smoren \ArrayView \Util ;
1518
1619/**
1720 * Trait providing methods for accessing elements in ArrayView object.
1821 * The trait implements methods for accessing, retrieving, setting,
1922 * and unsetting elements in the ArrayView object.
2023 *
2124 * @template T Type of ArrayView values.
25+ * @template S of string|array<mixed>|ArrayViewInterface<mixed>|ArraySelectorInterface Type of selectors.
2226 */
2327trait ArrayViewAccessTrait
2428{
2529 /**
2630 * Check if the specified offset exists in the ArrayView object.
2731 *
28- * @param numeric|string|ArraySelectorInterface $offset The offset to check.
32+ * @param numeric|S $offset The offset to check.
2933 *
3034 * @return bool
3135 *
@@ -37,21 +41,17 @@ public function offsetExists($offset): bool
3741 return $ this ->numericOffsetExists ($ offset );
3842 }
3943
40- if (\is_string ($ offset ) && Slice::isSlice ($ offset )) {
41- return true ;
44+ try {
45+ return $ this ->toSelector ($ offset )->compatibleWith ($ this );
46+ } catch (KeyError $ e ) {
47+ return false ;
4248 }
43-
44- if ($ offset instanceof ArraySelectorInterface) {
45- return $ offset ->compatibleWith ($ this );
46- }
47-
48- return false ;
4949 }
5050
5151 /**
5252 * Get the value at the specified offset in the ArrayView object.
5353 *
54- * @param numeric|string|ArraySelectorInterface $offset The offset to get the value from.
54+ * @param numeric|S $offset The offset to get the value from.
5555 *
5656 * @return T|array<T> The value at the specified offset.
5757 *
@@ -63,30 +63,20 @@ public function offsetExists($offset): bool
6363 #[\ReturnTypeWillChange]
6464 public function offsetGet ($ offset )
6565 {
66- /** @var mixed $offset */
6766 if (\is_numeric ($ offset )) {
6867 if (!$ this ->numericOffsetExists ($ offset )) {
6968 throw new IndexError ("Index {$ offset } is out of range. " );
7069 }
7170 return $ this ->source [$ this ->convertIndex (\intval ($ offset ))];
7271 }
7372
74- if (\is_string ($ offset ) && Slice::isSlice ($ offset )) {
75- return $ this ->subview (new SliceSelector ($ offset ))->toArray ();
76- }
77-
78- if ($ offset instanceof ArraySelectorInterface) {
79- return $ this ->subview ($ offset )->toArray ();
80- }
81-
82- $ strOffset = \is_scalar ($ offset ) ? \strval ($ offset ) : \gettype ($ offset );
83- throw new KeyError ("Invalid key: \"{$ strOffset }\". " );
73+ return $ this ->subview ($ this ->toSelector ($ offset ))->toArray ();
8474 }
8575
8676 /**
8777 * Set the value at the specified offset in the ArrayView object.
8878 *
89- * @param numeric|string|ArraySelectorInterface $offset The offset to set the value at.
79+ * @param numeric|S $offset The offset to set the value at.
9080 * @param T|array<T>|ArrayViewInterface<T> $value The value to set.
9181 *
9282 * @return void
@@ -99,40 +89,27 @@ public function offsetGet($offset)
9989 */
10090 public function offsetSet ($ offset , $ value ): void
10191 {
102- /** @var mixed $offset */
10392 if ($ this ->isReadonly ()) {
10493 throw new ReadonlyError ("Cannot modify a readonly view. " );
10594 }
10695
107- if (\is_numeric ($ offset )) {
108- if (!$ this ->numericOffsetExists ($ offset )) {
109- throw new IndexError ("Index {$ offset } is out of range. " );
110- }
111-
112- // @phpstan-ignore-next-line
113- $ this ->source [$ this ->convertIndex (\intval ($ offset ))] = $ value ;
114- return ;
115- }
116-
117- if (\is_string ($ offset ) && Slice::isSlice ($ offset )) {
118- /** @var array<T>|ArrayViewInterface<T> $value */
119- $ this ->subview (new SliceSelector ($ offset ))->set ($ value );
96+ if (!\is_numeric ($ offset )) {
97+ $ this ->subview ($ this ->toSelector ($ offset ))->set ($ value );
12098 return ;
12199 }
122100
123- if ($ offset instanceof ArraySelectorInterface) {
124- $ this ->subview ($ offset )->set ($ value );
125- return ;
101+ if (!$ this ->numericOffsetExists ($ offset )) {
102+ throw new IndexError ("Index {$ offset } is out of range. " );
126103 }
127104
128- $ strOffset = \is_scalar ( $ offset ) ? \strval ( $ offset ) : \gettype ( $ offset );
129- throw new KeyError ( " Invalid key: \"{ $ strOffset }\" . " ) ;
105+ // @phpstan-ignore-next-line
106+ $ this -> source [ $ this -> convertIndex ( \intval ( $ offset ))] = $ value ;
130107 }
131108
132109 /**
133110 * Unset the value at the specified offset in the array-like object.
134111 *
135- * @param numeric|string|ArraySelectorInterface $offset The offset to unset the value at.
112+ * @param numeric|S $offset The offset to unset the value at.
136113 *
137114 * @return void
138115 *
@@ -144,4 +121,37 @@ public function offsetUnset($offset): void
144121 {
145122 throw new NotSupportedError ();
146123 }
124+
125+ /**
126+ * Converts array to selector.
127+ *
128+ * @param S $input value to convert.
129+ *
130+ * @return ArraySelectorInterface
131+ */
132+ protected function toSelector ($ input ): ArraySelectorInterface
133+ {
134+ if ($ input instanceof ArraySelectorInterface) {
135+ return $ input ;
136+ }
137+
138+ if (\is_string ($ input ) && Slice::isSlice ($ input )) {
139+ return new SliceSelector ($ input );
140+ }
141+
142+ if ($ input instanceof ArrayViewInterface) {
143+ $ input = $ input ->toArray ();
144+ }
145+
146+ if (!\is_array ($ input ) || !Util::isArraySequential ($ input )) {
147+ $ strOffset = \is_scalar ($ input ) ? \strval ($ input ) : \gettype ($ input );
148+ throw new KeyError ("Invalid key: \"{$ strOffset }\". " );
149+ }
150+
151+ if (\count ($ input ) > 0 && \is_bool ($ input [0 ])) {
152+ return new MaskSelector ($ input );
153+ }
154+
155+ return new IndexListSelector ($ input );
156+ }
147157}
0 commit comments